Files
atlantis/server/events/project_pre_execute_test.go

270 lines
10 KiB
Go

package events_test
import (
"errors"
"testing"
"github.com/hashicorp/go-version"
"github.com/hootsuite/atlantis/server/events"
"github.com/hootsuite/atlantis/server/events/locking"
lmocks "github.com/hootsuite/atlantis/server/events/locking/mocks"
"github.com/hootsuite/atlantis/server/events/mocks"
"github.com/hootsuite/atlantis/server/events/models"
rmocks "github.com/hootsuite/atlantis/server/events/run/mocks"
tmocks "github.com/hootsuite/atlantis/server/events/terraform/mocks"
"github.com/hootsuite/atlantis/server/logging"
. "github.com/hootsuite/atlantis/testing"
"github.com/mohae/deepcopy"
. "github.com/petergtz/pegomock"
)
var ctx = events.CommandContext{
Command: &events.Command{
Name: events.Plan,
},
Log: logging.NewNoopLogger(),
}
var project = models.Project{}
func TestExecute_LockErr(t *testing.T) {
t.Log("when there is an error returned from TryLock we return it")
p, l, _, _ := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{}, errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "acquiring lock: err", res.ProjectResult.Error.Error())
}
func TestExecute_LockFailed(t *testing.T) {
t.Log("when we can't acquire a lock for this project and the lock is owned by a different pull, we get an error")
p, l, _, _ := setupPreExecuteTest(t)
// The response has LockAcquired: false and the pull request is a number
// different than the current pull.
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: false,
CurrLock: models.ProjectLock{Pull: models.PullRequest{Num: ctx.Pull.Num + 1}},
}, nil)
res := p.Execute(&ctx, "", project)
Equals(t, "This project is currently locked by #1. The locking plan must be applied or discarded before future plans can execute.", res.ProjectResult.Failure)
}
func TestExecute_ConfigErr(t *testing.T) {
t.Log("when there is an error loading config, we return it")
p, l, _, _ := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: true,
}, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
When(p.ConfigReader.Read("")).ThenReturn(events.ProjectConfig{}, errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "err", res.ProjectResult.Error.Error())
}
func TestExecute_PreInitErr(t *testing.T) {
t.Log("when the project is on tf >= 0.9 and we run a `pre_init` that returns an error we return it")
p, l, tm, r := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: true,
}, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
When(p.ConfigReader.Read("")).ThenReturn(events.ProjectConfig{
PreInit: []string{"pre-init"},
}, nil)
tfVersion, _ := version.NewVersion("0.9.0")
When(tm.Version()).ThenReturn(tfVersion)
When(r.Execute(ctx.Log, []string{"pre-init"}, "", "", tfVersion, "pre_init")).ThenReturn("", errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "running pre_init commands: err", res.ProjectResult.Error.Error())
}
func TestExecute_InitErr(t *testing.T) {
t.Log("when the project is on tf >= 0.9 and we run `init` that returns an error we return it")
p, l, tm, _ := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: true,
}, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
When(p.ConfigReader.Read("")).ThenReturn(events.ProjectConfig{}, nil)
tfVersion, _ := version.NewVersion("0.9.0")
When(tm.Version()).ThenReturn(tfVersion)
When(tm.RunInitAndEnv(ctx.Log, "", "", nil, tfVersion)).ThenReturn(nil, errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "err", res.ProjectResult.Error.Error())
}
func TestExecute_PreGetErr(t *testing.T) {
t.Log("when the project is on tf < 0.9 and we run a `pre_get` that returns an error we return it")
p, l, tm, r := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: true,
}, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
When(p.ConfigReader.Read("")).ThenReturn(events.ProjectConfig{
PreGet: []string{"pre-get"},
}, nil)
tfVersion, _ := version.NewVersion("0.8")
When(tm.Version()).ThenReturn(tfVersion)
When(r.Execute(ctx.Log, []string{"pre-get"}, "", "", tfVersion, "pre_get")).ThenReturn("", errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "running pre_get commands: err", res.ProjectResult.Error.Error())
}
func TestExecute_GetErr(t *testing.T) {
t.Log("when the project is on tf < 0.9 and we run `get` that returns an error we return it")
p, l, tm, _ := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: true,
}, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
When(p.ConfigReader.Read("")).ThenReturn(events.ProjectConfig{}, nil)
tfVersion, _ := version.NewVersion("0.8")
When(tm.Version()).ThenReturn(tfVersion)
When(tm.RunCommandWithVersion(ctx.Log, "", []string{"get", "-no-color"}, tfVersion, "")).ThenReturn("", errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "err", res.ProjectResult.Error.Error())
}
func TestExecute_PreCommandErr(t *testing.T) {
t.Log("when we get an error running pre commands we return it")
p, l, tm, r := setupPreExecuteTest(t)
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(locking.TryLockResponse{
LockAcquired: true,
}, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
When(p.ConfigReader.Read("")).ThenReturn(events.ProjectConfig{
PrePlan: []string{"command"},
}, nil)
tfVersion, _ := version.NewVersion("0.9")
When(tm.Version()).ThenReturn(tfVersion)
When(tm.RunInitAndEnv(ctx.Log, "", "", nil, tfVersion)).ThenReturn(nil, nil)
When(r.Execute(ctx.Log, []string{"command"}, "", "", tfVersion, "pre_plan")).ThenReturn("", errors.New("err"))
res := p.Execute(&ctx, "", project)
Equals(t, "running pre_plan commands: err", res.ProjectResult.Error.Error())
}
func TestExecute_SuccessTF9(t *testing.T) {
t.Log("when the project is on tf >= 0.9 it should be successful")
p, l, tm, r := setupPreExecuteTest(t)
lockResponse := locking.TryLockResponse{
LockAcquired: true,
}
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(lockResponse, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
config := events.ProjectConfig{
PreInit: []string{"pre-init"},
}
When(p.ConfigReader.Read("")).ThenReturn(config, nil)
tfVersion, _ := version.NewVersion("0.9")
When(tm.Version()).ThenReturn(tfVersion)
When(tm.RunInitAndEnv(ctx.Log, "", "", nil, tfVersion)).ThenReturn(nil, nil)
res := p.Execute(&ctx, "", project)
Equals(t, events.PreExecuteResult{
ProjectConfig: config,
TerraformVersion: tfVersion,
LockResponse: lockResponse,
}, res)
tm.VerifyWasCalledOnce().RunInitAndEnv(ctx.Log, "", "", nil, tfVersion)
r.VerifyWasCalledOnce().Execute(ctx.Log, []string{"pre-init"}, "", "", tfVersion, "pre_init")
}
func TestExecute_SuccessTF8(t *testing.T) {
t.Log("when the project is on tf < 0.9 it should be successful")
p, l, tm, r := setupPreExecuteTest(t)
lockResponse := locking.TryLockResponse{
LockAcquired: true,
}
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(lockResponse, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
config := events.ProjectConfig{
PreGet: []string{"pre-get"},
}
When(p.ConfigReader.Read("")).ThenReturn(config, nil)
tfVersion, _ := version.NewVersion("0.8")
When(tm.Version()).ThenReturn(tfVersion)
res := p.Execute(&ctx, "", project)
Equals(t, events.PreExecuteResult{
ProjectConfig: config,
TerraformVersion: tfVersion,
LockResponse: lockResponse,
}, res)
tm.VerifyWasCalledOnce().RunCommandWithVersion(ctx.Log, "", []string{"get", "-no-color"}, tfVersion, "")
r.VerifyWasCalledOnce().Execute(ctx.Log, []string{"pre-get"}, "", "", tfVersion, "pre_get")
}
func TestExecute_SuccessPrePlan(t *testing.T) {
t.Log("when there are pre_plan commands they are run")
p, l, tm, r := setupPreExecuteTest(t)
lockResponse := locking.TryLockResponse{
LockAcquired: true,
}
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(lockResponse, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
config := events.ProjectConfig{
PrePlan: []string{"command"},
}
When(p.ConfigReader.Read("")).ThenReturn(config, nil)
tfVersion, _ := version.NewVersion("0.9")
When(tm.Version()).ThenReturn(tfVersion)
res := p.Execute(&ctx, "", project)
Equals(t, events.PreExecuteResult{
ProjectConfig: config,
TerraformVersion: tfVersion,
LockResponse: lockResponse,
}, res)
r.VerifyWasCalledOnce().Execute(ctx.Log, []string{"command"}, "", "", tfVersion, "pre_plan")
}
func TestExecute_SuccessPreApply(t *testing.T) {
t.Log("when there are pre_apply commands they are run")
p, l, tm, r := setupPreExecuteTest(t)
lockResponse := locking.TryLockResponse{
LockAcquired: true,
}
When(l.TryLock(project, "", ctx.Pull, ctx.User)).ThenReturn(lockResponse, nil)
When(p.ConfigReader.Exists("")).ThenReturn(true)
config := events.ProjectConfig{
PreApply: []string{"command"},
}
When(p.ConfigReader.Read("")).ThenReturn(config, nil)
tfVersion, _ := version.NewVersion("0.9")
When(tm.Version()).ThenReturn(tfVersion)
cpCtx := deepcopy.Copy(ctx).(events.CommandContext)
cpCtx.Command = &events.Command{
Name: events.Apply,
}
cpCtx.Log = logging.NewNoopLogger()
res := p.Execute(&cpCtx, "", project)
Equals(t, events.PreExecuteResult{
ProjectConfig: config,
TerraformVersion: tfVersion,
LockResponse: lockResponse,
}, res)
r.VerifyWasCalledOnce().Execute(cpCtx.Log, []string{"command"}, "", "", tfVersion, "pre_apply")
}
func setupPreExecuteTest(t *testing.T) (*events.DefaultProjectPreExecutor, *lmocks.MockLocker, *tmocks.MockRunner, *rmocks.MockRunner) {
RegisterMockTestingT(t)
l := lmocks.NewMockLocker()
cr := mocks.NewMockProjectConfigReader()
tm := tmocks.NewMockRunner()
r := rmocks.NewMockRunner()
return &events.DefaultProjectPreExecutor{
Locker: l,
ConfigReader: cr,
Terraform: tm,
Run: r,
}, l, tm, r
}