From 0a92ad27efa972d6e960665fd274eb765fbabcec Mon Sep 17 00:00:00 2001 From: Joe Chen Date: Mon, 6 Jun 2022 12:10:36 +0800 Subject: [PATCH] db: use `context` and go-mockgen for `AccessTokensStore` (#7013) --- .deepsource.toml | 2 + .github/workflows/go.yml | 7 +- Taskfile.yml | 3 +- docs/dev/local_development.md | 6 + internal/context/auth.go | 4 +- internal/db/access_tokens.go | 64 +-- internal/db/access_tokens_test.go | 118 ++--- internal/db/mock_gen.go | 214 +++++++++ internal/db/mocks.go | 767 +++++++++++++++++++++++------- internal/route/api/v1/user/app.go | 4 +- internal/route/lfs/route.go | 4 +- internal/route/lfs/route_test.go | 26 +- internal/route/repo/http.go | 4 +- internal/route/user/setting.go | 8 +- 14 files changed, 927 insertions(+), 304 deletions(-) create mode 100644 internal/db/mock_gen.go diff --git a/.deepsource.toml b/.deepsource.toml index 1265553fd..ba82c7c54 100644 --- a/.deepsource.toml +++ b/.deepsource.toml @@ -1,5 +1,7 @@ version = 1 +exclude_patterns = ["**/mocks.go"] + [[analyzers]] name = "docker" enabled = true diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3ad1d6f10..fa7dd593f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -38,17 +38,20 @@ jobs: args: --timeout=30m - name: Install Task uses: arduino/setup-task@v1 + - name: Install goimports and go-mockgen + run: | + go install github.com/derision-test/go-mockgen/cmd/go-mockgen@latest + go install golang.org/x/tools/cmd/goimports@latest - name: Check Go module tidiness and generated files shell: bash run: | go mod tidy task generate - task generate-schemadoc STATUS=$(git status --porcelain) if [ ! -z "$STATUS" ]; then echo "Unstaged files:" echo $STATUS - echo "Run 'go mod tidy', 'task generate' or 'task generate-schemadoc' and commit them" + echo "Run 'go mod tidy' or 'task generate' commit them" exit 1 fi diff --git a/Taskfile.yml b/Taskfile.yml index 9789e61c8..431421b40 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -44,7 +44,8 @@ tasks: generate: desc: Run all go:generate commands - deps: [generate-schemadoc] + cmds: + - go generate ./... test: desc: Run all tests. diff --git a/docs/dev/local_development.md b/docs/dev/local_development.md index 9458de850..7d822ae8f 100644 --- a/docs/dev/local_development.md +++ b/docs/dev/local_development.md @@ -24,6 +24,8 @@ Gogs has the following dependencies: - [Go](https://golang.org/doc/install) (v1.16 or higher) - [Less.js](http://lesscss.org/usage/#command-line-usage-installing) - [Task](https://github.com/go-task/task) (v3) +- [goimports](https://pkg.go.dev/golang.org/x/tools/cmd/goimports) +- [go-mockgen](https://github.com/derision-test/go-mockgen) - Database upon your choice (pick one, we choose PostgreSQL in this document): - [PostgreSQL](https://wiki.postgresql.org/wiki/Detailed_installation_guides) (v9.6 or higher) - [MySQL](https://dev.mysql.com/downloads/mysql/) with `ENGINE=InnoDB` (v5.7 or higher) @@ -39,6 +41,8 @@ Gogs has the following dependencies: brew install go postgresql git npm go-task/tap/go-task npm install -g less npm install -g less-plugin-clean-css + go install github.com/derision-test/go-mockgen/cmd/go-mockgen@latest + go install golang.org/x/tools/cmd/goimports@latest ``` 1. Configure PostgreSQL to start automatically: @@ -75,6 +79,8 @@ Gogs has the following dependencies: sudo apt install -y make git-all postgresql postgresql-contrib golang-go nodejs npm install -g less go install github.com/go-task/task/v3/cmd/task@latest + go install github.com/derision-test/go-mockgen/cmd/go-mockgen@latest + go install golang.org/x/tools/cmd/goimports@latest ``` 1. Configure startup services: diff --git a/internal/context/auth.go b/internal/context/auth.go index bd2b5fb70..021420c57 100644 --- a/internal/context/auth.go +++ b/internal/context/auth.go @@ -130,14 +130,14 @@ func authenticatedUserID(c *macaron.Context, sess session.Store) (_ int64, isTok // Let's see if token is valid. if len(tokenSHA) > 0 { - t, err := db.AccessTokens.GetBySHA1(tokenSHA) + t, err := db.AccessTokens.GetBySHA1(c.Req.Context(), tokenSHA) if err != nil { if !db.IsErrAccessTokenNotExist(err) { log.Error("GetAccessTokenBySHA: %v", err) } return 0, false } - if err = db.AccessTokens.Save(t); err != nil { + if err = db.AccessTokens.Save(c.Req.Context(), t); err != nil { log.Error("UpdateAccessToken: %v", err) } return t.UserID, true diff --git a/internal/db/access_tokens.go b/internal/db/access_tokens.go index 8915f480a..bbb7b851c 100644 --- a/internal/db/access_tokens.go +++ b/internal/db/access_tokens.go @@ -5,6 +5,7 @@ package db import ( + "context" "fmt" "time" @@ -19,22 +20,23 @@ import ( // // NOTE: All methods are sorted in alphabetical order. type AccessTokensStore interface { - // Create creates a new access token and persist to database. - // It returns ErrAccessTokenAlreadyExist when an access token - // with same name already exists for the user. - Create(userID int64, name string) (*AccessToken, error) + // Create creates a new access token and persist to database. It returns + // ErrAccessTokenAlreadyExist when an access token with same name already exists + // for the user. + Create(ctx context.Context, userID int64, name string) (*AccessToken, error) // DeleteByID deletes the access token by given ID. - // 🚨 SECURITY: The "userID" is required to prevent attacker - // deletes arbitrary access token that belongs to another user. - DeleteByID(userID, id int64) error - // GetBySHA1 returns the access token with given SHA1. - // It returns ErrAccessTokenNotExist when not found. - GetBySHA1(sha1 string) (*AccessToken, error) + // + // 🚨 SECURITY: The "userID" is required to prevent attacker deletes arbitrary + // access token that belongs to another user. + DeleteByID(ctx context.Context, userID, id int64) error + // GetBySHA1 returns the access token with given SHA1. It returns + // ErrAccessTokenNotExist when not found. + GetBySHA1(ctx context.Context, sha1 string) (*AccessToken, error) // List returns all access tokens belongs to given user. - List(userID int64) ([]*AccessToken, error) - // Save persists all values of given access token. - // The Updated field is set to current time automatically. - Save(t *AccessToken) error + List(ctx context.Context, userID int64) ([]*AccessToken, error) + // Save persists all values of given access token. The Updated field is set to + // current time automatically. + Save(ctx context.Context, t *AccessToken) error } var AccessTokens AccessTokensStore @@ -42,17 +44,17 @@ var AccessTokens AccessTokensStore // AccessToken is a personal access token. type AccessToken struct { ID int64 - UserID int64 `xorm:"uid INDEX" gorm:"COLUMN:uid;INDEX"` + UserID int64 `gorm:"column:uid;index"` Name string - Sha1 string `xorm:"UNIQUE VARCHAR(40)" gorm:"TYPE:VARCHAR(40);UNIQUE"` + Sha1 string `gorm:"type:VARCHAR(40);unique"` SHA256 string `gorm:"type:VARCHAR(64);unique;not null"` - Created time.Time `xorm:"-" gorm:"-" json:"-"` + Created time.Time `gorm:"-" json:"-"` CreatedUnix int64 - Updated time.Time `xorm:"-" gorm:"-" json:"-"` + Updated time.Time `gorm:"-" json:"-"` UpdatedUnix int64 - HasRecentActivity bool `xorm:"-" gorm:"-" json:"-"` - HasUsed bool `xorm:"-" gorm:"-" json:"-"` + HasRecentActivity bool `gorm:"-" json:"-"` + HasUsed bool `gorm:"-" json:"-"` } // BeforeCreate implements the GORM create hook. @@ -97,8 +99,8 @@ func (err ErrAccessTokenAlreadyExist) Error() string { return fmt.Sprintf("access token already exists: %v", err.args) } -func (db *accessTokens) Create(userID int64, name string) (*AccessToken, error) { - err := db.Where("uid = ? AND name = ?", userID, name).First(new(AccessToken)).Error +func (db *accessTokens) Create(ctx context.Context, userID int64, name string) (*AccessToken, error) { + err := db.WithContext(ctx).Where("uid = ? AND name = ?", userID, name).First(new(AccessToken)).Error if err == nil { return nil, ErrAccessTokenAlreadyExist{args: errutil.Args{"userID": userID, "name": name}} } else if err != gorm.ErrRecordNotFound { @@ -114,7 +116,7 @@ func (db *accessTokens) Create(userID int64, name string) (*AccessToken, error) Sha1: sha256[:40], // To pass the column unique constraint, keep the length of SHA1. SHA256: sha256, } - if err = db.DB.Create(accessToken).Error; err != nil { + if err = db.DB.WithContext(ctx).Create(accessToken).Error; err != nil { return nil, err } @@ -123,8 +125,8 @@ func (db *accessTokens) Create(userID int64, name string) (*AccessToken, error) return accessToken, nil } -func (db *accessTokens) DeleteByID(userID, id int64) error { - return db.Where("id = ? AND uid = ?", id, userID).Delete(new(AccessToken)).Error +func (db *accessTokens) DeleteByID(ctx context.Context, userID, id int64) error { + return db.WithContext(ctx).Where("id = ? AND uid = ?", id, userID).Delete(new(AccessToken)).Error } var _ errutil.NotFound = (*ErrAccessTokenNotExist)(nil) @@ -146,10 +148,10 @@ func (ErrAccessTokenNotExist) NotFound() bool { return true } -func (db *accessTokens) GetBySHA1(sha1 string) (*AccessToken, error) { +func (db *accessTokens) GetBySHA1(ctx context.Context, sha1 string) (*AccessToken, error) { sha256 := cryptoutil.SHA256(sha1) token := new(AccessToken) - err := db.Where("sha256 = ?", sha256).First(token).Error + err := db.WithContext(ctx).Where("sha256 = ?", sha256).First(token).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, ErrAccessTokenNotExist{args: errutil.Args{"sha": sha1}} @@ -159,11 +161,11 @@ func (db *accessTokens) GetBySHA1(sha1 string) (*AccessToken, error) { return token, nil } -func (db *accessTokens) List(userID int64) ([]*AccessToken, error) { +func (db *accessTokens) List(ctx context.Context, userID int64) ([]*AccessToken, error) { var tokens []*AccessToken - return tokens, db.Where("uid = ?", userID).Order("id ASC").Find(&tokens).Error + return tokens, db.WithContext(ctx).Where("uid = ?", userID).Order("id ASC").Find(&tokens).Error } -func (db *accessTokens) Save(t *AccessToken) error { - return db.DB.Save(t).Error +func (db *accessTokens) Save(ctx context.Context, t *AccessToken) error { + return db.DB.WithContext(ctx).Save(t).Error } diff --git a/internal/db/access_tokens_test.go b/internal/db/access_tokens_test.go index 9c0d7759f..7c3024b18 100644 --- a/internal/db/access_tokens_test.go +++ b/internal/db/access_tokens_test.go @@ -5,10 +5,12 @@ package db import ( + "context" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gorm.io/gorm" "gogs.io/gogs/internal/errutil" @@ -77,105 +79,87 @@ func TestAccessTokens(t *testing.T) { } func accessTokensCreate(t *testing.T, db *accessTokens) { + ctx := context.Background() + // Create first access token with name "Test" - token, err := db.Create(1, "Test") - if err != nil { - t.Fatal(err) - } + token, err := db.Create(ctx, 1, "Test") + require.NoError(t, err) assert.Equal(t, int64(1), token.UserID) assert.Equal(t, "Test", token.Name) assert.Equal(t, 40, len(token.Sha1), "sha1 length") // Get it back and check the Created field - token, err = db.GetBySHA1(token.Sha1) - if err != nil { - t.Fatal(err) - } + token, err = db.GetBySHA1(ctx, token.Sha1) + require.NoError(t, err) assert.Equal(t, db.NowFunc().Format(time.RFC3339), token.Created.UTC().Format(time.RFC3339)) // Try create second access token with same name should fail - _, err = db.Create(token.UserID, token.Name) - expErr := ErrAccessTokenAlreadyExist{args: errutil.Args{"userID": token.UserID, "name": token.Name}} - assert.Equal(t, expErr, err) + _, err = db.Create(ctx, token.UserID, token.Name) + wantErr := ErrAccessTokenAlreadyExist{args: errutil.Args{"userID": token.UserID, "name": token.Name}} + assert.Equal(t, wantErr, err) } func accessTokensDeleteByID(t *testing.T, db *accessTokens) { + ctx := context.Background() + // Create an access token with name "Test" - token, err := db.Create(1, "Test") - if err != nil { - t.Fatal(err) - } + token, err := db.Create(ctx, 1, "Test") + require.NoError(t, err) // Delete a token with mismatched user ID is noop - err = db.DeleteByID(2, token.ID) - if err != nil { - t.Fatal(err) - } + err = db.DeleteByID(ctx, 2, token.ID) + require.NoError(t, err) // We should be able to get it back - _, err = db.GetBySHA1(token.Sha1) - if err != nil { - t.Fatal(err) - } - _, err = db.GetBySHA1(token.Sha1) - if err != nil { - t.Fatal(err) - } + _, err = db.GetBySHA1(ctx, token.Sha1) + require.NoError(t, err) + _, err = db.GetBySHA1(ctx, token.Sha1) + require.NoError(t, err) // Now delete this token with correct user ID - err = db.DeleteByID(token.UserID, token.ID) - if err != nil { - t.Fatal(err) - } + err = db.DeleteByID(ctx, token.UserID, token.ID) + require.NoError(t, err) // We should get token not found error - _, err = db.GetBySHA1(token.Sha1) + _, err = db.GetBySHA1(ctx, token.Sha1) expErr := ErrAccessTokenNotExist{args: errutil.Args{"sha": token.Sha1}} assert.Equal(t, expErr, err) } func accessTokensGetBySHA(t *testing.T, db *accessTokens) { + ctx := context.Background() + // Create an access token with name "Test" - token, err := db.Create(1, "Test") - if err != nil { - t.Fatal(err) - } + token, err := db.Create(ctx, 1, "Test") + require.NoError(t, err) // We should be able to get it back - _, err = db.GetBySHA1(token.Sha1) - if err != nil { - t.Fatal(err) - } + _, err = db.GetBySHA1(ctx, token.Sha1) + require.NoError(t, err) // Try to get a non-existent token - _, err = db.GetBySHA1("bad_sha") + _, err = db.GetBySHA1(ctx, "bad_sha") expErr := ErrAccessTokenNotExist{args: errutil.Args{"sha": "bad_sha"}} assert.Equal(t, expErr, err) } func accessTokensList(t *testing.T, db *accessTokens) { + ctx := context.Background() + // Create two access tokens for user 1 - _, err := db.Create(1, "user1_1") - if err != nil { - t.Fatal(err) - } - _, err = db.Create(1, "user1_2") - if err != nil { - t.Fatal(err) - } + _, err := db.Create(ctx, 1, "user1_1") + require.NoError(t, err) + _, err = db.Create(ctx, 1, "user1_2") + require.NoError(t, err) // Create one access token for user 2 - _, err = db.Create(2, "user2_1") - if err != nil { - t.Fatal(err) - } + _, err = db.Create(ctx, 2, "user2_1") + require.NoError(t, err) // List all access tokens for user 1 - tokens, err := db.List(1) - if err != nil { - t.Fatal(err) - } + tokens, err := db.List(ctx, 1) + require.NoError(t, err) assert.Equal(t, 2, len(tokens), "number of tokens") assert.Equal(t, int64(1), tokens[0].UserID) @@ -186,24 +170,20 @@ func accessTokensList(t *testing.T, db *accessTokens) { } func accessTokensSave(t *testing.T, db *accessTokens) { + ctx := context.Background() + // Create an access token with name "Test" - token, err := db.Create(1, "Test") - if err != nil { - t.Fatal(err) - } + token, err := db.Create(ctx, 1, "Test") + require.NoError(t, err) // Updated field is zero now assert.True(t, token.Updated.IsZero()) - err = db.Save(token) - if err != nil { - t.Fatal(err) - } + err = db.Save(ctx, token) + require.NoError(t, err) // Get back from DB should have Updated set - token, err = db.GetBySHA1(token.Sha1) - if err != nil { - t.Fatal(err) - } + token, err = db.GetBySHA1(ctx, token.Sha1) + require.NoError(t, err) assert.Equal(t, db.NowFunc().Format(time.RFC3339), token.Updated.UTC().Format(time.RFC3339)) } diff --git a/internal/db/mock_gen.go b/internal/db/mock_gen.go new file mode 100644 index 000000000..564dcc577 --- /dev/null +++ b/internal/db/mock_gen.go @@ -0,0 +1,214 @@ +// 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" + + "gogs.io/gogs/internal/lfsutil" +) + +//go:generate go-mockgen -f gogs.io/gogs/internal/db -i AccessTokensStore -o mocks.go + +func SetMockAccessTokensStore(t *testing.T, mock AccessTokensStore) { + before := AccessTokens + AccessTokens = mock + t.Cleanup(func() { + AccessTokens = before + }) +} + +var _ LFSStore = (*MockLFSStore)(nil) + +type MockLFSStore struct { + MockCreateObject func(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error + MockGetObjectByOID func(repoID int64, oid lfsutil.OID) (*LFSObject, error) + MockGetObjectsByOIDs func(repoID int64, oids ...lfsutil.OID) ([]*LFSObject, error) +} + +func (m *MockLFSStore) CreateObject(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error { + return m.MockCreateObject(repoID, oid, size, storage) +} + +func (m *MockLFSStore) GetObjectByOID(repoID int64, oid lfsutil.OID) (*LFSObject, error) { + return m.MockGetObjectByOID(repoID, oid) +} + +func (m *MockLFSStore) GetObjectsByOIDs(repoID int64, oids ...lfsutil.OID) ([]*LFSObject, error) { + return m.MockGetObjectsByOIDs(repoID, oids...) +} + +func SetMockLFSStore(t *testing.T, mock LFSStore) { + before := LFS + LFS = mock + t.Cleanup(func() { + LFS = before + }) +} + +var _ loginSourceFilesStore = (*mockLoginSourceFilesStore)(nil) + +type mockLoginSourceFilesStore struct { + MockGetByID func(id int64) (*LoginSource, error) + MockLen func() int + MockList func(opts ListLoginSourceOpts) []*LoginSource + MockUpdate func(source *LoginSource) +} + +func (m *mockLoginSourceFilesStore) GetByID(id int64) (*LoginSource, error) { + return m.MockGetByID(id) +} + +func (m *mockLoginSourceFilesStore) Len() int { + return m.MockLen() +} + +func (m *mockLoginSourceFilesStore) List(opts ListLoginSourceOpts) []*LoginSource { + return m.MockList(opts) +} + +func (m *mockLoginSourceFilesStore) Update(source *LoginSource) { + m.MockUpdate(source) +} + +func setMockLoginSourceFilesStore(t *testing.T, db *loginSources, mock loginSourceFilesStore) { + before := db.files + db.files = mock + t.Cleanup(func() { + db.files = before + }) +} + +var _ loginSourceFileStore = (*mockLoginSourceFileStore)(nil) + +type mockLoginSourceFileStore struct { + MockSetGeneral func(name, value string) + MockSetConfig func(cfg interface{}) error + MockSave func() error +} + +func (m *mockLoginSourceFileStore) SetGeneral(name, value string) { + m.MockSetGeneral(name, value) +} + +func (m *mockLoginSourceFileStore) SetConfig(cfg interface{}) error { + return m.MockSetConfig(cfg) +} + +func (m *mockLoginSourceFileStore) Save() error { + return m.MockSave() +} + +var _ PermsStore = (*MockPermsStore)(nil) + +type MockPermsStore struct { + MockAccessMode func(userID, repoID int64, opts AccessModeOptions) AccessMode + MockAuthorize func(userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool + MockSetRepoPerms func(repoID int64, accessMap map[int64]AccessMode) error +} + +func (m *MockPermsStore) AccessMode(userID, repoID int64, opts AccessModeOptions) AccessMode { + return m.MockAccessMode(userID, repoID, opts) +} + +func (m *MockPermsStore) Authorize(userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool { + return m.MockAuthorize(userID, repoID, desired, opts) +} + +func (m *MockPermsStore) SetRepoPerms(repoID int64, accessMap map[int64]AccessMode) error { + return m.MockSetRepoPerms(repoID, accessMap) +} + +func SetMockPermsStore(t *testing.T, mock PermsStore) { + before := Perms + Perms = mock + t.Cleanup(func() { + Perms = before + }) +} + +var _ ReposStore = (*MockReposStore)(nil) + +type MockReposStore struct { + MockGetByName func(ownerID int64, name string) (*Repository, error) +} + +func (m *MockReposStore) GetByName(ownerID int64, name string) (*Repository, error) { + return m.MockGetByName(ownerID, name) +} + +func SetMockReposStore(t *testing.T, mock ReposStore) { + before := Repos + Repos = mock + t.Cleanup(func() { + Repos = before + }) +} + +var _ TwoFactorsStore = (*MockTwoFactorsStore)(nil) + +type MockTwoFactorsStore struct { + MockCreate func(userID int64, key, secret string) error + MockGetByUserID func(userID int64) (*TwoFactor, error) + MockIsUserEnabled func(userID int64) bool +} + +func (m *MockTwoFactorsStore) Create(userID int64, key, secret string) error { + return m.MockCreate(userID, key, secret) +} + +func (m *MockTwoFactorsStore) GetByUserID(userID int64) (*TwoFactor, error) { + return m.MockGetByUserID(userID) +} + +func (m *MockTwoFactorsStore) IsUserEnabled(userID int64) bool { + return m.MockIsUserEnabled(userID) +} + +func SetMockTwoFactorsStore(t *testing.T, mock TwoFactorsStore) { + before := TwoFactors + TwoFactors = mock + t.Cleanup(func() { + TwoFactors = before + }) +} + +var _ UsersStore = (*MockUsersStore)(nil) + +type MockUsersStore struct { + MockAuthenticate func(username, password string, loginSourceID int64) (*User, error) + MockCreate func(username, email string, opts CreateUserOpts) (*User, error) + MockGetByEmail func(email string) (*User, error) + MockGetByID func(id int64) (*User, error) + MockGetByUsername func(username string) (*User, error) +} + +func (m *MockUsersStore) Authenticate(username, password string, loginSourceID int64) (*User, error) { + return m.MockAuthenticate(username, password, loginSourceID) +} + +func (m *MockUsersStore) Create(username, email string, opts CreateUserOpts) (*User, error) { + return m.MockCreate(username, email, opts) +} + +func (m *MockUsersStore) GetByEmail(email string) (*User, error) { + return m.MockGetByEmail(email) +} + +func (m *MockUsersStore) GetByID(id int64) (*User, error) { + return m.MockGetByID(id) +} + +func (m *MockUsersStore) GetByUsername(username string) (*User, error) { + return m.MockGetByUsername(username) +} + +func SetMockUsersStore(t *testing.T, mock UsersStore) { + before := Users + Users = mock + t.Cleanup(func() { + Users = before + }) +} diff --git a/internal/db/mocks.go b/internal/db/mocks.go index 4addae93b..95c306953 100644 --- a/internal/db/mocks.go +++ b/internal/db/mocks.go @@ -1,244 +1,659 @@ -// 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. +// Code generated by go-mockgen 1.2.0; DO NOT EDIT. package db import ( - "testing" - - "gogs.io/gogs/internal/lfsutil" + "context" + "sync" ) -// NOTE: Mocks are sorted in alphabetical order. - -var _ AccessTokensStore = (*MockAccessTokensStore)(nil) - +// MockAccessTokensStore is a mock implementation of the AccessTokensStore +// interface (from the package gogs.io/gogs/internal/db) used for unit +// testing. type MockAccessTokensStore struct { - MockCreate func(userID int64, name string) (*AccessToken, error) - MockDeleteByID func(userID, id int64) error - MockGetBySHA1 func(sha string) (*AccessToken, error) - MockList func(userID int64) ([]*AccessToken, error) - MockSave func(t *AccessToken) error + // CreateFunc is an instance of a mock function object controlling the + // behavior of the method Create. + CreateFunc *AccessTokensStoreCreateFunc + // DeleteByIDFunc is an instance of a mock function object controlling + // the behavior of the method DeleteByID. + DeleteByIDFunc *AccessTokensStoreDeleteByIDFunc + // GetBySHA1Func is an instance of a mock function object controlling + // the behavior of the method GetBySHA1. + GetBySHA1Func *AccessTokensStoreGetBySHA1Func + // ListFunc is an instance of a mock function object controlling the + // behavior of the method List. + ListFunc *AccessTokensStoreListFunc + // SaveFunc is an instance of a mock function object controlling the + // behavior of the method Save. + SaveFunc *AccessTokensStoreSaveFunc } -func (m *MockAccessTokensStore) Create(userID int64, name string) (*AccessToken, error) { - return m.MockCreate(userID, name) +// NewMockAccessTokensStore creates a new mock of the AccessTokensStore +// interface. All methods return zero values for all results, unless +// overwritten. +func NewMockAccessTokensStore() *MockAccessTokensStore { + return &MockAccessTokensStore{ + CreateFunc: &AccessTokensStoreCreateFunc{ + defaultHook: func(context.Context, int64, string) (r0 *AccessToken, r1 error) { + return + }, + }, + DeleteByIDFunc: &AccessTokensStoreDeleteByIDFunc{ + defaultHook: func(context.Context, int64, int64) (r0 error) { + return + }, + }, + GetBySHA1Func: &AccessTokensStoreGetBySHA1Func{ + defaultHook: func(context.Context, string) (r0 *AccessToken, r1 error) { + return + }, + }, + ListFunc: &AccessTokensStoreListFunc{ + defaultHook: func(context.Context, int64) (r0 []*AccessToken, r1 error) { + return + }, + }, + SaveFunc: &AccessTokensStoreSaveFunc{ + defaultHook: func(context.Context, *AccessToken) (r0 error) { + return + }, + }, + } } -func (m *MockAccessTokensStore) DeleteByID(userID, id int64) error { - return m.MockDeleteByID(userID, id) +// NewStrictMockAccessTokensStore creates a new mock of the +// AccessTokensStore interface. All methods panic on invocation, unless +// overwritten. +func NewStrictMockAccessTokensStore() *MockAccessTokensStore { + return &MockAccessTokensStore{ + CreateFunc: &AccessTokensStoreCreateFunc{ + defaultHook: func(context.Context, int64, string) (*AccessToken, error) { + panic("unexpected invocation of MockAccessTokensStore.Create") + }, + }, + DeleteByIDFunc: &AccessTokensStoreDeleteByIDFunc{ + defaultHook: func(context.Context, int64, int64) error { + panic("unexpected invocation of MockAccessTokensStore.DeleteByID") + }, + }, + GetBySHA1Func: &AccessTokensStoreGetBySHA1Func{ + defaultHook: func(context.Context, string) (*AccessToken, error) { + panic("unexpected invocation of MockAccessTokensStore.GetBySHA1") + }, + }, + ListFunc: &AccessTokensStoreListFunc{ + defaultHook: func(context.Context, int64) ([]*AccessToken, error) { + panic("unexpected invocation of MockAccessTokensStore.List") + }, + }, + SaveFunc: &AccessTokensStoreSaveFunc{ + defaultHook: func(context.Context, *AccessToken) error { + panic("unexpected invocation of MockAccessTokensStore.Save") + }, + }, + } } -func (m *MockAccessTokensStore) GetBySHA1(sha string) (*AccessToken, error) { - return m.MockGetBySHA1(sha) +// NewMockAccessTokensStoreFrom creates a new mock of the +// MockAccessTokensStore interface. All methods delegate to the given +// implementation, unless overwritten. +func NewMockAccessTokensStoreFrom(i AccessTokensStore) *MockAccessTokensStore { + return &MockAccessTokensStore{ + CreateFunc: &AccessTokensStoreCreateFunc{ + defaultHook: i.Create, + }, + DeleteByIDFunc: &AccessTokensStoreDeleteByIDFunc{ + defaultHook: i.DeleteByID, + }, + GetBySHA1Func: &AccessTokensStoreGetBySHA1Func{ + defaultHook: i.GetBySHA1, + }, + ListFunc: &AccessTokensStoreListFunc{ + defaultHook: i.List, + }, + SaveFunc: &AccessTokensStoreSaveFunc{ + defaultHook: i.Save, + }, + } } -func (m *MockAccessTokensStore) List(userID int64) ([]*AccessToken, error) { - return m.MockList(userID) +// AccessTokensStoreCreateFunc describes the behavior when the Create method +// of the parent MockAccessTokensStore instance is invoked. +type AccessTokensStoreCreateFunc struct { + defaultHook func(context.Context, int64, string) (*AccessToken, error) + hooks []func(context.Context, int64, string) (*AccessToken, error) + history []AccessTokensStoreCreateFuncCall + mutex sync.Mutex } -func (m *MockAccessTokensStore) Save(t *AccessToken) error { - return m.MockSave(t) +// Create delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockAccessTokensStore) Create(v0 context.Context, v1 int64, v2 string) (*AccessToken, error) { + r0, r1 := m.CreateFunc.nextHook()(v0, v1, v2) + m.CreateFunc.appendCall(AccessTokensStoreCreateFuncCall{v0, v1, v2, r0, r1}) + return r0, r1 } -func SetMockAccessTokensStore(t *testing.T, mock AccessTokensStore) { - before := AccessTokens - AccessTokens = mock - t.Cleanup(func() { - AccessTokens = before +// SetDefaultHook sets function that is called when the Create method of the +// parent MockAccessTokensStore instance is invoked and the hook queue is +// empty. +func (f *AccessTokensStoreCreateFunc) SetDefaultHook(hook func(context.Context, int64, string) (*AccessToken, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Create method of the parent MockAccessTokensStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *AccessTokensStoreCreateFunc) PushHook(hook func(context.Context, int64, string) (*AccessToken, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AccessTokensStoreCreateFunc) SetDefaultReturn(r0 *AccessToken, r1 error) { + f.SetDefaultHook(func(context.Context, int64, string) (*AccessToken, error) { + return r0, r1 }) } -var _ LFSStore = (*MockLFSStore)(nil) - -type MockLFSStore struct { - MockCreateObject func(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error - MockGetObjectByOID func(repoID int64, oid lfsutil.OID) (*LFSObject, error) - MockGetObjectsByOIDs func(repoID int64, oids ...lfsutil.OID) ([]*LFSObject, error) -} - -func (m *MockLFSStore) CreateObject(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error { - return m.MockCreateObject(repoID, oid, size, storage) -} - -func (m *MockLFSStore) GetObjectByOID(repoID int64, oid lfsutil.OID) (*LFSObject, error) { - return m.MockGetObjectByOID(repoID, oid) -} - -func (m *MockLFSStore) GetObjectsByOIDs(repoID int64, oids ...lfsutil.OID) ([]*LFSObject, error) { - return m.MockGetObjectsByOIDs(repoID, oids...) -} - -func SetMockLFSStore(t *testing.T, mock LFSStore) { - before := LFS - LFS = mock - t.Cleanup(func() { - LFS = before +// PushReturn calls PushHook with a function that returns the given values. +func (f *AccessTokensStoreCreateFunc) PushReturn(r0 *AccessToken, r1 error) { + f.PushHook(func(context.Context, int64, string) (*AccessToken, error) { + return r0, r1 }) } -var _ loginSourceFilesStore = (*mockLoginSourceFilesStore)(nil) +func (f *AccessTokensStoreCreateFunc) nextHook() func(context.Context, int64, string) (*AccessToken, error) { + f.mutex.Lock() + defer f.mutex.Unlock() -type mockLoginSourceFilesStore struct { - MockGetByID func(id int64) (*LoginSource, error) - MockLen func() int - MockList func(opts ListLoginSourceOpts) []*LoginSource - MockUpdate func(source *LoginSource) + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook } -func (m *mockLoginSourceFilesStore) GetByID(id int64) (*LoginSource, error) { - return m.MockGetByID(id) +func (f *AccessTokensStoreCreateFunc) appendCall(r0 AccessTokensStoreCreateFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() } -func (m *mockLoginSourceFilesStore) Len() int { - return m.MockLen() +// History returns a sequence of AccessTokensStoreCreateFuncCall objects +// describing the invocations of this function. +func (f *AccessTokensStoreCreateFunc) History() []AccessTokensStoreCreateFuncCall { + f.mutex.Lock() + history := make([]AccessTokensStoreCreateFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history } -func (m *mockLoginSourceFilesStore) List(opts ListLoginSourceOpts) []*LoginSource { - return m.MockList(opts) +// AccessTokensStoreCreateFuncCall is an object that describes an invocation +// of method Create on an instance of MockAccessTokensStore. +type AccessTokensStoreCreateFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int64 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 *AccessToken + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error } -func (m *mockLoginSourceFilesStore) Update(source *LoginSource) { - m.MockUpdate(source) +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AccessTokensStoreCreateFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} } -func setMockLoginSourceFilesStore(t *testing.T, db *loginSources, mock loginSourceFilesStore) { - before := db.files - db.files = mock - t.Cleanup(func() { - db.files = before +// Results returns an interface slice containing the results of this +// invocation. +func (c AccessTokensStoreCreateFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// AccessTokensStoreDeleteByIDFunc describes the behavior when the +// DeleteByID method of the parent MockAccessTokensStore instance is +// invoked. +type AccessTokensStoreDeleteByIDFunc struct { + defaultHook func(context.Context, int64, int64) error + hooks []func(context.Context, int64, int64) error + history []AccessTokensStoreDeleteByIDFuncCall + mutex sync.Mutex +} + +// DeleteByID delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockAccessTokensStore) DeleteByID(v0 context.Context, v1 int64, v2 int64) error { + r0 := m.DeleteByIDFunc.nextHook()(v0, v1, v2) + m.DeleteByIDFunc.appendCall(AccessTokensStoreDeleteByIDFuncCall{v0, v1, v2, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the DeleteByID method of +// the parent MockAccessTokensStore instance is invoked and the hook queue +// is empty. +func (f *AccessTokensStoreDeleteByIDFunc) SetDefaultHook(hook func(context.Context, int64, int64) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// DeleteByID method of the parent MockAccessTokensStore instance invokes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *AccessTokensStoreDeleteByIDFunc) PushHook(hook func(context.Context, int64, int64) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AccessTokensStoreDeleteByIDFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, int64, int64) error { + return r0 }) } -var _ loginSourceFileStore = (*mockLoginSourceFileStore)(nil) - -type mockLoginSourceFileStore struct { - MockSetGeneral func(name, value string) - MockSetConfig func(cfg interface{}) error - MockSave func() error -} - -func (m *mockLoginSourceFileStore) SetGeneral(name, value string) { - m.MockSetGeneral(name, value) -} - -func (m *mockLoginSourceFileStore) SetConfig(cfg interface{}) error { - return m.MockSetConfig(cfg) -} - -func (m *mockLoginSourceFileStore) Save() error { - return m.MockSave() -} - -var _ PermsStore = (*MockPermsStore)(nil) - -type MockPermsStore struct { - MockAccessMode func(userID, repoID int64, opts AccessModeOptions) AccessMode - MockAuthorize func(userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool - MockSetRepoPerms func(repoID int64, accessMap map[int64]AccessMode) error -} - -func (m *MockPermsStore) AccessMode(userID, repoID int64, opts AccessModeOptions) AccessMode { - return m.MockAccessMode(userID, repoID, opts) -} - -func (m *MockPermsStore) Authorize(userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool { - return m.MockAuthorize(userID, repoID, desired, opts) -} - -func (m *MockPermsStore) SetRepoPerms(repoID int64, accessMap map[int64]AccessMode) error { - return m.MockSetRepoPerms(repoID, accessMap) -} - -func SetMockPermsStore(t *testing.T, mock PermsStore) { - before := Perms - Perms = mock - t.Cleanup(func() { - Perms = before +// PushReturn calls PushHook with a function that returns the given values. +func (f *AccessTokensStoreDeleteByIDFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, int64, int64) error { + return r0 }) } -var _ ReposStore = (*MockReposStore)(nil) +func (f *AccessTokensStoreDeleteByIDFunc) nextHook() func(context.Context, int64, int64) error { + f.mutex.Lock() + defer f.mutex.Unlock() -type MockReposStore struct { - MockGetByName func(ownerID int64, name string) (*Repository, error) + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook } -func (m *MockReposStore) GetByName(ownerID int64, name string) (*Repository, error) { - return m.MockGetByName(ownerID, name) +func (f *AccessTokensStoreDeleteByIDFunc) appendCall(r0 AccessTokensStoreDeleteByIDFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() } -func SetMockReposStore(t *testing.T, mock ReposStore) { - before := Repos - Repos = mock - t.Cleanup(func() { - Repos = before +// History returns a sequence of AccessTokensStoreDeleteByIDFuncCall objects +// describing the invocations of this function. +func (f *AccessTokensStoreDeleteByIDFunc) History() []AccessTokensStoreDeleteByIDFuncCall { + f.mutex.Lock() + history := make([]AccessTokensStoreDeleteByIDFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// AccessTokensStoreDeleteByIDFuncCall is an object that describes an +// invocation of method DeleteByID on an instance of MockAccessTokensStore. +type AccessTokensStoreDeleteByIDFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int64 + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 int64 + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AccessTokensStoreDeleteByIDFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c AccessTokensStoreDeleteByIDFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// AccessTokensStoreGetBySHA1Func describes the behavior when the GetBySHA1 +// method of the parent MockAccessTokensStore instance is invoked. +type AccessTokensStoreGetBySHA1Func struct { + defaultHook func(context.Context, string) (*AccessToken, error) + hooks []func(context.Context, string) (*AccessToken, error) + history []AccessTokensStoreGetBySHA1FuncCall + mutex sync.Mutex +} + +// GetBySHA1 delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockAccessTokensStore) GetBySHA1(v0 context.Context, v1 string) (*AccessToken, error) { + r0, r1 := m.GetBySHA1Func.nextHook()(v0, v1) + m.GetBySHA1Func.appendCall(AccessTokensStoreGetBySHA1FuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetBySHA1 method of +// the parent MockAccessTokensStore instance is invoked and the hook queue +// is empty. +func (f *AccessTokensStoreGetBySHA1Func) SetDefaultHook(hook func(context.Context, string) (*AccessToken, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetBySHA1 method of the parent MockAccessTokensStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *AccessTokensStoreGetBySHA1Func) PushHook(hook func(context.Context, string) (*AccessToken, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AccessTokensStoreGetBySHA1Func) SetDefaultReturn(r0 *AccessToken, r1 error) { + f.SetDefaultHook(func(context.Context, string) (*AccessToken, error) { + return r0, r1 }) } -var _ TwoFactorsStore = (*MockTwoFactorsStore)(nil) - -type MockTwoFactorsStore struct { - MockCreate func(userID int64, key, secret string) error - MockGetByUserID func(userID int64) (*TwoFactor, error) - MockIsUserEnabled func(userID int64) bool -} - -func (m *MockTwoFactorsStore) Create(userID int64, key, secret string) error { - return m.MockCreate(userID, key, secret) -} - -func (m *MockTwoFactorsStore) GetByUserID(userID int64) (*TwoFactor, error) { - return m.MockGetByUserID(userID) -} - -func (m *MockTwoFactorsStore) IsUserEnabled(userID int64) bool { - return m.MockIsUserEnabled(userID) -} - -func SetMockTwoFactorsStore(t *testing.T, mock TwoFactorsStore) { - before := TwoFactors - TwoFactors = mock - t.Cleanup(func() { - TwoFactors = before +// PushReturn calls PushHook with a function that returns the given values. +func (f *AccessTokensStoreGetBySHA1Func) PushReturn(r0 *AccessToken, r1 error) { + f.PushHook(func(context.Context, string) (*AccessToken, error) { + return r0, r1 }) } -var _ UsersStore = (*MockUsersStore)(nil) +func (f *AccessTokensStoreGetBySHA1Func) nextHook() func(context.Context, string) (*AccessToken, error) { + f.mutex.Lock() + defer f.mutex.Unlock() -type MockUsersStore struct { - MockAuthenticate func(username, password string, loginSourceID int64) (*User, error) - MockCreate func(username, email string, opts CreateUserOpts) (*User, error) - MockGetByEmail func(email string) (*User, error) - MockGetByID func(id int64) (*User, error) - MockGetByUsername func(username string) (*User, error) + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook } -func (m *MockUsersStore) Authenticate(username, password string, loginSourceID int64) (*User, error) { - return m.MockAuthenticate(username, password, loginSourceID) +func (f *AccessTokensStoreGetBySHA1Func) appendCall(r0 AccessTokensStoreGetBySHA1FuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() } -func (m *MockUsersStore) Create(username, email string, opts CreateUserOpts) (*User, error) { - return m.MockCreate(username, email, opts) +// History returns a sequence of AccessTokensStoreGetBySHA1FuncCall objects +// describing the invocations of this function. +func (f *AccessTokensStoreGetBySHA1Func) History() []AccessTokensStoreGetBySHA1FuncCall { + f.mutex.Lock() + history := make([]AccessTokensStoreGetBySHA1FuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history } -func (m *MockUsersStore) GetByEmail(email string) (*User, error) { - return m.MockGetByEmail(email) +// AccessTokensStoreGetBySHA1FuncCall is an object that describes an +// invocation of method GetBySHA1 on an instance of MockAccessTokensStore. +type AccessTokensStoreGetBySHA1FuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 *AccessToken + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error } -func (m *MockUsersStore) GetByID(id int64) (*User, error) { - return m.MockGetByID(id) +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AccessTokensStoreGetBySHA1FuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} } -func (m *MockUsersStore) GetByUsername(username string) (*User, error) { - return m.MockGetByUsername(username) +// Results returns an interface slice containing the results of this +// invocation. +func (c AccessTokensStoreGetBySHA1FuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} } -func SetMockUsersStore(t *testing.T, mock UsersStore) { - before := Users - Users = mock - t.Cleanup(func() { - Users = before +// AccessTokensStoreListFunc describes the behavior when the List method of +// the parent MockAccessTokensStore instance is invoked. +type AccessTokensStoreListFunc struct { + defaultHook func(context.Context, int64) ([]*AccessToken, error) + hooks []func(context.Context, int64) ([]*AccessToken, error) + history []AccessTokensStoreListFuncCall + mutex sync.Mutex +} + +// List delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockAccessTokensStore) List(v0 context.Context, v1 int64) ([]*AccessToken, error) { + r0, r1 := m.ListFunc.nextHook()(v0, v1) + m.ListFunc.appendCall(AccessTokensStoreListFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the List method of the +// parent MockAccessTokensStore instance is invoked and the hook queue is +// empty. +func (f *AccessTokensStoreListFunc) SetDefaultHook(hook func(context.Context, int64) ([]*AccessToken, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// List method of the parent MockAccessTokensStore instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *AccessTokensStoreListFunc) PushHook(hook func(context.Context, int64) ([]*AccessToken, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AccessTokensStoreListFunc) SetDefaultReturn(r0 []*AccessToken, r1 error) { + f.SetDefaultHook(func(context.Context, int64) ([]*AccessToken, error) { + return r0, r1 }) } + +// PushReturn calls PushHook with a function that returns the given values. +func (f *AccessTokensStoreListFunc) PushReturn(r0 []*AccessToken, r1 error) { + f.PushHook(func(context.Context, int64) ([]*AccessToken, error) { + return r0, r1 + }) +} + +func (f *AccessTokensStoreListFunc) nextHook() func(context.Context, int64) ([]*AccessToken, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *AccessTokensStoreListFunc) appendCall(r0 AccessTokensStoreListFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of AccessTokensStoreListFuncCall objects +// describing the invocations of this function. +func (f *AccessTokensStoreListFunc) History() []AccessTokensStoreListFuncCall { + f.mutex.Lock() + history := make([]AccessTokensStoreListFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// AccessTokensStoreListFuncCall is an object that describes an invocation +// of method List on an instance of MockAccessTokensStore. +type AccessTokensStoreListFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int64 + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []*AccessToken + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AccessTokensStoreListFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c AccessTokensStoreListFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// AccessTokensStoreSaveFunc describes the behavior when the Save method of +// the parent MockAccessTokensStore instance is invoked. +type AccessTokensStoreSaveFunc struct { + defaultHook func(context.Context, *AccessToken) error + hooks []func(context.Context, *AccessToken) error + history []AccessTokensStoreSaveFuncCall + mutex sync.Mutex +} + +// Save delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockAccessTokensStore) Save(v0 context.Context, v1 *AccessToken) error { + r0 := m.SaveFunc.nextHook()(v0, v1) + m.SaveFunc.appendCall(AccessTokensStoreSaveFuncCall{v0, v1, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the Save method of the +// parent MockAccessTokensStore instance is invoked and the hook queue is +// empty. +func (f *AccessTokensStoreSaveFunc) SetDefaultHook(hook func(context.Context, *AccessToken) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Save method of the parent MockAccessTokensStore instance invokes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *AccessTokensStoreSaveFunc) PushHook(hook func(context.Context, *AccessToken) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AccessTokensStoreSaveFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, *AccessToken) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *AccessTokensStoreSaveFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, *AccessToken) error { + return r0 + }) +} + +func (f *AccessTokensStoreSaveFunc) nextHook() func(context.Context, *AccessToken) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *AccessTokensStoreSaveFunc) appendCall(r0 AccessTokensStoreSaveFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of AccessTokensStoreSaveFuncCall objects +// describing the invocations of this function. +func (f *AccessTokensStoreSaveFunc) History() []AccessTokensStoreSaveFuncCall { + f.mutex.Lock() + history := make([]AccessTokensStoreSaveFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// AccessTokensStoreSaveFuncCall is an object that describes an invocation +// of method Save on an instance of MockAccessTokensStore. +type AccessTokensStoreSaveFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 *AccessToken + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AccessTokensStoreSaveFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c AccessTokensStoreSaveFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} diff --git a/internal/route/api/v1/user/app.go b/internal/route/api/v1/user/app.go index 5afa34fba..dce7d4215 100644 --- a/internal/route/api/v1/user/app.go +++ b/internal/route/api/v1/user/app.go @@ -14,7 +14,7 @@ import ( ) func ListAccessTokens(c *context.APIContext) { - tokens, err := db.AccessTokens.List(c.User.ID) + tokens, err := db.AccessTokens.List(c.Req.Context(), c.User.ID) if err != nil { c.Error(err, "list access tokens") return @@ -28,7 +28,7 @@ func ListAccessTokens(c *context.APIContext) { } func CreateAccessToken(c *context.APIContext, form api.CreateAccessTokenOption) { - t, err := db.AccessTokens.Create(c.User.ID, form.Name) + t, err := db.AccessTokens.Create(c.Req.Context(), c.User.ID, form.Name) if err != nil { if db.IsErrAccessTokenAlreadyExist(err) { c.ErrorStatus(http.StatusUnprocessableEntity, err) diff --git a/internal/route/lfs/route.go b/internal/route/lfs/route.go index 388dde0ca..78a45fde2 100644 --- a/internal/route/lfs/route.go +++ b/internal/route/lfs/route.go @@ -72,7 +72,7 @@ func authenticate() macaron.Handler { // If username and password authentication failed, try again using username as an access token. if auth.IsErrBadCredentials(err) { - token, err := db.AccessTokens.GetBySHA1(username) + token, err := db.AccessTokens.GetBySHA1(c.Req.Context(), username) if err != nil { if db.IsErrAccessTokenNotExist(err) { askCredentials(c.Resp) @@ -82,7 +82,7 @@ func authenticate() macaron.Handler { } return } - if err = db.AccessTokens.Save(token); err != nil { + if err = db.AccessTokens.Save(c.Req.Context(), token); err != nil { log.Error("Failed to update access token: %v", err) } diff --git a/internal/route/lfs/route_test.go b/internal/route/lfs/route_test.go index 119b925ee..a07121cc1 100644 --- a/internal/route/lfs/route_test.go +++ b/internal/route/lfs/route_test.go @@ -31,7 +31,7 @@ func Test_authenticate(t *testing.T) { header http.Header mockUsersStore *db.MockUsersStore mockTwoFactorsStore *db.MockTwoFactorsStore - mockAccessTokensStore *db.MockAccessTokensStore + mockAccessTokensStore func() db.AccessTokensStore expStatusCode int expHeader http.Header expBody string @@ -74,10 +74,10 @@ func Test_authenticate(t *testing.T) { return nil, auth.ErrBadCredentials{} }, }, - mockAccessTokensStore: &db.MockAccessTokensStore{ - MockGetBySHA1: func(sha string) (*db.AccessToken, error) { - return nil, db.ErrAccessTokenNotExist{} - }, + mockAccessTokensStore: func() db.AccessTokensStore { + mock := db.NewMockAccessTokensStore() + mock.GetBySHA1Func.SetDefaultReturn(nil, db.ErrAccessTokenNotExist{}) + return mock }, expStatusCode: http.StatusUnauthorized, expHeader: http.Header{ @@ -119,13 +119,10 @@ func Test_authenticate(t *testing.T) { return &db.User{ID: 1, Name: "unknwon"}, nil }, }, - mockAccessTokensStore: &db.MockAccessTokensStore{ - MockGetBySHA1: func(sha string) (*db.AccessToken, error) { - return &db.AccessToken{}, nil - }, - MockSave: func(t *db.AccessToken) error { - return nil - }, + mockAccessTokensStore: func() db.AccessTokensStore { + mock := db.NewMockAccessTokensStore() + mock.GetBySHA1Func.SetDefaultReturn(&db.AccessToken{}, nil) + return mock }, expStatusCode: http.StatusOK, expHeader: http.Header{}, @@ -136,7 +133,10 @@ func Test_authenticate(t *testing.T) { t.Run(test.name, func(t *testing.T) { db.SetMockUsersStore(t, test.mockUsersStore) db.SetMockTwoFactorsStore(t, test.mockTwoFactorsStore) - db.SetMockAccessTokensStore(t, test.mockAccessTokensStore) + + if test.mockAccessTokensStore != nil { + db.SetMockAccessTokensStore(t, test.mockAccessTokensStore()) + } r, err := http.NewRequest("GET", "/", nil) if err != nil { diff --git a/internal/route/repo/http.go b/internal/route/repo/http.go index b5bbefc1f..575719f1f 100644 --- a/internal/route/repo/http.go +++ b/internal/route/repo/http.go @@ -131,7 +131,7 @@ func HTTPContexter() macaron.Handler { // If username and password combination failed, try again using username as a token. if authUser == nil { - token, err := db.AccessTokens.GetBySHA1(authUsername) + token, err := db.AccessTokens.GetBySHA1(c.Req.Context(), authUsername) if err != nil { if db.IsErrAccessTokenNotExist(err) { askCredentials(c, http.StatusUnauthorized, "") @@ -141,7 +141,7 @@ func HTTPContexter() macaron.Handler { } return } - if err = db.AccessTokens.Save(token); err != nil { + if err = db.AccessTokens.Save(c.Req.Context(), token); err != nil { log.Error("Failed to update access token: %v", err) } diff --git a/internal/route/user/setting.go b/internal/route/user/setting.go index 5d879f42f..cf2226c53 100644 --- a/internal/route/user/setting.go +++ b/internal/route/user/setting.go @@ -581,7 +581,7 @@ func SettingsApplications(c *context.Context) { c.Title("settings.applications") c.PageIs("SettingsApplications") - tokens, err := db.AccessTokens.List(c.User.ID) + tokens, err := db.AccessTokens.List(c.Req.Context(), c.User.ID) if err != nil { c.Errorf(err, "list access tokens") return @@ -596,7 +596,7 @@ func SettingsApplicationsPost(c *context.Context, f form.NewAccessToken) { c.PageIs("SettingsApplications") if c.HasError() { - tokens, err := db.AccessTokens.List(c.User.ID) + tokens, err := db.AccessTokens.List(c.Req.Context(), c.User.ID) if err != nil { c.Errorf(err, "list access tokens") return @@ -607,7 +607,7 @@ func SettingsApplicationsPost(c *context.Context, f form.NewAccessToken) { return } - t, err := db.AccessTokens.Create(c.User.ID, f.Name) + t, err := db.AccessTokens.Create(c.Req.Context(), c.User.ID, f.Name) if err != nil { if db.IsErrAccessTokenAlreadyExist(err) { c.Flash.Error(c.Tr("settings.token_name_exists")) @@ -624,7 +624,7 @@ func SettingsApplicationsPost(c *context.Context, f form.NewAccessToken) { } func SettingsDeleteApplication(c *context.Context) { - if err := db.AccessTokens.DeleteByID(c.User.ID, c.QueryInt64("id")); err != nil { + if err := db.AccessTokens.DeleteByID(c.Req.Context(), c.User.ID, c.QueryInt64("id")); err != nil { c.Flash.Error("DeleteAccessTokenByID: " + err.Error()) } else { c.Flash.Success(c.Tr("settings.delete_token_success"))