From c85155e583d38f2b8ff85a92c78147b77ef334cf Mon Sep 17 00:00:00 2001 From: Paris Morali Date: Thu, 23 Apr 2020 17:07:01 +0100 Subject: [PATCH 01/11] Fix: Do not automerge with errors or noop Extra guards have been added to preven automatically merging a branch upstream when automerge is enabled but errors exist or if no commands where executed at all. An example of this bug in action is when you delete a plan and atlantis lock via the UI and then execute atlantis apply No projects are applied but the branch is automerged --- server/events/command_runner.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/events/command_runner.go b/server/events/command_runner.go index c008534751..90d4e1c529 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -273,7 +273,8 @@ func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHead c.updateCommitStatus(ctx, cmd.Name, pullStatus) - if cmd.Name == models.ApplyCommand && c.automergeEnabled(ctx, projectCmds) { + // Do not automerge if no commands were executed at all, or if there have been errors + if cmd.Name == models.ApplyCommand && c.automergeEnabled(ctx, projectCmds) && len(projectCmds) > 0 && !result.HasErrors() { c.automerge(ctx, pullStatus) } } From c5eda2742bef25ae211252eab60f006456cf269a Mon Sep 17 00:00:00 2001 From: Paris Morali Date: Sun, 26 Apr 2020 13:55:42 +0100 Subject: [PATCH 02/11] Refactoring model to allow NotPlanned status As part of the fix the model is slightly extended to allow for an extra PlanStatus indicating the absence of a plan for a project. This allows us to unlock a project and delete the plan, without having to completely remove the project status. That means that atlantis knows there is a project that should normally have a plan and be accounted for, but the plan has been deleted/unlocked. The reason this is important is so that we can't "trick" atlantis into thinking that the PR can be merged just because we've lost track of a projectstatus as a result of a manual unlock. --- server/events/command_runner.go | 5 +++-- server/events/db/boltdb.go | 35 +++++++++++++++++++++++++++++++++ server/events/models/models.go | 7 ++++++- server/locks_controller.go | 4 ++-- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/server/events/command_runner.go b/server/events/command_runner.go index 90d4e1c529..bd74d86722 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -273,8 +273,7 @@ func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHead c.updateCommitStatus(ctx, cmd.Name, pullStatus) - // Do not automerge if no commands were executed at all, or if there have been errors - if cmd.Name == models.ApplyCommand && c.automergeEnabled(ctx, projectCmds) && len(projectCmds) > 0 && !result.HasErrors() { + if cmd.Name == models.ApplyCommand && c.automergeEnabled(ctx, projectCmds) { c.automerge(ctx, pullStatus) } } @@ -328,6 +327,7 @@ func (c *DefaultCommandRunner) automerge(ctx *CommandContext, pullStatus models. // Make the API call to perform the merge. ctx.Log.Info("automerging pull request") + err := c.VCSClient.MergePull(ctx.Pull) if err != nil { @@ -338,6 +338,7 @@ func (c *DefaultCommandRunner) automerge(ctx *CommandContext, pullStatus models. ctx.Log.Err("failed to comment about automerge failing: %s", err) } } + } func (c *DefaultCommandRunner) runProjectCmds(cmds []models.ProjectCommandContext, cmdName models.CommandName) CommandResult { diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go index a12a17a343..c41792ceb4 100644 --- a/server/events/db/boltdb.go +++ b/server/events/db/boltdb.go @@ -344,6 +344,41 @@ func (b *BoltDB) DeleteProjectStatus(pull models.PullRequest, workspace string, return errors.Wrap(err, "DB transaction failed") } +// UpdateProjectStatus updates all project statuses under pull that match +// workspace and repoRelDir. +func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { + key, err := b.pullKey(pull) + if err != nil { + return err + } + err = b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.pullsBucketName) + currStatusPtr, err := b.getPullFromBucket(bucket, key) + if err != nil { + return err + } + if currStatusPtr == nil { + return nil + } + currStatus := *currStatusPtr + + // Create a new projectStatuses array without the ones we want to + // delete. + var newProjects []models.ProjectStatus + for _, p := range currStatus.Projects { + if p.Workspace == workspace && p.RepoRelDir == repoRelDir { + p.Status = targetStatus + } + newProjects = append(newProjects, p) + } + + // Overwrite the old pull status. + currStatus.Projects = newProjects + return b.writePullToBucket(bucket, key, currStatus) + }) + return errors.Wrap(err, "DB transaction failed") +} + func (b *BoltDB) pullKey(pull models.PullRequest) ([]byte, error) { hostname := pull.BaseRepo.VCSHost.Hostname if strings.Contains(hostname, pullKeySeparator) { diff --git a/server/events/models/models.go b/server/events/models/models.go index 8e1ec53798..839ad314a8 100644 --- a/server/events/models/models.go +++ b/server/events/models/models.go @@ -476,12 +476,15 @@ const ( // PlannedPlanStatus means that a plan has been successfully generated but // not yet applied. PlannedPlanStatus - // ErrorApplyStatus means that a plan has been generated but there was an + // ErroredApplyStatus means that a plan has been generated but there was an // error while applying it. ErroredApplyStatus // AppliedPlanStatus means that a plan has been generated and applied // successfully. AppliedPlanStatus + // NotPlannedPlanStatus means that either no plan has been generated yet or + // a plan has been deleted - eg after using the UI to unlock the project + NotPlannedPlanStatus ) // String returns a string representation of the status. @@ -495,6 +498,8 @@ func (p ProjectPlanStatus) String() string { return "apply_errored" case AppliedPlanStatus: return "applied" + case NotPlannedPlanStatus: + return "not_planned" default: panic("missing String() impl for ProjectPlanStatus") } diff --git a/server/locks_controller.go b/server/locks_controller.go index 628034d938..02fa3a1842 100644 --- a/server/locks_controller.go +++ b/server/locks_controller.go @@ -108,8 +108,8 @@ func (l *LocksController) DeleteLock(w http.ResponseWriter, r *http.Request) { l.Logger.Err("unable to delete workspace: %s", err) } } - if err := l.DB.DeleteProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path); err != nil { - l.Logger.Err("unable to delete project status: %s", err) + if err := l.DB.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.NotPlannedPlanStatus); err != nil { + l.Logger.Err("unable to update project status: %s", err) } // Once the lock has been deleted, comment back on the pull request. From ce1d577f1d5c27f6bf2ec0861c6ec62ec43e3d7a Mon Sep 17 00:00:00 2001 From: Paris Morali Date: Sat, 9 May 2020 11:42:48 +0100 Subject: [PATCH 03/11] Integrate PR feedback and tests adapted --- server/events/command_runner.go | 2 -- server/events/db/boltdb.go | 35 ----------------------------- server/events/db/boltdb_test.go | 14 ++++++++---- server/events/models/models.go | 10 ++++----- server/events/models/models_test.go | 4 ++++ server/locks_controller.go | 2 +- 6 files changed, 20 insertions(+), 47 deletions(-) diff --git a/server/events/command_runner.go b/server/events/command_runner.go index bd74d86722..c008534751 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -327,7 +327,6 @@ func (c *DefaultCommandRunner) automerge(ctx *CommandContext, pullStatus models. // Make the API call to perform the merge. ctx.Log.Info("automerging pull request") - err := c.VCSClient.MergePull(ctx.Pull) if err != nil { @@ -338,7 +337,6 @@ func (c *DefaultCommandRunner) automerge(ctx *CommandContext, pullStatus models. ctx.Log.Err("failed to comment about automerge failing: %s", err) } } - } func (c *DefaultCommandRunner) runProjectCmds(cmds []models.ProjectCommandContext, cmdName models.CommandName) CommandResult { diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go index c41792ceb4..18d8e26cb6 100644 --- a/server/events/db/boltdb.go +++ b/server/events/db/boltdb.go @@ -309,41 +309,6 @@ func (b *BoltDB) DeletePullStatus(pull models.PullRequest) error { return errors.Wrap(err, "DB transaction failed") } -// DeleteProjectStatus deletes all project statuses under pull that match -// workspace and repoRelDir. -func (b *BoltDB) DeleteProjectStatus(pull models.PullRequest, workspace string, repoRelDir string) error { - key, err := b.pullKey(pull) - if err != nil { - return err - } - err = b.db.Update(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.pullsBucketName) - currStatusPtr, err := b.getPullFromBucket(bucket, key) - if err != nil { - return err - } - if currStatusPtr == nil { - return nil - } - currStatus := *currStatusPtr - - // Create a new projectStatuses array without the ones we want to - // delete. - var newProjects []models.ProjectStatus - for _, p := range currStatus.Projects { - if p.Workspace == workspace && p.RepoRelDir == repoRelDir { - continue - } - newProjects = append(newProjects, p) - } - - // Overwrite the old pull status. - currStatus.Projects = newProjects - return b.writePullToBucket(bucket, key, currStatus) - }) - return errors.Wrap(err, "DB transaction failed") -} - // UpdateProjectStatus updates all project statuses under pull that match // workspace and repoRelDir. func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { diff --git a/server/events/db/boltdb_test.go b/server/events/db/boltdb_test.go index 5eaac70a30..7129bb3ee6 100644 --- a/server/events/db/boltdb_test.go +++ b/server/events/db/boltdb_test.go @@ -449,10 +449,10 @@ func TestPullStatus_UpdateDeleteGet(t *testing.T) { Assert(t, maybeStatus == nil, "exp nil") } -// Test we can create a status, delete a specific project's status within that +// Test we can create a status, update a specific project's status within that // pull status, and when we get all the project statuses, that specific project -// should not be there. -func TestPullStatus_UpdateDeleteProject(t *testing.T) { +// should be updated. +func TestPullStatus_UpdateProject(t *testing.T) { b, cleanup := newTestDB2(t) defer cleanup() @@ -492,7 +492,7 @@ func TestPullStatus_UpdateDeleteProject(t *testing.T) { }) Ok(t, err) - err = b.DeleteProjectStatus(pull, "default", ".") + err = b.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus) Ok(t, err) status, err := b.GetPullStatus(pull) @@ -500,6 +500,12 @@ func TestPullStatus_UpdateDeleteProject(t *testing.T) { Assert(t, status != nil, "exp non-nil") Equals(t, pull, status.Pull) // nolint: staticcheck Equals(t, []models.ProjectStatus{ + { + Workspace: "default", + RepoRelDir: ".", + ProjectName: "", + Status: models.DiscardedPlanStatus, + }, { Workspace: "staging", RepoRelDir: ".", diff --git a/server/events/models/models.go b/server/events/models/models.go index 839ad314a8..84d5ff211e 100644 --- a/server/events/models/models.go +++ b/server/events/models/models.go @@ -482,9 +482,9 @@ const ( // AppliedPlanStatus means that a plan has been generated and applied // successfully. AppliedPlanStatus - // NotPlannedPlanStatus means that either no plan has been generated yet or - // a plan has been deleted - eg after using the UI to unlock the project - NotPlannedPlanStatus + // DiscardedPlanStatus means that there was an unapplied plan that was + // discarded due to a project being unlocked + DiscardedPlanStatus ) // String returns a string representation of the status. @@ -498,8 +498,8 @@ func (p ProjectPlanStatus) String() string { return "apply_errored" case AppliedPlanStatus: return "applied" - case NotPlannedPlanStatus: - return "not_planned" + case DiscardedPlanStatus: + return "plan_discarded" default: panic("missing String() impl for ProjectPlanStatus") } diff --git a/server/events/models/models_test.go b/server/events/models/models_test.go index 4ff59190ca..02eea9e4a6 100644 --- a/server/events/models/models_test.go +++ b/server/events/models/models_test.go @@ -452,6 +452,9 @@ func TestPullStatus_StatusCount(t *testing.T) { { Status: models.ErroredApplyStatus, }, + { + Status: models.DiscardedPlanStatus, + }, }, } @@ -459,4 +462,5 @@ func TestPullStatus_StatusCount(t *testing.T) { Equals(t, 1, ps.StatusCount(models.AppliedPlanStatus)) Equals(t, 1, ps.StatusCount(models.ErroredApplyStatus)) Equals(t, 0, ps.StatusCount(models.ErroredPlanStatus)) + Equals(t, 1, ps.StatusCount(models.DiscardedPlanStatus)) } diff --git a/server/locks_controller.go b/server/locks_controller.go index 02fa3a1842..540d6608ad 100644 --- a/server/locks_controller.go +++ b/server/locks_controller.go @@ -108,7 +108,7 @@ func (l *LocksController) DeleteLock(w http.ResponseWriter, r *http.Request) { l.Logger.Err("unable to delete workspace: %s", err) } } - if err := l.DB.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.NotPlannedPlanStatus); err != nil { + if err := l.DB.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.DiscardedPlanStatus); err != nil { l.Logger.Err("unable to update project status: %s", err) } From ade9b315931a62cfda91c4e38844e39f5a3c7c35 Mon Sep 17 00:00:00 2001 From: Paris Morali Date: Mon, 11 May 2020 15:13:36 +0100 Subject: [PATCH 04/11] Add BoltDB interface and some relevant tests With BoltDB interface we are able to mock/stub and improve test coverage. Some other refactoring was required to make code aware and compatible with the new interface --- server/events/command_runner.go | 2 +- server/events/command_runner_test.go | 55 +++++ server/events/db/boltdb.go | 49 ++-- server/events/db/boltdb_test.go | 4 +- .../matchers/models_projectplanstatus.go | 20 ++ .../db/mocks/matchers/models_pullrequest.go | 20 ++ .../db/mocks/matchers/models_pullstatus.go | 20 ++ .../matchers/slice_of_models_projectresult.go | 20 ++ server/events/db/mocks/mock_boltdb.go | 209 ++++++++++++++++++ server/events/pull_closed_executor.go | 2 +- server/locks_controller.go | 2 +- server/locks_controller_test.go | 42 ++++ 12 files changed, 420 insertions(+), 25 deletions(-) create mode 100644 server/events/db/mocks/matchers/models_projectplanstatus.go create mode 100644 server/events/db/mocks/matchers/models_pullrequest.go create mode 100644 server/events/db/mocks/matchers/models_pullstatus.go create mode 100644 server/events/db/mocks/matchers/slice_of_models_projectresult.go create mode 100644 server/events/db/mocks/mock_boltdb.go diff --git a/server/events/command_runner.go b/server/events/command_runner.go index c008534751..80e164ec0e 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -97,7 +97,7 @@ type DefaultCommandRunner struct { GlobalAutomerge bool PendingPlanFinder PendingPlanFinder WorkingDir WorkingDir - DB *db.BoltDB + DB db.BoltDB } // RunAutoplanCommand runs plan when a pull request is opened or updated. diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index d5efac686c..482c3c50ab 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -24,6 +24,8 @@ import ( "github.com/google/go-github/v28/github" . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/events" + dbmocks "github.com/runatlantis/atlantis/server/events/db/mocks" + dbmatchers "github.com/runatlantis/atlantis/server/events/db/mocks/matchers" "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" @@ -43,6 +45,7 @@ var ch events.DefaultCommandRunner var pullLogger *logging.SimpleLogger var workingDir events.WorkingDir var pendingPlanFinder *mocks.MockPendingPlanFinder +var boltDB *dbmocks.MockBoltDB func setup(t *testing.T) *vcsmocks.MockClient { RegisterMockTestingT(t) @@ -57,6 +60,7 @@ func setup(t *testing.T) *vcsmocks.MockClient { projectCommandRunner = mocks.NewMockProjectCommandRunner() workingDir = mocks.NewMockWorkingDir() pendingPlanFinder = mocks.NewMockPendingPlanFinder() + boltDB = dbmocks.NewMockBoltDB() When(logger.GetLevel()).ThenReturn(logging.Info) When(logger.NewLogger("runatlantis/atlantis#1", true, logging.Info)). ThenReturn(pullLogger) @@ -76,6 +80,7 @@ func setup(t *testing.T) *vcsmocks.MockClient { PendingPlanFinder: pendingPlanFinder, WorkingDir: workingDir, DisableApplyAll: false, + DB: boltDB, } return vcsClient } @@ -234,3 +239,53 @@ func TestRunAutoplanCommand_DeletePlans(t *testing.T) { ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User) pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) } + +func TestApplyWithAutoMerge_VSCMerge(t *testing.T) { + t.Log("if \"atlantis apply\" is run with automerge and at least one project" + + " has a discarded plan, automerge should not take place") + + vcsClient := setup(t) + pull := &github.PullRequest{ + State: github.String("open"), + } + modelPull := models.PullRequest{State: models.OpenPullState} + When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) + ch.GlobalAutomerge = true + + ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) + vcsClient.VerifyWasCalledOnce().MergePull(modelPull) +} + +func TestApplyWithAutoMerge_DiscardedPlan(t *testing.T) { + t.Log("if \"atlantis apply\" is run with automerge and at least one project" + + " has a discarded plan, automerge should not take place") + + setup(t) + pull := &github.PullRequest{ + State: github.String("open"), + } + modelPull := models.PullRequest{State: models.OpenPullState} + When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) + ch.GlobalAutomerge = true + + ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) + projectStatuses := []models.ProjectStatus{ + { + RepoRelDir: ".", + Workspace: "default", + ProjectName: "automerge-test", + Status: models.DiscardedPlanStatus, + }, + } + pullStatus := models.PullStatus{ + Projects: projectStatuses, + Pull: modelPull, + } + //When(boltDB.UpdatePullWithResults(modelPull, nil)).ThenReturn(pullStatus, nil) + When(boltDB.UpdatePullWithResults(dbmatchers.EqModelsPullRequest(modelPull), dbmatchers.EqSliceOfModelsProjectResult(nil))).ThenReturn(pullStatus, nil) + // TODO: stubbing here doesn't seem to work? pullStatus defined here is not actually returned and so I cannot uncomment the next two lines which would verify our scenario here + //vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "not automerging because project at dir %q, workspace %q has status %q") + //VerifyWasCalled(Never()).MergePull(modelPull) +} diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go index 18d8e26cb6..221446c608 100644 --- a/server/events/db/boltdb.go +++ b/server/events/db/boltdb.go @@ -15,8 +15,17 @@ import ( bolt "go.etcd.io/bbolt" ) -// BoltDB is a database using BoltDB -type BoltDB struct { +//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_boltdb.go BoltDB + +// BoltDB interface defines the set of methods the DB implements. Use this to allow DB mocking when testing +type BoltDB interface { + UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) + DeletePullStatus(pull models.PullRequest) error + UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error +} + +// DefaultBoltDB is a database using BoltDB +type DefaultBoltDB struct { db *bolt.DB locksBucketName []byte pullsBucketName []byte @@ -30,7 +39,7 @@ const ( // New returns a valid locker. We need to be able to write to dataDir // since bolt stores its data as a file -func New(dataDir string) (*BoltDB, error) { +func New(dataDir string) (*DefaultBoltDB, error) { if err := os.MkdirAll(dataDir, 0700); err != nil { return nil, errors.Wrap(err, "creating data dir") } @@ -56,19 +65,19 @@ func New(dataDir string) (*BoltDB, error) { return nil, errors.Wrap(err, "starting BoltDB") } // todo: close BoltDB when server is sigtermed - return &BoltDB{db: db, locksBucketName: []byte(locksBucketName), pullsBucketName: []byte(pullsBucketName)}, nil + return &DefaultBoltDB{db: db, locksBucketName: []byte(locksBucketName), pullsBucketName: []byte(pullsBucketName)}, nil } // NewWithDB is used for testing. -func NewWithDB(db *bolt.DB, bucket string) (*BoltDB, error) { - return &BoltDB{db: db, locksBucketName: []byte(bucket), pullsBucketName: []byte(pullsBucketName)}, nil +func NewWithDB(db *bolt.DB, bucket string) (*DefaultBoltDB, error) { + return &DefaultBoltDB{db: db, locksBucketName: []byte(bucket), pullsBucketName: []byte(pullsBucketName)}, nil } // TryLock attempts to create a new lock. If the lock is // acquired, it will return true and the lock returned will be newLock. // If the lock is not acquired, it will return false and the current // lock that is preventing this lock from being acquired. -func (b *BoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { +func (b *DefaultBoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { var lockAcquired bool var currLock models.ProjectLock key := b.lockKey(newLock.Project, newLock.Workspace) @@ -105,7 +114,7 @@ func (b *BoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, // If there is no lock, then it will return a nil pointer. // If there is a lock, then it will delete it, and then return a pointer // to the deleted lock. -func (b *BoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { +func (b *DefaultBoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { var lock models.ProjectLock foundLock := false key := b.lockKey(p, workspace) @@ -128,7 +137,7 @@ func (b *BoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock } // List lists all current locks. -func (b *BoltDB) List() ([]models.ProjectLock, error) { +func (b *DefaultBoltDB) List() ([]models.ProjectLock, error) { var locks []models.ProjectLock var locksBytes [][]byte err := b.db.View(func(tx *bolt.Tx) error { @@ -156,7 +165,7 @@ func (b *BoltDB) List() ([]models.ProjectLock, error) { } // UnlockByPull deletes all locks associated with that pull request and returns them. -func (b *BoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { +func (b *DefaultBoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { var locks []models.ProjectLock err := b.db.View(func(tx *bolt.Tx) error { c := tx.Bucket(b.locksBucketName).Cursor() @@ -188,7 +197,7 @@ func (b *BoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.Projec // GetLock returns a pointer to the lock for that project and workspace. // If there is no lock, it returns a nil pointer. -func (b *BoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { +func (b *DefaultBoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { key := b.lockKey(p, workspace) var lockBytes []byte err := b.db.View(func(tx *bolt.Tx) error { @@ -216,7 +225,7 @@ func (b *BoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLoc // UpdatePullWithResults updates pull's status with the latest project results. // It returns the new PullStatus object. -func (b *BoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { +func (b *DefaultBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { key, err := b.pullKey(pull) if err != nil { return models.PullStatus{}, err @@ -281,7 +290,7 @@ func (b *BoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []mod // GetPullStatus returns the status for pull. // If there is no status, returns a nil pointer. -func (b *BoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { +func (b *DefaultBoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { key, err := b.pullKey(pull) if err != nil { return nil, err @@ -297,7 +306,7 @@ func (b *BoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, err } // DeletePullStatus deletes the status for pull. -func (b *BoltDB) DeletePullStatus(pull models.PullRequest) error { +func (b *DefaultBoltDB) DeletePullStatus(pull models.PullRequest) error { key, err := b.pullKey(pull) if err != nil { return err @@ -311,7 +320,7 @@ func (b *BoltDB) DeletePullStatus(pull models.PullRequest) error { // UpdateProjectStatus updates all project statuses under pull that match // workspace and repoRelDir. -func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { +func (b *DefaultBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { key, err := b.pullKey(pull) if err != nil { return err @@ -344,7 +353,7 @@ func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, return errors.Wrap(err, "DB transaction failed") } -func (b *BoltDB) pullKey(pull models.PullRequest) ([]byte, error) { +func (b *DefaultBoltDB) pullKey(pull models.PullRequest) ([]byte, error) { hostname := pull.BaseRepo.VCSHost.Hostname if strings.Contains(hostname, pullKeySeparator) { return nil, fmt.Errorf("vcs hostname %q contains illegal string %q", hostname, pullKeySeparator) @@ -358,11 +367,11 @@ func (b *BoltDB) pullKey(pull models.PullRequest) ([]byte, error) { nil } -func (b *BoltDB) lockKey(p models.Project, workspace string) string { +func (b *DefaultBoltDB) lockKey(p models.Project, workspace string) string { return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) } -func (b *BoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) { +func (b *DefaultBoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) { serialized := bucket.Get(key) if serialized == nil { return nil, nil @@ -375,7 +384,7 @@ func (b *BoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.Pul return &p, nil } -func (b *BoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models.PullStatus) error { +func (b *DefaultBoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models.PullStatus) error { serialized, err := json.Marshal(pull) if err != nil { return errors.Wrap(err, "serializing") @@ -383,7 +392,7 @@ func (b *BoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models. return bucket.Put(key, serialized) } -func (b *BoltDB) projectResultToProject(p models.ProjectResult) models.ProjectStatus { +func (b *DefaultBoltDB) projectResultToProject(p models.ProjectResult) models.ProjectStatus { return models.ProjectStatus{ Workspace: p.Workspace, RepoRelDir: p.RepoRelDir, diff --git a/server/events/db/boltdb_test.go b/server/events/db/boltdb_test.go index 7129bb3ee6..71b44e6efc 100644 --- a/server/events/db/boltdb_test.go +++ b/server/events/db/boltdb_test.go @@ -692,7 +692,7 @@ func TestPullStatus_UpdateMerge(t *testing.T) { } // newTestDB returns a TestDB using a temporary path. -func newTestDB() (*bolt.DB, *db.BoltDB) { +func newTestDB() (*bolt.DB, *db.DefaultBoltDB) { // Retrieve a temporary path. f, err := ioutil.TempFile("", "") if err != nil { @@ -718,7 +718,7 @@ func newTestDB() (*bolt.DB, *db.BoltDB) { return boltDB, b } -func newTestDB2(t *testing.T) (*db.BoltDB, func()) { +func newTestDB2(t *testing.T) (*db.DefaultBoltDB, func()) { tmp, cleanup := TempDir(t) boltDB, err := db.New(tmp) Ok(t, err) diff --git a/server/events/db/mocks/matchers/models_projectplanstatus.go b/server/events/db/mocks/matchers/models_projectplanstatus.go new file mode 100644 index 0000000000..9a9f2ced62 --- /dev/null +++ b/server/events/db/mocks/matchers/models_projectplanstatus.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsProjectPlanStatus() models.ProjectPlanStatus { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectPlanStatus))(nil)).Elem())) + var nullValue models.ProjectPlanStatus + return nullValue +} + +func EqModelsProjectPlanStatus(value models.ProjectPlanStatus) models.ProjectPlanStatus { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.ProjectPlanStatus + return nullValue +} diff --git a/server/events/db/mocks/matchers/models_pullrequest.go b/server/events/db/mocks/matchers/models_pullrequest.go new file mode 100644 index 0000000000..dd1fb0d4ee --- /dev/null +++ b/server/events/db/mocks/matchers/models_pullrequest.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsPullRequest() models.PullRequest { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) + var nullValue models.PullRequest + return nullValue +} + +func EqModelsPullRequest(value models.PullRequest) models.PullRequest { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.PullRequest + return nullValue +} diff --git a/server/events/db/mocks/matchers/models_pullstatus.go b/server/events/db/mocks/matchers/models_pullstatus.go new file mode 100644 index 0000000000..920d2c5f50 --- /dev/null +++ b/server/events/db/mocks/matchers/models_pullstatus.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsPullStatus() models.PullStatus { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullStatus))(nil)).Elem())) + var nullValue models.PullStatus + return nullValue +} + +func EqModelsPullStatus(value models.PullStatus) models.PullStatus { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.PullStatus + return nullValue +} diff --git a/server/events/db/mocks/matchers/slice_of_models_projectresult.go b/server/events/db/mocks/matchers/slice_of_models_projectresult.go new file mode 100644 index 0000000000..6877535086 --- /dev/null +++ b/server/events/db/mocks/matchers/slice_of_models_projectresult.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnySliceOfModelsProjectResult() []models.ProjectResult { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]models.ProjectResult))(nil)).Elem())) + var nullValue []models.ProjectResult + return nullValue +} + +func EqSliceOfModelsProjectResult(value []models.ProjectResult) []models.ProjectResult { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue []models.ProjectResult + return nullValue +} diff --git a/server/events/db/mocks/mock_boltdb.go b/server/events/db/mocks/mock_boltdb.go new file mode 100644 index 0000000000..f395896d59 --- /dev/null +++ b/server/events/db/mocks/mock_boltdb.go @@ -0,0 +1,209 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events/db (interfaces: BoltDB) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockBoltDB struct { + fail func(message string, callerSkip ...int) +} + +func NewMockBoltDB(options ...pegomock.Option) *MockBoltDB { + mock := &MockBoltDB{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockBoltDB) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockBoltDB) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{pull, newResults} + result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePullWithResults", params, []reflect.Type{reflect.TypeOf((*models.PullStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 models.PullStatus + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(models.PullStatus) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockBoltDB) DeletePullStatus(pull models.PullRequest) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{pull} + result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePullStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(error) + } + } + return ret0 +} + +func (mock *MockBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{pull, workspace, repoRelDir, targetStatus} + result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProjectStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(error) + } + } + return ret0 +} + +func (mock *MockBoltDB) VerifyWasCalledOnce() *VerifierMockBoltDB { + return &VerifierMockBoltDB{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockBoltDB) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockBoltDB { + return &VerifierMockBoltDB{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockBoltDB) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockBoltDB { + return &VerifierMockBoltDB{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockBoltDB) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockBoltDB { + return &VerifierMockBoltDB{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockBoltDB struct { + mock *MockBoltDB + invocationCountMatcher pegomock.Matcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) *MockBoltDB_UpdatePullWithResults_OngoingVerification { + params := []pegomock.Param{pull, newResults} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePullWithResults", params, verifier.timeout) + return &MockBoltDB_UpdatePullWithResults_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_UpdatePullWithResults_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_UpdatePullWithResults_OngoingVerification) GetCapturedArguments() (models.PullRequest, []models.ProjectResult) { + pull, newResults := c.GetAllCapturedArguments() + return pull[len(pull)-1], newResults[len(newResults)-1] +} + +func (c *MockBoltDB_UpdatePullWithResults_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 [][]models.ProjectResult) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.PullRequest) + } + _param1 = make([][]models.ProjectResult, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.([]models.ProjectResult) + } + } + return +} + +func (verifier *VerifierMockBoltDB) DeletePullStatus(pull models.PullRequest) *MockBoltDB_DeletePullStatus_OngoingVerification { + params := []pegomock.Param{pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePullStatus", params, verifier.timeout) + return &MockBoltDB_DeletePullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_DeletePullStatus_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_DeletePullStatus_OngoingVerification) GetCapturedArguments() models.PullRequest { + pull := c.GetAllCapturedArguments() + return pull[len(pull)-1] +} + +func (c *MockBoltDB_DeletePullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.PullRequest) + } + } + return +} + +func (verifier *VerifierMockBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) *MockBoltDB_UpdateProjectStatus_OngoingVerification { + params := []pegomock.Param{pull, workspace, repoRelDir, targetStatus} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProjectStatus", params, verifier.timeout) + return &MockBoltDB_UpdateProjectStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_UpdateProjectStatus_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_UpdateProjectStatus_OngoingVerification) GetCapturedArguments() (models.PullRequest, string, string, models.ProjectPlanStatus) { + pull, workspace, repoRelDir, targetStatus := c.GetAllCapturedArguments() + return pull[len(pull)-1], workspace[len(workspace)-1], repoRelDir[len(repoRelDir)-1], targetStatus[len(targetStatus)-1] +} + +func (c *MockBoltDB_UpdateProjectStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []string, _param2 []string, _param3 []models.ProjectPlanStatus) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.PullRequest) + } + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(string) + } + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(string) + } + _param3 = make([]models.ProjectPlanStatus, len(c.methodInvocations)) + for u, param := range params[3] { + _param3[u] = param.(models.ProjectPlanStatus) + } + } + return +} diff --git a/server/events/pull_closed_executor.go b/server/events/pull_closed_executor.go index b8a5a5219d..309aaa993e 100644 --- a/server/events/pull_closed_executor.go +++ b/server/events/pull_closed_executor.go @@ -46,7 +46,7 @@ type PullClosedExecutor struct { VCSClient vcs.Client WorkingDir WorkingDir Logger logging.SimpleLogging - DB *db.BoltDB + DB db.BoltDB } type templatedProject struct { diff --git a/server/locks_controller.go b/server/locks_controller.go index 540d6608ad..2995c26750 100644 --- a/server/locks_controller.go +++ b/server/locks_controller.go @@ -25,7 +25,7 @@ type LocksController struct { LockDetailTemplate TemplateWriter WorkingDir events.WorkingDir WorkingDirLocker events.WorkingDirLocker - DB *db.BoltDB + DB db.BoltDB } // GetLock is the GET /locks/{id} route. It renders the lock detail view. diff --git a/server/locks_controller_test.go b/server/locks_controller_test.go index 1b159018d5..2bfa7488e9 100644 --- a/server/locks_controller_test.go +++ b/server/locks_controller_test.go @@ -15,6 +15,8 @@ import ( . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server" "github.com/runatlantis/atlantis/server/events" + dbmocks "github.com/runatlantis/atlantis/server/events/db/mocks" + "github.com/runatlantis/atlantis/server/events/locking/mocks" mocks2 "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/models" @@ -192,6 +194,46 @@ func TestDeleteLock_OldFormat(t *testing.T) { cp.VerifyWasCalled(Never()).CreateComment(AnyRepo(), AnyInt(), AnyString()) } +func TestDeleteLock_UpdateProjectStatus(t *testing.T) { + t.Log("When deleting a lock, pull status has to be updated to reflect discarded plan") + RegisterMockTestingT(t) + + repoName := "owner/repo" + projectPath := "path" + workspaceName := "workspace" + + cp := vcsmocks.NewMockClient() + l := mocks.NewMockLocker() + workingDir := mocks2.NewMockWorkingDir() + workingDirLocker := events.NewDefaultWorkingDirLocker() + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: repoName}, + } + When(l.Unlock("id")).ThenReturn(&models.ProjectLock{ + Pull: pull, + Workspace: workspaceName, + Project: models.Project{ + Path: projectPath, + RepoFullName: repoName, + }, + }, nil) + db := dbmocks.NewMockBoltDB() + lc := server.LocksController{ + Locker: l, + Logger: logging.NewNoopLogger(), + VCSClient: cp, + WorkingDirLocker: workingDirLocker, + WorkingDir: workingDir, + DB: db, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + responseContains(t, w, http.StatusOK, "Deleted lock id \"id\"") + db.VerifyWasCalledOnce().UpdateProjectStatus(pull, workspaceName, projectPath, models.DiscardedPlanStatus) +} + func TestDeleteLock_CommentFailed(t *testing.T) { t.Log("If the commenting fails we return an error") RegisterMockTestingT(t) From cb26355da1c236a7f74f8804dbf3de2a10e66925 Mon Sep 17 00:00:00 2001 From: Paris Morali Date: Mon, 25 May 2020 15:58:01 +0100 Subject: [PATCH 05/11] Add the rest of the BoltDB interface methods --- server/events/command_runner_test.go | 34 --- server/events/db/boltdb.go | 6 + .../db/mocks/matchers/models_project.go | 20 ++ .../db/mocks/matchers/models_projectlock.go | 20 ++ .../db/mocks/matchers/models_projectresult.go | 20 ++ .../db/mocks/matchers/models_projectstatus.go | 20 ++ .../db/mocks/matchers/ptr_to_bbolt_bucket.go | 20 ++ .../matchers/ptr_to_models_projectlock.go | 20 ++ .../matchers/ptr_to_models_pullstatus.go | 20 ++ .../events/db/mocks/matchers/slice_of_byte.go | 20 ++ .../matchers/slice_of_models_projectlock.go | 20 ++ server/events/db/mocks/mock_boltdb.go | 282 ++++++++++++++++++ 12 files changed, 468 insertions(+), 34 deletions(-) create mode 100644 server/events/db/mocks/matchers/models_project.go create mode 100644 server/events/db/mocks/matchers/models_projectlock.go create mode 100644 server/events/db/mocks/matchers/models_projectresult.go create mode 100644 server/events/db/mocks/matchers/models_projectstatus.go create mode 100644 server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go create mode 100644 server/events/db/mocks/matchers/ptr_to_models_projectlock.go create mode 100644 server/events/db/mocks/matchers/ptr_to_models_pullstatus.go create mode 100644 server/events/db/mocks/matchers/slice_of_byte.go create mode 100644 server/events/db/mocks/matchers/slice_of_models_projectlock.go diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index 482c3c50ab..cddedad5ea 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -25,7 +25,6 @@ import ( . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/events" dbmocks "github.com/runatlantis/atlantis/server/events/db/mocks" - dbmatchers "github.com/runatlantis/atlantis/server/events/db/mocks/matchers" "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" @@ -256,36 +255,3 @@ func TestApplyWithAutoMerge_VSCMerge(t *testing.T) { ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) vcsClient.VerifyWasCalledOnce().MergePull(modelPull) } - -func TestApplyWithAutoMerge_DiscardedPlan(t *testing.T) { - t.Log("if \"atlantis apply\" is run with automerge and at least one project" + - " has a discarded plan, automerge should not take place") - - setup(t) - pull := &github.PullRequest{ - State: github.String("open"), - } - modelPull := models.PullRequest{State: models.OpenPullState} - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) - When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) - ch.GlobalAutomerge = true - - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) - projectStatuses := []models.ProjectStatus{ - { - RepoRelDir: ".", - Workspace: "default", - ProjectName: "automerge-test", - Status: models.DiscardedPlanStatus, - }, - } - pullStatus := models.PullStatus{ - Projects: projectStatuses, - Pull: modelPull, - } - //When(boltDB.UpdatePullWithResults(modelPull, nil)).ThenReturn(pullStatus, nil) - When(boltDB.UpdatePullWithResults(dbmatchers.EqModelsPullRequest(modelPull), dbmatchers.EqSliceOfModelsProjectResult(nil))).ThenReturn(pullStatus, nil) - // TODO: stubbing here doesn't seem to work? pullStatus defined here is not actually returned and so I cannot uncomment the next two lines which would verify our scenario here - //vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "not automerging because project at dir %q, workspace %q has status %q") - //VerifyWasCalled(Never()).MergePull(modelPull) -} diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go index 221446c608..9be6e137e4 100644 --- a/server/events/db/boltdb.go +++ b/server/events/db/boltdb.go @@ -19,6 +19,12 @@ import ( // BoltDB interface defines the set of methods the DB implements. Use this to allow DB mocking when testing type BoltDB interface { + TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) + Unlock(p models.Project, workspace string) (*models.ProjectLock, error) + List() ([]models.ProjectLock, error) + UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) + GetLock(p models.Project, workspace string) (*models.ProjectLock, error) + GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) DeletePullStatus(pull models.PullRequest) error UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error diff --git a/server/events/db/mocks/matchers/models_project.go b/server/events/db/mocks/matchers/models_project.go new file mode 100644 index 0000000000..4d1a43a965 --- /dev/null +++ b/server/events/db/mocks/matchers/models_project.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsProject() models.Project { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Project))(nil)).Elem())) + var nullValue models.Project + return nullValue +} + +func EqModelsProject(value models.Project) models.Project { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.Project + return nullValue +} diff --git a/server/events/db/mocks/matchers/models_projectlock.go b/server/events/db/mocks/matchers/models_projectlock.go new file mode 100644 index 0000000000..a7f790db0c --- /dev/null +++ b/server/events/db/mocks/matchers/models_projectlock.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsProjectLock() models.ProjectLock { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectLock))(nil)).Elem())) + var nullValue models.ProjectLock + return nullValue +} + +func EqModelsProjectLock(value models.ProjectLock) models.ProjectLock { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.ProjectLock + return nullValue +} diff --git a/server/events/db/mocks/matchers/models_projectresult.go b/server/events/db/mocks/matchers/models_projectresult.go new file mode 100644 index 0000000000..4411f242cb --- /dev/null +++ b/server/events/db/mocks/matchers/models_projectresult.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsProjectResult() models.ProjectResult { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectResult))(nil)).Elem())) + var nullValue models.ProjectResult + return nullValue +} + +func EqModelsProjectResult(value models.ProjectResult) models.ProjectResult { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.ProjectResult + return nullValue +} diff --git a/server/events/db/mocks/matchers/models_projectstatus.go b/server/events/db/mocks/matchers/models_projectstatus.go new file mode 100644 index 0000000000..3a25987bee --- /dev/null +++ b/server/events/db/mocks/matchers/models_projectstatus.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsProjectStatus() models.ProjectStatus { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectStatus))(nil)).Elem())) + var nullValue models.ProjectStatus + return nullValue +} + +func EqModelsProjectStatus(value models.ProjectStatus) models.ProjectStatus { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.ProjectStatus + return nullValue +} diff --git a/server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go b/server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go new file mode 100644 index 0000000000..8d15aff953 --- /dev/null +++ b/server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + bbolt "go.etcd.io/bbolt" +) + +func AnyPtrToBboltBucket() *bbolt.Bucket { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*bbolt.Bucket))(nil)).Elem())) + var nullValue *bbolt.Bucket + return nullValue +} + +func EqPtrToBboltBucket(value *bbolt.Bucket) *bbolt.Bucket { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue *bbolt.Bucket + return nullValue +} diff --git a/server/events/db/mocks/matchers/ptr_to_models_projectlock.go b/server/events/db/mocks/matchers/ptr_to_models_projectlock.go new file mode 100644 index 0000000000..bf95261d17 --- /dev/null +++ b/server/events/db/mocks/matchers/ptr_to_models_projectlock.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyPtrToModelsProjectLock() *models.ProjectLock { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.ProjectLock))(nil)).Elem())) + var nullValue *models.ProjectLock + return nullValue +} + +func EqPtrToModelsProjectLock(value *models.ProjectLock) *models.ProjectLock { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue *models.ProjectLock + return nullValue +} diff --git a/server/events/db/mocks/matchers/ptr_to_models_pullstatus.go b/server/events/db/mocks/matchers/ptr_to_models_pullstatus.go new file mode 100644 index 0000000000..4c61f20001 --- /dev/null +++ b/server/events/db/mocks/matchers/ptr_to_models_pullstatus.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyPtrToModelsPullStatus() *models.PullStatus { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.PullStatus))(nil)).Elem())) + var nullValue *models.PullStatus + return nullValue +} + +func EqPtrToModelsPullStatus(value *models.PullStatus) *models.PullStatus { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue *models.PullStatus + return nullValue +} diff --git a/server/events/db/mocks/matchers/slice_of_byte.go b/server/events/db/mocks/matchers/slice_of_byte.go new file mode 100644 index 0000000000..9a9894fa07 --- /dev/null +++ b/server/events/db/mocks/matchers/slice_of_byte.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + +) + +func AnySliceOfByte() []byte { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]byte))(nil)).Elem())) + var nullValue []byte + return nullValue +} + +func EqSliceOfByte(value []byte) []byte { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue []byte + return nullValue +} diff --git a/server/events/db/mocks/matchers/slice_of_models_projectlock.go b/server/events/db/mocks/matchers/slice_of_models_projectlock.go new file mode 100644 index 0000000000..07666359b7 --- /dev/null +++ b/server/events/db/mocks/matchers/slice_of_models_projectlock.go @@ -0,0 +1,20 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "reflect" + "github.com/petergtz/pegomock" + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnySliceOfModelsProjectLock() []models.ProjectLock { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]models.ProjectLock))(nil)).Elem())) + var nullValue []models.ProjectLock + return nullValue +} + +func EqSliceOfModelsProjectLock(value []models.ProjectLock) []models.ProjectLock { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue []models.ProjectLock + return nullValue +} diff --git a/server/events/db/mocks/mock_boltdb.go b/server/events/db/mocks/mock_boltdb.go index f395896d59..d37853fb86 100644 --- a/server/events/db/mocks/mock_boltdb.go +++ b/server/events/db/mocks/mock_boltdb.go @@ -25,6 +25,124 @@ func NewMockBoltDB(options ...pegomock.Option) *MockBoltDB { func (mock *MockBoltDB) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockBoltDB) FailHandler() pegomock.FailHandler { return mock.fail } +func (mock *MockBoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{newLock} + result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 bool + var ret1 models.ProjectLock + var ret2 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(bool) + } + if result[1] != nil { + ret1 = result[1].(models.ProjectLock) + } + if result[2] != nil { + ret2 = result[2].(error) + } + } + return ret0, ret1, ret2 +} + +func (mock *MockBoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{p, workspace} + result := pegomock.GetGenericMockFrom(mock).Invoke("Unlock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 *models.ProjectLock + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(*models.ProjectLock) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockBoltDB) List() ([]models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{} + result := pegomock.GetGenericMockFrom(mock).Invoke("List", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 []models.ProjectLock + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].([]models.ProjectLock) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockBoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{repoFullName, pullNum} + result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockByPull", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 []models.ProjectLock + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].([]models.ProjectLock) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockBoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{p, workspace} + result := pegomock.GetGenericMockFrom(mock).Invoke("GetLock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 *models.ProjectLock + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(*models.ProjectLock) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockBoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBoltDB().") + } + params := []pegomock.Param{pull} + result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullStatus", params, []reflect.Type{reflect.TypeOf((**models.PullStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 *models.PullStatus + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(*models.PullStatus) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + func (mock *MockBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockBoltDB().") @@ -111,6 +229,170 @@ type VerifierMockBoltDB struct { timeout time.Duration } +func (verifier *VerifierMockBoltDB) TryLock(newLock models.ProjectLock) *MockBoltDB_TryLock_OngoingVerification { + params := []pegomock.Param{newLock} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", params, verifier.timeout) + return &MockBoltDB_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_TryLock_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_TryLock_OngoingVerification) GetCapturedArguments() models.ProjectLock { + newLock := c.GetAllCapturedArguments() + return newLock[len(newLock)-1] +} + +func (c *MockBoltDB_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectLock) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.ProjectLock, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.ProjectLock) + } + } + return +} + +func (verifier *VerifierMockBoltDB) Unlock(p models.Project, workspace string) *MockBoltDB_Unlock_OngoingVerification { + params := []pegomock.Param{p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Unlock", params, verifier.timeout) + return &MockBoltDB_Unlock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_Unlock_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_Unlock_OngoingVerification) GetCapturedArguments() (models.Project, string) { + p, workspace := c.GetAllCapturedArguments() + return p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockBoltDB_Unlock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.Project, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.Project) + } + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(string) + } + } + return +} + +func (verifier *VerifierMockBoltDB) List() *MockBoltDB_List_OngoingVerification { + params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", params, verifier.timeout) + return &MockBoltDB_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_List_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_List_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockBoltDB_List_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockBoltDB) UnlockByPull(repoFullName string, pullNum int) *MockBoltDB_UnlockByPull_OngoingVerification { + params := []pegomock.Param{repoFullName, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockByPull", params, verifier.timeout) + return &MockBoltDB_UnlockByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_UnlockByPull_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_UnlockByPull_OngoingVerification) GetCapturedArguments() (string, int) { + repoFullName, pullNum := c.GetAllCapturedArguments() + return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] +} + +func (c *MockBoltDB_UnlockByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(string) + } + _param1 = make([]int, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(int) + } + } + return +} + +func (verifier *VerifierMockBoltDB) GetLock(p models.Project, workspace string) *MockBoltDB_GetLock_OngoingVerification { + params := []pegomock.Param{p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLock", params, verifier.timeout) + return &MockBoltDB_GetLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_GetLock_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_GetLock_OngoingVerification) GetCapturedArguments() (models.Project, string) { + p, workspace := c.GetAllCapturedArguments() + return p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockBoltDB_GetLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.Project, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.Project) + } + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(string) + } + } + return +} + +func (verifier *VerifierMockBoltDB) GetPullStatus(pull models.PullRequest) *MockBoltDB_GetPullStatus_OngoingVerification { + params := []pegomock.Param{pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullStatus", params, verifier.timeout) + return &MockBoltDB_GetPullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBoltDB_GetPullStatus_OngoingVerification struct { + mock *MockBoltDB + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBoltDB_GetPullStatus_OngoingVerification) GetCapturedArguments() models.PullRequest { + pull := c.GetAllCapturedArguments() + return pull[len(pull)-1] +} + +func (c *MockBoltDB_GetPullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.PullRequest) + } + } + return +} + func (verifier *VerifierMockBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) *MockBoltDB_UpdatePullWithResults_OngoingVerification { params := []pegomock.Param{pull, newResults} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePullWithResults", params, verifier.timeout) From 421b24738eaeaf3a93099507cbb8b712a3f4c298 Mon Sep 17 00:00:00 2001 From: parmouraly Date: Wed, 3 Jun 2020 17:00:30 +0100 Subject: [PATCH 06/11] Integrate some more PR feedback including a test --- server/events/command_runner_test.go | 54 ++++++++++++++++++++++++---- server/events/db/boltdb.go | 23 ++++++------ 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index cddedad5ea..0502be2d7d 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-github/v28/github" . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/events" - dbmocks "github.com/runatlantis/atlantis/server/events/db/mocks" + "github.com/runatlantis/atlantis/server/events/db" "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" @@ -44,7 +44,7 @@ var ch events.DefaultCommandRunner var pullLogger *logging.SimpleLogger var workingDir events.WorkingDir var pendingPlanFinder *mocks.MockPendingPlanFinder -var boltDB *dbmocks.MockBoltDB +var defaultBoltDB *db.DefaultBoltDB func setup(t *testing.T) *vcsmocks.MockClient { RegisterMockTestingT(t) @@ -59,7 +59,12 @@ func setup(t *testing.T) *vcsmocks.MockClient { projectCommandRunner = mocks.NewMockProjectCommandRunner() workingDir = mocks.NewMockWorkingDir() pendingPlanFinder = mocks.NewMockPendingPlanFinder() - boltDB = dbmocks.NewMockBoltDB() + + tmp, cleanup := TempDir(t) + defer cleanup() + defaultBoltDB, err := db.New(tmp) + Ok(t, err) + When(logger.GetLevel()).ThenReturn(logging.Info) When(logger.NewLogger("runatlantis/atlantis#1", true, logging.Info)). ThenReturn(pullLogger) @@ -79,7 +84,7 @@ func setup(t *testing.T) *vcsmocks.MockClient { PendingPlanFinder: pendingPlanFinder, WorkingDir: workingDir, DisableApplyAll: false, - DB: boltDB, + DB: defaultBoltDB, } return vcsClient } @@ -240,8 +245,7 @@ func TestRunAutoplanCommand_DeletePlans(t *testing.T) { } func TestApplyWithAutoMerge_VSCMerge(t *testing.T) { - t.Log("if \"atlantis apply\" is run with automerge and at least one project" + - " has a discarded plan, automerge should not take place") + t.Log("if \"atlantis apply\" is run with automerge then a VCS merge is performed") vcsClient := setup(t) pull := &github.PullRequest{ @@ -251,7 +255,45 @@ func TestApplyWithAutoMerge_VSCMerge(t *testing.T) { When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) ch.GlobalAutomerge = true + defer func() { ch.GlobalAutomerge = false }() ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) vcsClient.VerifyWasCalledOnce().MergePull(modelPull) } + +func TestRunApply_DiscardedProjects(t *testing.T) { + t.Log("if \"atlantis apply\" is run with automerge and at least one project" + + " has a discarded plan, automerge should not take place") + vcsClient := setup(t) + ch.GlobalAutomerge = true + defer func() { ch.GlobalAutomerge = false }() + tmp, cleanup := TempDir(t) + defer cleanup() + boltDB, err := db.New(tmp) + Ok(t, err) + ch.DB = boltDB + pull := fixtures.Pull + pull.BaseRepo = fixtures.GithubRepo + _, err = boltDB.UpdatePullWithResults(pull, []models.ProjectResult{ + { + Command: models.PlanCommand, + RepoRelDir: ".", + Workspace: "default", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "tf-output", + LockURL: "lock-url", + }, + }, + }) + Ok(t, err) + Ok(t, boltDB.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus)) + ghPull := &github.PullRequest{ + State: github.String("open"), + } + When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(ghPull, nil) + When(eventParsing.ParseGithubPull(ghPull)).ThenReturn(pull, pull.BaseRepo, fixtures.GithubRepo, nil) + When(workingDir.GetPullDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())). + ThenReturn(tmp, nil) + ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, &pull, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) + vcsClient.VerifyWasCalled(Never()).MergePull(matchers.AnyModelsPullRequest()) +} diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go index 9be6e137e4..85eab54ce8 100644 --- a/server/events/db/boltdb.go +++ b/server/events/db/boltdb.go @@ -324,9 +324,8 @@ func (b *DefaultBoltDB) DeletePullStatus(pull models.PullRequest) error { return errors.Wrap(err, "DB transaction failed") } -// UpdateProjectStatus updates all project statuses under pull that match -// workspace and repoRelDir. -func (b *DefaultBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { +// UpdateProjectStatus updates project status. +func (b *DefaultBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { key, err := b.pullKey(pull) if err != nil { return err @@ -342,18 +341,16 @@ func (b *DefaultBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace s } currStatus := *currStatusPtr - // Create a new projectStatuses array without the ones we want to - // delete. - var newProjects []models.ProjectStatus - for _, p := range currStatus.Projects { - if p.Workspace == workspace && p.RepoRelDir == repoRelDir { - p.Status = targetStatus + // Update the status. + for i := range currStatus.Projects { + // NOTE: We're using a reference here because we are + // in-place updating its Status field. + proj := &currStatus.Projects[i] + if proj.Workspace == workspace && proj.RepoRelDir == repoRelDir { + proj.Status = newStatus + break } - newProjects = append(newProjects, p) } - - // Overwrite the old pull status. - currStatus.Projects = newProjects return b.writePullToBucket(bucket, key, currStatus) }) return errors.Wrap(err, "DB transaction failed") From 9689dbb981e025757946409587aa5550c624d9ef Mon Sep 17 00:00:00 2001 From: parmouraly Date: Wed, 3 Jun 2020 17:08:16 +0100 Subject: [PATCH 07/11] Fix lint error --- server/events/command_runner_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index 0502be2d7d..53d1861d36 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -44,7 +44,6 @@ var ch events.DefaultCommandRunner var pullLogger *logging.SimpleLogger var workingDir events.WorkingDir var pendingPlanFinder *mocks.MockPendingPlanFinder -var defaultBoltDB *db.DefaultBoltDB func setup(t *testing.T) *vcsmocks.MockClient { RegisterMockTestingT(t) From f546b698000163e4b6af345c6e02461b06cba8ef Mon Sep 17 00:00:00 2001 From: parmouraly Date: Thu, 4 Jun 2020 16:12:26 +0100 Subject: [PATCH 08/11] Remove BoltDB interface and mock as not needed --- server/events/command_runner.go | 2 +- server/events/db/boltdb.go | 55 +- .../db/mocks/matchers/models_project.go | 20 - .../db/mocks/matchers/models_projectlock.go | 20 - .../matchers/models_projectplanstatus.go | 20 - .../db/mocks/matchers/models_projectresult.go | 20 - .../db/mocks/matchers/models_projectstatus.go | 20 - .../db/mocks/matchers/models_pullrequest.go | 20 - .../db/mocks/matchers/models_pullstatus.go | 20 - .../db/mocks/matchers/ptr_to_bbolt_bucket.go | 20 - .../matchers/ptr_to_models_projectlock.go | 20 - .../matchers/ptr_to_models_pullstatus.go | 20 - .../events/db/mocks/matchers/slice_of_byte.go | 20 - .../matchers/slice_of_models_projectlock.go | 20 - .../matchers/slice_of_models_projectresult.go | 20 - server/events/db/mocks/mock_boltdb.go | 491 ------------------ server/locks_controller_test.go | 30 +- server/server.go | 4 +- 18 files changed, 50 insertions(+), 792 deletions(-) delete mode 100644 server/events/db/mocks/matchers/models_project.go delete mode 100644 server/events/db/mocks/matchers/models_projectlock.go delete mode 100644 server/events/db/mocks/matchers/models_projectplanstatus.go delete mode 100644 server/events/db/mocks/matchers/models_projectresult.go delete mode 100644 server/events/db/mocks/matchers/models_projectstatus.go delete mode 100644 server/events/db/mocks/matchers/models_pullrequest.go delete mode 100644 server/events/db/mocks/matchers/models_pullstatus.go delete mode 100644 server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go delete mode 100644 server/events/db/mocks/matchers/ptr_to_models_projectlock.go delete mode 100644 server/events/db/mocks/matchers/ptr_to_models_pullstatus.go delete mode 100644 server/events/db/mocks/matchers/slice_of_byte.go delete mode 100644 server/events/db/mocks/matchers/slice_of_models_projectlock.go delete mode 100644 server/events/db/mocks/matchers/slice_of_models_projectresult.go delete mode 100644 server/events/db/mocks/mock_boltdb.go diff --git a/server/events/command_runner.go b/server/events/command_runner.go index 80e164ec0e..c008534751 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -97,7 +97,7 @@ type DefaultCommandRunner struct { GlobalAutomerge bool PendingPlanFinder PendingPlanFinder WorkingDir WorkingDir - DB db.BoltDB + DB *db.BoltDB } // RunAutoplanCommand runs plan when a pull request is opened or updated. diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go index 85eab54ce8..3da2135dd8 100644 --- a/server/events/db/boltdb.go +++ b/server/events/db/boltdb.go @@ -15,23 +15,8 @@ import ( bolt "go.etcd.io/bbolt" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_boltdb.go BoltDB - -// BoltDB interface defines the set of methods the DB implements. Use this to allow DB mocking when testing -type BoltDB interface { - TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) - Unlock(p models.Project, workspace string) (*models.ProjectLock, error) - List() ([]models.ProjectLock, error) - UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) - GetLock(p models.Project, workspace string) (*models.ProjectLock, error) - GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) - UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) - DeletePullStatus(pull models.PullRequest) error - UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error -} - -// DefaultBoltDB is a database using BoltDB -type DefaultBoltDB struct { +// BoltDB is a database using BoltDB +type BoltDB struct { db *bolt.DB locksBucketName []byte pullsBucketName []byte @@ -45,7 +30,7 @@ const ( // New returns a valid locker. We need to be able to write to dataDir // since bolt stores its data as a file -func New(dataDir string) (*DefaultBoltDB, error) { +func New(dataDir string) (*BoltDB, error) { if err := os.MkdirAll(dataDir, 0700); err != nil { return nil, errors.Wrap(err, "creating data dir") } @@ -71,19 +56,19 @@ func New(dataDir string) (*DefaultBoltDB, error) { return nil, errors.Wrap(err, "starting BoltDB") } // todo: close BoltDB when server is sigtermed - return &DefaultBoltDB{db: db, locksBucketName: []byte(locksBucketName), pullsBucketName: []byte(pullsBucketName)}, nil + return &BoltDB{db: db, locksBucketName: []byte(locksBucketName), pullsBucketName: []byte(pullsBucketName)}, nil } // NewWithDB is used for testing. -func NewWithDB(db *bolt.DB, bucket string) (*DefaultBoltDB, error) { - return &DefaultBoltDB{db: db, locksBucketName: []byte(bucket), pullsBucketName: []byte(pullsBucketName)}, nil +func NewWithDB(db *bolt.DB, bucket string) (*BoltDB, error) { + return &BoltDB{db: db, locksBucketName: []byte(bucket), pullsBucketName: []byte(pullsBucketName)}, nil } // TryLock attempts to create a new lock. If the lock is // acquired, it will return true and the lock returned will be newLock. // If the lock is not acquired, it will return false and the current // lock that is preventing this lock from being acquired. -func (b *DefaultBoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { +func (b *BoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { var lockAcquired bool var currLock models.ProjectLock key := b.lockKey(newLock.Project, newLock.Workspace) @@ -120,7 +105,7 @@ func (b *DefaultBoltDB) TryLock(newLock models.ProjectLock) (bool, models.Projec // If there is no lock, then it will return a nil pointer. // If there is a lock, then it will delete it, and then return a pointer // to the deleted lock. -func (b *DefaultBoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { +func (b *BoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { var lock models.ProjectLock foundLock := false key := b.lockKey(p, workspace) @@ -143,7 +128,7 @@ func (b *DefaultBoltDB) Unlock(p models.Project, workspace string) (*models.Proj } // List lists all current locks. -func (b *DefaultBoltDB) List() ([]models.ProjectLock, error) { +func (b *BoltDB) List() ([]models.ProjectLock, error) { var locks []models.ProjectLock var locksBytes [][]byte err := b.db.View(func(tx *bolt.Tx) error { @@ -171,7 +156,7 @@ func (b *DefaultBoltDB) List() ([]models.ProjectLock, error) { } // UnlockByPull deletes all locks associated with that pull request and returns them. -func (b *DefaultBoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { +func (b *BoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { var locks []models.ProjectLock err := b.db.View(func(tx *bolt.Tx) error { c := tx.Bucket(b.locksBucketName).Cursor() @@ -203,7 +188,7 @@ func (b *DefaultBoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models // GetLock returns a pointer to the lock for that project and workspace. // If there is no lock, it returns a nil pointer. -func (b *DefaultBoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { +func (b *BoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { key := b.lockKey(p, workspace) var lockBytes []byte err := b.db.View(func(tx *bolt.Tx) error { @@ -231,7 +216,7 @@ func (b *DefaultBoltDB) GetLock(p models.Project, workspace string) (*models.Pro // UpdatePullWithResults updates pull's status with the latest project results. // It returns the new PullStatus object. -func (b *DefaultBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { +func (b *BoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { key, err := b.pullKey(pull) if err != nil { return models.PullStatus{}, err @@ -296,7 +281,7 @@ func (b *DefaultBoltDB) UpdatePullWithResults(pull models.PullRequest, newResult // GetPullStatus returns the status for pull. // If there is no status, returns a nil pointer. -func (b *DefaultBoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { +func (b *BoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { key, err := b.pullKey(pull) if err != nil { return nil, err @@ -312,7 +297,7 @@ func (b *DefaultBoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStat } // DeletePullStatus deletes the status for pull. -func (b *DefaultBoltDB) DeletePullStatus(pull models.PullRequest) error { +func (b *BoltDB) DeletePullStatus(pull models.PullRequest) error { key, err := b.pullKey(pull) if err != nil { return err @@ -325,7 +310,7 @@ func (b *DefaultBoltDB) DeletePullStatus(pull models.PullRequest) error { } // UpdateProjectStatus updates project status. -func (b *DefaultBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { +func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { key, err := b.pullKey(pull) if err != nil { return err @@ -356,7 +341,7 @@ func (b *DefaultBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace s return errors.Wrap(err, "DB transaction failed") } -func (b *DefaultBoltDB) pullKey(pull models.PullRequest) ([]byte, error) { +func (b *BoltDB) pullKey(pull models.PullRequest) ([]byte, error) { hostname := pull.BaseRepo.VCSHost.Hostname if strings.Contains(hostname, pullKeySeparator) { return nil, fmt.Errorf("vcs hostname %q contains illegal string %q", hostname, pullKeySeparator) @@ -370,11 +355,11 @@ func (b *DefaultBoltDB) pullKey(pull models.PullRequest) ([]byte, error) { nil } -func (b *DefaultBoltDB) lockKey(p models.Project, workspace string) string { +func (b *BoltDB) lockKey(p models.Project, workspace string) string { return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) } -func (b *DefaultBoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) { +func (b *BoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) { serialized := bucket.Get(key) if serialized == nil { return nil, nil @@ -387,7 +372,7 @@ func (b *DefaultBoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*mod return &p, nil } -func (b *DefaultBoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models.PullStatus) error { +func (b *BoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models.PullStatus) error { serialized, err := json.Marshal(pull) if err != nil { return errors.Wrap(err, "serializing") @@ -395,7 +380,7 @@ func (b *DefaultBoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull return bucket.Put(key, serialized) } -func (b *DefaultBoltDB) projectResultToProject(p models.ProjectResult) models.ProjectStatus { +func (b *BoltDB) projectResultToProject(p models.ProjectResult) models.ProjectStatus { return models.ProjectStatus{ Workspace: p.Workspace, RepoRelDir: p.RepoRelDir, diff --git a/server/events/db/mocks/matchers/models_project.go b/server/events/db/mocks/matchers/models_project.go deleted file mode 100644 index 4d1a43a965..0000000000 --- a/server/events/db/mocks/matchers/models_project.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProject() models.Project { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Project))(nil)).Elem())) - var nullValue models.Project - return nullValue -} - -func EqModelsProject(value models.Project) models.Project { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Project - return nullValue -} diff --git a/server/events/db/mocks/matchers/models_projectlock.go b/server/events/db/mocks/matchers/models_projectlock.go deleted file mode 100644 index a7f790db0c..0000000000 --- a/server/events/db/mocks/matchers/models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectLock() models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectLock))(nil)).Elem())) - var nullValue models.ProjectLock - return nullValue -} - -func EqModelsProjectLock(value models.ProjectLock) models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectLock - return nullValue -} diff --git a/server/events/db/mocks/matchers/models_projectplanstatus.go b/server/events/db/mocks/matchers/models_projectplanstatus.go deleted file mode 100644 index 9a9f2ced62..0000000000 --- a/server/events/db/mocks/matchers/models_projectplanstatus.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectPlanStatus() models.ProjectPlanStatus { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectPlanStatus))(nil)).Elem())) - var nullValue models.ProjectPlanStatus - return nullValue -} - -func EqModelsProjectPlanStatus(value models.ProjectPlanStatus) models.ProjectPlanStatus { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectPlanStatus - return nullValue -} diff --git a/server/events/db/mocks/matchers/models_projectresult.go b/server/events/db/mocks/matchers/models_projectresult.go deleted file mode 100644 index 4411f242cb..0000000000 --- a/server/events/db/mocks/matchers/models_projectresult.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectResult() models.ProjectResult { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectResult))(nil)).Elem())) - var nullValue models.ProjectResult - return nullValue -} - -func EqModelsProjectResult(value models.ProjectResult) models.ProjectResult { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectResult - return nullValue -} diff --git a/server/events/db/mocks/matchers/models_projectstatus.go b/server/events/db/mocks/matchers/models_projectstatus.go deleted file mode 100644 index 3a25987bee..0000000000 --- a/server/events/db/mocks/matchers/models_projectstatus.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectStatus() models.ProjectStatus { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectStatus))(nil)).Elem())) - var nullValue models.ProjectStatus - return nullValue -} - -func EqModelsProjectStatus(value models.ProjectStatus) models.ProjectStatus { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectStatus - return nullValue -} diff --git a/server/events/db/mocks/matchers/models_pullrequest.go b/server/events/db/mocks/matchers/models_pullrequest.go deleted file mode 100644 index dd1fb0d4ee..0000000000 --- a/server/events/db/mocks/matchers/models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequest() models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) - var nullValue models.PullRequest - return nullValue -} - -func EqModelsPullRequest(value models.PullRequest) models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequest - return nullValue -} diff --git a/server/events/db/mocks/matchers/models_pullstatus.go b/server/events/db/mocks/matchers/models_pullstatus.go deleted file mode 100644 index 920d2c5f50..0000000000 --- a/server/events/db/mocks/matchers/models_pullstatus.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullStatus() models.PullStatus { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullStatus))(nil)).Elem())) - var nullValue models.PullStatus - return nullValue -} - -func EqModelsPullStatus(value models.PullStatus) models.PullStatus { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullStatus - return nullValue -} diff --git a/server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go b/server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go deleted file mode 100644 index 8d15aff953..0000000000 --- a/server/events/db/mocks/matchers/ptr_to_bbolt_bucket.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - bbolt "go.etcd.io/bbolt" -) - -func AnyPtrToBboltBucket() *bbolt.Bucket { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*bbolt.Bucket))(nil)).Elem())) - var nullValue *bbolt.Bucket - return nullValue -} - -func EqPtrToBboltBucket(value *bbolt.Bucket) *bbolt.Bucket { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *bbolt.Bucket - return nullValue -} diff --git a/server/events/db/mocks/matchers/ptr_to_models_projectlock.go b/server/events/db/mocks/matchers/ptr_to_models_projectlock.go deleted file mode 100644 index bf95261d17..0000000000 --- a/server/events/db/mocks/matchers/ptr_to_models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyPtrToModelsProjectLock() *models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.ProjectLock))(nil)).Elem())) - var nullValue *models.ProjectLock - return nullValue -} - -func EqPtrToModelsProjectLock(value *models.ProjectLock) *models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *models.ProjectLock - return nullValue -} diff --git a/server/events/db/mocks/matchers/ptr_to_models_pullstatus.go b/server/events/db/mocks/matchers/ptr_to_models_pullstatus.go deleted file mode 100644 index 4c61f20001..0000000000 --- a/server/events/db/mocks/matchers/ptr_to_models_pullstatus.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyPtrToModelsPullStatus() *models.PullStatus { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.PullStatus))(nil)).Elem())) - var nullValue *models.PullStatus - return nullValue -} - -func EqPtrToModelsPullStatus(value *models.PullStatus) *models.PullStatus { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *models.PullStatus - return nullValue -} diff --git a/server/events/db/mocks/matchers/slice_of_byte.go b/server/events/db/mocks/matchers/slice_of_byte.go deleted file mode 100644 index 9a9894fa07..0000000000 --- a/server/events/db/mocks/matchers/slice_of_byte.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfByte() []byte { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]byte))(nil)).Elem())) - var nullValue []byte - return nullValue -} - -func EqSliceOfByte(value []byte) []byte { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []byte - return nullValue -} diff --git a/server/events/db/mocks/matchers/slice_of_models_projectlock.go b/server/events/db/mocks/matchers/slice_of_models_projectlock.go deleted file mode 100644 index 07666359b7..0000000000 --- a/server/events/db/mocks/matchers/slice_of_models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnySliceOfModelsProjectLock() []models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]models.ProjectLock))(nil)).Elem())) - var nullValue []models.ProjectLock - return nullValue -} - -func EqSliceOfModelsProjectLock(value []models.ProjectLock) []models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []models.ProjectLock - return nullValue -} diff --git a/server/events/db/mocks/matchers/slice_of_models_projectresult.go b/server/events/db/mocks/matchers/slice_of_models_projectresult.go deleted file mode 100644 index 6877535086..0000000000 --- a/server/events/db/mocks/matchers/slice_of_models_projectresult.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnySliceOfModelsProjectResult() []models.ProjectResult { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]models.ProjectResult))(nil)).Elem())) - var nullValue []models.ProjectResult - return nullValue -} - -func EqSliceOfModelsProjectResult(value []models.ProjectResult) []models.ProjectResult { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []models.ProjectResult - return nullValue -} diff --git a/server/events/db/mocks/mock_boltdb.go b/server/events/db/mocks/mock_boltdb.go deleted file mode 100644 index d37853fb86..0000000000 --- a/server/events/db/mocks/mock_boltdb.go +++ /dev/null @@ -1,491 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server/events/db (interfaces: BoltDB) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" - "reflect" - "time" -) - -type MockBoltDB struct { - fail func(message string, callerSkip ...int) -} - -func NewMockBoltDB(options ...pegomock.Option) *MockBoltDB { - mock := &MockBoltDB{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockBoltDB) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockBoltDB) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockBoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{newLock} - result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 models.ProjectLock - var ret2 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) - } - if result[1] != nil { - ret1 = result[1].(models.ProjectLock) - } - if result[2] != nil { - ret2 = result[2].(error) - } - } - return ret0, ret1, ret2 -} - -func (mock *MockBoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("Unlock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBoltDB) List() ([]models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("List", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{repoFullName, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockByPull", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetLock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullStatus", params, []reflect.Type{reflect.TypeOf((**models.PullStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.PullStatus - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.PullStatus) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{pull, newResults} - result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePullWithResults", params, []reflect.Type{reflect.TypeOf((*models.PullStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullStatus - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullStatus) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBoltDB) DeletePullStatus(pull models.PullRequest) error { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePullStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) - } - } - return ret0 -} - -func (mock *MockBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) error { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBoltDB().") - } - params := []pegomock.Param{pull, workspace, repoRelDir, targetStatus} - result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProjectStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) - } - } - return ret0 -} - -func (mock *MockBoltDB) VerifyWasCalledOnce() *VerifierMockBoltDB { - return &VerifierMockBoltDB{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockBoltDB) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockBoltDB { - return &VerifierMockBoltDB{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockBoltDB) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockBoltDB { - return &VerifierMockBoltDB{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockBoltDB) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockBoltDB { - return &VerifierMockBoltDB{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockBoltDB struct { - mock *MockBoltDB - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockBoltDB) TryLock(newLock models.ProjectLock) *MockBoltDB_TryLock_OngoingVerification { - params := []pegomock.Param{newLock} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", params, verifier.timeout) - return &MockBoltDB_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_TryLock_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_TryLock_OngoingVerification) GetCapturedArguments() models.ProjectLock { - newLock := c.GetAllCapturedArguments() - return newLock[len(newLock)-1] -} - -func (c *MockBoltDB_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectLock) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectLock, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectLock) - } - } - return -} - -func (verifier *VerifierMockBoltDB) Unlock(p models.Project, workspace string) *MockBoltDB_Unlock_OngoingVerification { - params := []pegomock.Param{p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Unlock", params, verifier.timeout) - return &MockBoltDB_Unlock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_Unlock_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_Unlock_OngoingVerification) GetCapturedArguments() (models.Project, string) { - p, workspace := c.GetAllCapturedArguments() - return p[len(p)-1], workspace[len(workspace)-1] -} - -func (c *MockBoltDB_Unlock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Project, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Project) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - } - return -} - -func (verifier *VerifierMockBoltDB) List() *MockBoltDB_List_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", params, verifier.timeout) - return &MockBoltDB_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_List_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_List_OngoingVerification) GetCapturedArguments() { -} - -func (c *MockBoltDB_List_OngoingVerification) GetAllCapturedArguments() { -} - -func (verifier *VerifierMockBoltDB) UnlockByPull(repoFullName string, pullNum int) *MockBoltDB_UnlockByPull_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockByPull", params, verifier.timeout) - return &MockBoltDB_UnlockByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_UnlockByPull_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_UnlockByPull_OngoingVerification) GetCapturedArguments() (string, int) { - repoFullName, pullNum := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] -} - -func (c *MockBoltDB_UnlockByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) - } - } - return -} - -func (verifier *VerifierMockBoltDB) GetLock(p models.Project, workspace string) *MockBoltDB_GetLock_OngoingVerification { - params := []pegomock.Param{p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLock", params, verifier.timeout) - return &MockBoltDB_GetLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_GetLock_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_GetLock_OngoingVerification) GetCapturedArguments() (models.Project, string) { - p, workspace := c.GetAllCapturedArguments() - return p[len(p)-1], workspace[len(workspace)-1] -} - -func (c *MockBoltDB_GetLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Project, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Project) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - } - return -} - -func (verifier *VerifierMockBoltDB) GetPullStatus(pull models.PullRequest) *MockBoltDB_GetPullStatus_OngoingVerification { - params := []pegomock.Param{pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullStatus", params, verifier.timeout) - return &MockBoltDB_GetPullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_GetPullStatus_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_GetPullStatus_OngoingVerification) GetCapturedArguments() models.PullRequest { - pull := c.GetAllCapturedArguments() - return pull[len(pull)-1] -} - -func (c *MockBoltDB_GetPullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) - } - } - return -} - -func (verifier *VerifierMockBoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) *MockBoltDB_UpdatePullWithResults_OngoingVerification { - params := []pegomock.Param{pull, newResults} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePullWithResults", params, verifier.timeout) - return &MockBoltDB_UpdatePullWithResults_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_UpdatePullWithResults_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_UpdatePullWithResults_OngoingVerification) GetCapturedArguments() (models.PullRequest, []models.ProjectResult) { - pull, newResults := c.GetAllCapturedArguments() - return pull[len(pull)-1], newResults[len(newResults)-1] -} - -func (c *MockBoltDB_UpdatePullWithResults_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 [][]models.ProjectResult) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) - } - _param1 = make([][]models.ProjectResult, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.([]models.ProjectResult) - } - } - return -} - -func (verifier *VerifierMockBoltDB) DeletePullStatus(pull models.PullRequest) *MockBoltDB_DeletePullStatus_OngoingVerification { - params := []pegomock.Param{pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePullStatus", params, verifier.timeout) - return &MockBoltDB_DeletePullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_DeletePullStatus_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_DeletePullStatus_OngoingVerification) GetCapturedArguments() models.PullRequest { - pull := c.GetAllCapturedArguments() - return pull[len(pull)-1] -} - -func (c *MockBoltDB_DeletePullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) - } - } - return -} - -func (verifier *VerifierMockBoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, targetStatus models.ProjectPlanStatus) *MockBoltDB_UpdateProjectStatus_OngoingVerification { - params := []pegomock.Param{pull, workspace, repoRelDir, targetStatus} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProjectStatus", params, verifier.timeout) - return &MockBoltDB_UpdateProjectStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBoltDB_UpdateProjectStatus_OngoingVerification struct { - mock *MockBoltDB - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBoltDB_UpdateProjectStatus_OngoingVerification) GetCapturedArguments() (models.PullRequest, string, string, models.ProjectPlanStatus) { - pull, workspace, repoRelDir, targetStatus := c.GetAllCapturedArguments() - return pull[len(pull)-1], workspace[len(workspace)-1], repoRelDir[len(repoRelDir)-1], targetStatus[len(targetStatus)-1] -} - -func (c *MockBoltDB_UpdateProjectStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []string, _param2 []string, _param3 []models.ProjectPlanStatus) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) - } - _param3 = make([]models.ProjectPlanStatus, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(models.ProjectPlanStatus) - } - } - return -} diff --git a/server/locks_controller_test.go b/server/locks_controller_test.go index 2bfa7488e9..d08b3069d5 100644 --- a/server/locks_controller_test.go +++ b/server/locks_controller_test.go @@ -15,7 +15,6 @@ import ( . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server" "github.com/runatlantis/atlantis/server/events" - dbmocks "github.com/runatlantis/atlantis/server/events/db/mocks" "github.com/runatlantis/atlantis/server/events/locking/mocks" mocks2 "github.com/runatlantis/atlantis/server/events/mocks" @@ -217,7 +216,23 @@ func TestDeleteLock_UpdateProjectStatus(t *testing.T) { RepoFullName: repoName, }, }, nil) - db := dbmocks.NewMockBoltDB() + tmp, cleanup := TempDir(t) + defer cleanup() + db, err := db.New(tmp) + Ok(t, err) + // Seed the DB with a successful plan for that project (that is later discarded). + _, err = db.UpdatePullWithResults(pull, []models.ProjectResult{ + { + Command: models.PlanCommand, + RepoRelDir: projectPath, + Workspace: workspaceName, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "tf-output", + LockURL: "lock-url", + }, + }, + }) + Ok(t, err) lc := server.LocksController{ Locker: l, Logger: logging.NewNoopLogger(), @@ -231,7 +246,16 @@ func TestDeleteLock_UpdateProjectStatus(t *testing.T) { w := httptest.NewRecorder() lc.DeleteLock(w, req) responseContains(t, w, http.StatusOK, "Deleted lock id \"id\"") - db.VerifyWasCalledOnce().UpdateProjectStatus(pull, workspaceName, projectPath, models.DiscardedPlanStatus) + status, err := db.GetPullStatus(pull) + Ok(t, err) + Assert(t, status != nil, "status was nil") + Equals(t, []models.ProjectStatus{ + { + Workspace: workspaceName, + RepoRelDir: projectPath, + Status: models.DiscardedPlanStatus, + }, + }, status.Projects) } func TestDeleteLock_CommentFailed(t *testing.T) { diff --git a/server/server.go b/server/server.go index da7fa46186..897e0d2bad 100644 --- a/server/server.go +++ b/server/server.go @@ -279,7 +279,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { Locker: lockingClient, WorkingDir: workingDir, Logger: logger, - DB: boltdb, + DB: *boltdb, } eventParser := &events.EventParser{ GithubUser: userConfig.GithubUser, @@ -376,7 +376,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { LockDetailTemplate: lockTemplate, WorkingDir: workingDir, WorkingDirLocker: workingDirLocker, - DB: boltdb, + DB: *boltdb, } eventsController := &EventsController{ CommandRunner: commandRunner, From 036e1f699e4bf5b2262a0148a071b99a2e8b2d5c Mon Sep 17 00:00:00 2001 From: parmouraly Date: Thu, 4 Jun 2020 16:21:16 +0100 Subject: [PATCH 09/11] Fix typo on boltDB reference --- server/events/pull_closed_executor.go | 2 +- server/locks_controller.go | 2 +- server/server.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/events/pull_closed_executor.go b/server/events/pull_closed_executor.go index 309aaa993e..b8a5a5219d 100644 --- a/server/events/pull_closed_executor.go +++ b/server/events/pull_closed_executor.go @@ -46,7 +46,7 @@ type PullClosedExecutor struct { VCSClient vcs.Client WorkingDir WorkingDir Logger logging.SimpleLogging - DB db.BoltDB + DB *db.BoltDB } type templatedProject struct { diff --git a/server/locks_controller.go b/server/locks_controller.go index 2995c26750..540d6608ad 100644 --- a/server/locks_controller.go +++ b/server/locks_controller.go @@ -25,7 +25,7 @@ type LocksController struct { LockDetailTemplate TemplateWriter WorkingDir events.WorkingDir WorkingDirLocker events.WorkingDirLocker - DB db.BoltDB + DB *db.BoltDB } // GetLock is the GET /locks/{id} route. It renders the lock detail view. diff --git a/server/server.go b/server/server.go index 897e0d2bad..da7fa46186 100644 --- a/server/server.go +++ b/server/server.go @@ -279,7 +279,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { Locker: lockingClient, WorkingDir: workingDir, Logger: logger, - DB: *boltdb, + DB: boltdb, } eventParser := &events.EventParser{ GithubUser: userConfig.GithubUser, @@ -376,7 +376,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { LockDetailTemplate: lockTemplate, WorkingDir: workingDir, WorkingDirLocker: workingDirLocker, - DB: *boltdb, + DB: boltdb, } eventsController := &EventsController{ CommandRunner: commandRunner, From 8a905f9c0b3e5c270e0658c0ef054f349b52b306 Mon Sep 17 00:00:00 2001 From: parmouraly Date: Thu, 4 Jun 2020 16:27:23 +0100 Subject: [PATCH 10/11] Typo in BoltDB test --- server/events/db/boltdb_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/events/db/boltdb_test.go b/server/events/db/boltdb_test.go index 71b44e6efc..7129bb3ee6 100644 --- a/server/events/db/boltdb_test.go +++ b/server/events/db/boltdb_test.go @@ -692,7 +692,7 @@ func TestPullStatus_UpdateMerge(t *testing.T) { } // newTestDB returns a TestDB using a temporary path. -func newTestDB() (*bolt.DB, *db.DefaultBoltDB) { +func newTestDB() (*bolt.DB, *db.BoltDB) { // Retrieve a temporary path. f, err := ioutil.TempFile("", "") if err != nil { @@ -718,7 +718,7 @@ func newTestDB() (*bolt.DB, *db.DefaultBoltDB) { return boltDB, b } -func newTestDB2(t *testing.T) (*db.DefaultBoltDB, func()) { +func newTestDB2(t *testing.T) (*db.BoltDB, func()) { tmp, cleanup := TempDir(t) boltDB, err := db.New(tmp) Ok(t, err) From abd2161bbb5d97f59f0be73068af3901794a45fb Mon Sep 17 00:00:00 2001 From: parmouraly Date: Thu, 4 Jun 2020 16:46:15 +0100 Subject: [PATCH 11/11] Fix typo from master merge conflict --- server/events/command_runner_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index eefa640730..c32f52d9a8 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -25,7 +25,6 @@ import ( "github.com/google/go-github/v28/github" . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/db" "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" @@ -302,6 +301,7 @@ func TestRunApply_DiscardedProjects(t *testing.T) { ThenReturn(tmp, nil) ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, &pull, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) vcsClient.VerifyWasCalled(Never()).MergePull(matchers.AnyModelsPullRequest()) +} func TestRunCommentCommand_DrainOngoing(t *testing.T) { t.Log("if drain is ongoing then a message should be displayed")