mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 19:48:34 +00:00
* fix: add path to DefaultWorkingDirLocker.TryLock() In the release notes for v0.13.0: https://github.com/runatlantis/atlantis/blob/master/CHANGELOG.md#features-4 > Running in parallel is only supported if you're using workspaces to separate your projects. Projects in separate directories can not be run in parallel currently. This commit adds `path` as an argument to `DefaultWorkingDirLocker.TryLock()` and includes `path` in the `workspaceKey` used to check if a project is locked. This should allow projects in separate directories to run in parallel. To my knowledge, there is no functional reason that projects in separate directories cannot run in parallel. All calls to `DefaultWorkingDirLocker.TryLock()` have been updated. A new unit test `TestTryLockWithDifferentPaths` has been added to test the behavior of locking two separate directories with the same workspace name. * Add documntation for parallel_plan and parallel_apply options Co-authored-by: Kevin Snyder <kevinsnyder@ip-192-168-4-61.ec2.internal> Co-authored-by: Kevin Snyder <kevinsnyder@ip-10-60-10-94.ec2.internal>
223 lines
6.3 KiB
Go
223 lines
6.3 KiB
Go
package events_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
. "github.com/petergtz/pegomock"
|
|
"github.com/runatlantis/atlantis/server/core/config/valid"
|
|
runtime_mocks "github.com/runatlantis/atlantis/server/core/runtime/mocks"
|
|
"github.com/runatlantis/atlantis/server/events"
|
|
"github.com/runatlantis/atlantis/server/events/command"
|
|
"github.com/runatlantis/atlantis/server/events/mocks"
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
"github.com/runatlantis/atlantis/server/events/models/fixtures"
|
|
vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks"
|
|
"github.com/runatlantis/atlantis/server/logging"
|
|
. "github.com/runatlantis/atlantis/testing"
|
|
)
|
|
|
|
var preWh events.DefaultPreWorkflowHooksCommandRunner
|
|
var preWhWorkingDir *mocks.MockWorkingDir
|
|
var preWhWorkingDirLocker *mocks.MockWorkingDirLocker
|
|
var whPreWorkflowHookRunner *runtime_mocks.MockPreWorkflowHookRunner
|
|
|
|
func preWorkflowHooksSetup(t *testing.T) {
|
|
RegisterMockTestingT(t)
|
|
vcsClient := vcsmocks.NewMockClient()
|
|
preWhWorkingDir = mocks.NewMockWorkingDir()
|
|
preWhWorkingDirLocker = mocks.NewMockWorkingDirLocker()
|
|
whPreWorkflowHookRunner = runtime_mocks.NewMockPreWorkflowHookRunner()
|
|
|
|
preWh = events.DefaultPreWorkflowHooksCommandRunner{
|
|
VCSClient: vcsClient,
|
|
WorkingDirLocker: preWhWorkingDirLocker,
|
|
WorkingDir: preWhWorkingDir,
|
|
PreWorkflowHookRunner: whPreWorkflowHookRunner,
|
|
}
|
|
}
|
|
|
|
func newBool(b bool) *bool {
|
|
return &b
|
|
}
|
|
|
|
func TestRunPreHooks_Clone(t *testing.T) {
|
|
|
|
log := logging.NewNoopLogger(t)
|
|
|
|
var newPull = fixtures.Pull
|
|
newPull.BaseRepo = fixtures.GithubRepo
|
|
|
|
ctx := &command.Context{
|
|
Pull: newPull,
|
|
HeadRepo: fixtures.GithubRepo,
|
|
User: fixtures.User,
|
|
Log: log,
|
|
}
|
|
|
|
testHook := valid.WorkflowHook{
|
|
StepName: "test",
|
|
RunCommand: "some command",
|
|
}
|
|
|
|
pCtx := models.WorkflowHookCommandContext{
|
|
BaseRepo: fixtures.GithubRepo,
|
|
HeadRepo: fixtures.GithubRepo,
|
|
Pull: newPull,
|
|
Log: log,
|
|
User: fixtures.User,
|
|
Verbose: false,
|
|
}
|
|
|
|
repoDir := "path/to/repo"
|
|
result := "some result"
|
|
|
|
t.Run("success hooks in cfg", func(t *testing.T) {
|
|
preWorkflowHooksSetup(t)
|
|
|
|
var unlockCalled = newBool(false)
|
|
unlockFn := func() {
|
|
unlockCalled = newBool(true)
|
|
}
|
|
|
|
globalCfg := valid.GlobalCfg{
|
|
Repos: []valid.Repo{
|
|
{
|
|
ID: fixtures.GithubRepo.ID(),
|
|
PreWorkflowHooks: []*valid.WorkflowHook{
|
|
&testHook,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
preWh.GlobalCfg = globalCfg
|
|
|
|
When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
|
|
When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil)
|
|
When(whPreWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil)
|
|
|
|
err := preWh.RunPreHooks(ctx)
|
|
|
|
Ok(t, err)
|
|
whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(pCtx, testHook.RunCommand, repoDir)
|
|
Assert(t, *unlockCalled == true, "unlock function called")
|
|
})
|
|
t.Run("success hooks not in cfg", func(t *testing.T) {
|
|
preWorkflowHooksSetup(t)
|
|
globalCfg := valid.GlobalCfg{
|
|
Repos: []valid.Repo{
|
|
// one with hooks but mismatched id
|
|
{
|
|
ID: "id1",
|
|
PreWorkflowHooks: []*valid.WorkflowHook{
|
|
&testHook,
|
|
},
|
|
},
|
|
// one with the correct id but no hooks
|
|
{
|
|
ID: fixtures.GithubRepo.ID(),
|
|
PreWorkflowHooks: []*valid.WorkflowHook{},
|
|
},
|
|
},
|
|
}
|
|
|
|
preWh.GlobalCfg = globalCfg
|
|
|
|
err := preWh.RunPreHooks(ctx)
|
|
|
|
Ok(t, err)
|
|
|
|
whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(pCtx, testHook.RunCommand, repoDir)
|
|
preWhWorkingDirLocker.VerifyWasCalled(Never()).TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)
|
|
preWhWorkingDir.VerifyWasCalled(Never()).Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)
|
|
})
|
|
t.Run("error locking work dir", func(t *testing.T) {
|
|
preWorkflowHooksSetup(t)
|
|
|
|
globalCfg := valid.GlobalCfg{
|
|
Repos: []valid.Repo{
|
|
{
|
|
ID: fixtures.GithubRepo.ID(),
|
|
PreWorkflowHooks: []*valid.WorkflowHook{
|
|
&testHook,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
preWh.GlobalCfg = globalCfg
|
|
|
|
When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error"))
|
|
|
|
err := preWh.RunPreHooks(ctx)
|
|
|
|
Assert(t, err != nil, "error not nil")
|
|
preWhWorkingDir.VerifyWasCalled(Never()).Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)
|
|
whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(pCtx, testHook.RunCommand, repoDir)
|
|
})
|
|
|
|
t.Run("error cloning", func(t *testing.T) {
|
|
preWorkflowHooksSetup(t)
|
|
|
|
var unlockCalled = newBool(false)
|
|
unlockFn := func() {
|
|
unlockCalled = newBool(true)
|
|
}
|
|
|
|
globalCfg := valid.GlobalCfg{
|
|
Repos: []valid.Repo{
|
|
{
|
|
ID: fixtures.GithubRepo.ID(),
|
|
PreWorkflowHooks: []*valid.WorkflowHook{
|
|
&testHook,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
preWh.GlobalCfg = globalCfg
|
|
|
|
When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
|
|
When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, errors.New("some error"))
|
|
|
|
err := preWh.RunPreHooks(ctx)
|
|
|
|
Assert(t, err != nil, "error not nil")
|
|
|
|
whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(pCtx, testHook.RunCommand, repoDir)
|
|
Assert(t, *unlockCalled == true, "unlock function called")
|
|
})
|
|
|
|
t.Run("error running pre hook", func(t *testing.T) {
|
|
preWorkflowHooksSetup(t)
|
|
|
|
var unlockCalled = newBool(false)
|
|
unlockFn := func() {
|
|
unlockCalled = newBool(true)
|
|
}
|
|
|
|
globalCfg := valid.GlobalCfg{
|
|
Repos: []valid.Repo{
|
|
{
|
|
ID: fixtures.GithubRepo.ID(),
|
|
PreWorkflowHooks: []*valid.WorkflowHook{
|
|
&testHook,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
preWh.GlobalCfg = globalCfg
|
|
|
|
When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
|
|
When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil)
|
|
When(whPreWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, errors.New("some error"))
|
|
|
|
err := preWh.RunPreHooks(ctx)
|
|
|
|
Assert(t, err != nil, "error not nil")
|
|
Assert(t, *unlockCalled == true, "unlock function called")
|
|
})
|
|
}
|