diff options
author | ᴜɴᴋɴᴡᴏɴ <u@gogs.io> | 2020-04-11 02:56:37 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-11 02:56:37 +0800 |
commit | e077ecdd9d95ecb76d91105b3858ee48d52c0cc2 (patch) | |
tree | df44f46888c08fc675d47e22e11a165fdb8d185d /internal/db | |
parent | 62dda96159055ff9d485078f257445b964eb5220 (diff) |
db: add tests for LFS (#6087)
* Improve DB test setup
* Discard GORM logs in non-verbose mode
* Add tests to lfs
* Fix data race
Diffstat (limited to 'internal/db')
-rw-r--r-- | internal/db/access_tokens.go | 15 | ||||
-rw-r--r-- | internal/db/access_tokens_test.go | 45 | ||||
-rw-r--r-- | internal/db/db.go | 7 | ||||
-rw-r--r-- | internal/db/lfs_test.go | 117 | ||||
-rw-r--r-- | internal/db/main_test.go | 44 |
5 files changed, 184 insertions, 44 deletions
diff --git a/internal/db/access_tokens.go b/internal/db/access_tokens.go index f4f4ee80..b6cd5339 100644 --- a/internal/db/access_tokens.go +++ b/internal/db/access_tokens.go @@ -56,12 +56,12 @@ type AccessToken struct { // NOTE: This is a GORM create hook. func (t *AccessToken) BeforeCreate() { - t.CreatedUnix = t.Created.Unix() + t.CreatedUnix = gorm.NowFunc().Unix() } // NOTE: This is a GORM update hook. func (t *AccessToken) BeforeUpdate() { - t.UpdatedUnix = t.Updated.Unix() + t.UpdatedUnix = gorm.NowFunc().Unix() } // NOTE: This is a GORM query hook. @@ -69,14 +69,13 @@ func (t *AccessToken) AfterFind() { t.Created = time.Unix(t.CreatedUnix, 0).Local() t.Updated = time.Unix(t.UpdatedUnix, 0).Local() t.HasUsed = t.Updated.After(t.Created) - t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now()) + t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(gorm.NowFunc()) } var _ AccessTokensStore = (*accessTokens)(nil) type accessTokens struct { *gorm.DB - clock func() time.Time } type ErrAccessTokenAlreadyExist struct { @@ -101,10 +100,9 @@ func (db *accessTokens) Create(userID int64, name string) (*AccessToken, error) } token := &AccessToken{ - UserID: userID, - Name: name, - Sha1: tool.SHA1(gouuid.NewV4().String()), - Created: db.clock(), + UserID: userID, + Name: name, + Sha1: tool.SHA1(gouuid.NewV4().String()), } return token, db.DB.Create(token).Error } @@ -150,6 +148,5 @@ func (db *accessTokens) List(userID int64) ([]*AccessToken, error) { } func (db *accessTokens) Save(t *AccessToken) error { - t.Updated = db.clock() return db.DB.Save(t).Error } diff --git a/internal/db/access_tokens_test.go b/internal/db/access_tokens_test.go index f6d62745..d3dfb83f 100644 --- a/internal/db/access_tokens_test.go +++ b/internal/db/access_tokens_test.go @@ -5,15 +5,12 @@ package db import ( - "fmt" - "os" - "path/filepath" "testing" "time" + "github.com/jinzhu/gorm" "github.com/stretchr/testify/assert" - "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/errutil" ) @@ -24,34 +21,10 @@ func Test_accessTokens(t *testing.T) { t.Parallel() - dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("gogs-%d.db", time.Now().Unix())) - gdb, err := openDB(conf.DatabaseOpts{ - Type: "sqlite3", - Path: dbpath, - }) - if err != nil { - t.Fatal(err) - } - t.Cleanup(func() { - _ = gdb.Close() - - if t.Failed() { - t.Logf("Database %q left intact for inspection", dbpath) - return - } - - _ = os.Remove(dbpath) - }) - - err = gdb.AutoMigrate(new(AccessToken)).Error - if err != nil { - t.Fatal(err) + db := &accessTokens{ + DB: initTestDB(t, "accessTokens", new(AccessToken)), } - now := time.Now().Truncate(time.Second) - clock := func() time.Time { return now } - db := &accessTokens{DB: gdb, clock: clock} - for _, tc := range []struct { name string test func(*testing.T, *accessTokens) @@ -64,7 +37,7 @@ func Test_accessTokens(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { t.Cleanup(func() { - err := deleteTables(gdb, new(AccessToken)) + err := deleteTables(db.DB, new(AccessToken)) if err != nil { t.Fatal(err) } @@ -84,7 +57,13 @@ func test_accessTokens_Create(t *testing.T, db *accessTokens) { assert.Equal(t, int64(1), token.UserID) assert.Equal(t, "Test", token.Name) assert.Equal(t, 40, len(token.Sha1), "sha1 length") - assert.Equal(t, db.clock(), token.Created) + + // Get it back and check the Created field + token, err = db.GetBySHA(token.Sha1) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, gorm.NowFunc().Format(time.RFC3339), token.Created.Format(time.RFC3339)) // Try create second access token with same name should fail _, err = db.Create(token.UserID, token.Name) @@ -197,5 +176,5 @@ func test_accessTokens_Save(t *testing.T, db *accessTokens) { if err != nil { t.Fatal(err) } - assert.Equal(t, db.clock(), token.Updated) + assert.Equal(t, gorm.NowFunc().Format(time.RFC3339), token.Updated.Format(time.RFC3339)) } diff --git a/internal/db/db.go b/internal/db/db.go index 27135eba..1be2cc4b 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -163,9 +163,12 @@ func Init() error { return errors.Wrap(err, "migrate schemes") } - clock := func() time.Time {return time.Now().UTC().Truncate(time.Microsecond)} + gorm.NowFunc = func() time.Time { + return time.Now().UTC().Truncate(time.Microsecond) + } + // Initialize stores, sorted in alphabetical order. - AccessTokens = &accessTokens{DB: db, clock: clock} + AccessTokens = &accessTokens{DB: db} LoginSources = &loginSources{DB: db} LFS = &lfs{DB: db} Perms = &perms{DB: db} diff --git a/internal/db/lfs_test.go b/internal/db/lfs_test.go new file mode 100644 index 00000000..6eb14019 --- /dev/null +++ b/internal/db/lfs_test.go @@ -0,0 +1,117 @@ +// Copyright 2020 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package db + +import ( + "testing" + "time" + + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + + "gogs.io/gogs/internal/errutil" + "gogs.io/gogs/internal/lfsutil" +) + +func Test_lfs(t *testing.T) { + if testing.Short() { + t.Skip() + } + + t.Parallel() + + db := &lfs{ + DB: initTestDB(t, "lfs", new(LFSObject)), + } + + for _, tc := range []struct { + name string + test func(*testing.T, *lfs) + }{ + {"CreateObject", test_lfs_CreateObject}, + {"GetObjectByOID", test_lfs_GetObjectByOID}, + {"GetObjectsByOIDs", test_lfs_GetObjectsByOIDs}, + } { + t.Run(tc.name, func(t *testing.T) { + t.Cleanup(func() { + err := deleteTables(db.DB, new(LFSObject)) + if err != nil { + t.Fatal(err) + } + }) + tc.test(t, db) + }) + } +} + +func test_lfs_CreateObject(t *testing.T, db *lfs) { + // Create first LFS object + repoID := int64(1) + oid := lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f") + err := db.CreateObject(repoID, oid, 12, lfsutil.StorageLocal) + if err != nil { + t.Fatal(err) + } + + // Get it back and check the CreatedAt field + object, err := db.GetObjectByOID(repoID, oid) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, gorm.NowFunc().Format(time.RFC3339), object.CreatedAt.Format(time.RFC3339)) + + // Try create second LFS object with same oid should fail + err = db.CreateObject(repoID, oid, 12, lfsutil.StorageLocal) + assert.Error(t, err) +} + +func test_lfs_GetObjectByOID(t *testing.T, db *lfs) { + // Create a LFS object + repoID := int64(1) + oid := lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f") + err := db.CreateObject(repoID, oid, 12, lfsutil.StorageLocal) + if err != nil { + t.Fatal(err) + } + + // We should be able to get it back + _, err = db.GetObjectByOID(repoID, oid) + if err != nil { + t.Fatal(err) + } + + // Try to get a non-existent object + _, err = db.GetObjectByOID(repoID, "bad_oid") + expErr := ErrLFSObjectNotExist{args: errutil.Args{"repoID": repoID, "oid": lfsutil.OID("bad_oid")}} + assert.Equal(t, expErr, err) +} + +func test_lfs_GetObjectsByOIDs(t *testing.T, db *lfs) { + // Create two LFS objects + repoID := int64(1) + oid1 := lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f") + oid2 := lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64g") + err := db.CreateObject(repoID, oid1, 12, lfsutil.StorageLocal) + if err != nil { + t.Fatal(err) + } + err = db.CreateObject(repoID, oid2, 12, lfsutil.StorageLocal) + if err != nil { + t.Fatal(err) + } + + // We should be able to get them back and ignore non-existent ones + objects, err := db.GetObjectsByOIDs(repoID, oid1, oid2, "bad_oid") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, 2, len(objects), "number of objects") + + assert.Equal(t, repoID, objects[0].RepoID) + assert.Equal(t, oid1, objects[0].OID) + + assert.Equal(t, repoID, objects[1].RepoID) + assert.Equal(t, oid2, objects[1].OID) +} diff --git a/internal/db/main_test.go b/internal/db/main_test.go index d141d3cd..8b4190da 100644 --- a/internal/db/main_test.go +++ b/internal/db/main_test.go @@ -7,12 +7,17 @@ package db import ( "flag" "fmt" + "io/ioutil" "os" + "path/filepath" "testing" + "time" "github.com/jinzhu/gorm" log "unknwon.dev/clog/v2" + "gogs.io/gogs/internal/conf" + "gogs.io/gogs/internal/dbutil" "gogs.io/gogs/internal/testutil" ) @@ -27,6 +32,10 @@ func TestMain(m *testing.M) { os.Exit(1) } } + + now := time.Now().Truncate(time.Second) + gorm.NowFunc = func() time.Time { return now } + os.Exit(m.Run()) } @@ -39,3 +48,38 @@ func deleteTables(db *gorm.DB, tables ...interface{}) error { } return nil } + +func initTestDB(t *testing.T, suite string, tables ...interface{}) *gorm.DB { + t.Helper() + + dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("gogs-%s-%d.db", suite, time.Now().Unix())) + db, err := openDB(conf.DatabaseOpts{ + Type: "sqlite3", + Path: dbpath, + }) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + _ = db.Close() + + if t.Failed() { + t.Logf("Database %q left intact for inspection", dbpath) + return + } + + _ = os.Remove(dbpath) + }) + + db.SingularTable(true) + if !testing.Verbose() { + db.SetLogger(&dbutil.Writer{Writer: ioutil.Discard}) + } + + err = db.AutoMigrate(tables...).Error + if err != nil { + t.Fatal(err) + } + + return db +} |