Files
atlantis/server/events/command_requirement_handler_test.go
Ross Strickland 684f2fa7e0 feat(policies): Add granular policy_sets (#3086)
* Initial work.

* Periodic push.

* Fmt and start adding args to approve_policies cmd.

* keep funcs for now.

* Periodic push.

* Periodic push.

* fmt.

* Move approve policies logic to project_command_runner.

* update some tests

* More test fixes.

* update more tests. fix som logic.

* more tests. add additional info to common data for custom templates.

* fix apply with policies bug. update more tests/fmt

* file perms

* fix error parsing for conftest results.

* Update more tests and linting.

* update documentation.

* Address no-fail case. Address comments.

* Forgot changes.

* fix markdown renderer

* Fix policy fail logic. remove uneeded tmpl var

* targeted policy approvals fix

* Address PR comments.

* empty commit to trigger build

---------

Co-authored-by: PePe Amengual <jose.amengual@gmail.com>
Co-authored-by: rkstrickland <ross.strickland@instacart.com>
Co-authored-by: Dylan Page <dylan.page@autodesk.com>
2023-04-20 21:53:46 -04:00

294 lines
9.0 KiB
Go

package events_test
import (
"fmt"
"testing"
"github.com/runatlantis/atlantis/server/core/config/raw"
"github.com/runatlantis/atlantis/server/core/config/valid"
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/logging/mocks/matchers"
. "github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/events/command"
"github.com/runatlantis/atlantis/server/events/mocks"
"github.com/stretchr/testify/assert"
)
func TestAggregateApplyRequirements_ValidatePlanProject(t *testing.T) {
repoDir := "repoDir"
fullRequirements := []string{
raw.ApprovedRequirement,
valid.PoliciesPassedCommandReq,
raw.MergeableRequirement,
raw.UnDivergedRequirement,
}
tests := []struct {
name string
ctx command.ProjectContext
setup func(workingDir *mocks.MockWorkingDir)
wantFailure string
wantErr assert.ErrorAssertionFunc
}{
{
name: "pass no requirements",
ctx: command.ProjectContext{},
wantErr: assert.NoError,
},
{
name: "pass full requirements",
ctx: command.ProjectContext{
PlanRequirements: fullRequirements,
PullReqStatus: models.PullReqStatus{
ApprovalStatus: models.ApprovalStatus{IsApproved: true},
Mergeable: true,
},
ProjectPlanStatus: models.PassedPolicyCheckStatus,
},
setup: func(workingDir *mocks.MockWorkingDir) {
When(workingDir.HasDiverged(matchers.AnyLoggingSimpleLogging(), AnyString())).ThenReturn(false)
},
wantErr: assert.NoError,
},
{
name: "fail by no approved",
ctx: command.ProjectContext{
PlanRequirements: []string{raw.ApprovedRequirement},
PullReqStatus: models.PullReqStatus{
ApprovalStatus: models.ApprovalStatus{IsApproved: false},
},
},
wantFailure: "Pull request must be approved by at least one person other than the author before running plan.",
wantErr: assert.NoError,
},
{
name: "fail by no mergeable",
ctx: command.ProjectContext{
PlanRequirements: []string{raw.MergeableRequirement},
PullReqStatus: models.PullReqStatus{Mergeable: false},
},
wantFailure: "Pull request must be mergeable before running plan.",
wantErr: assert.NoError,
},
{
name: "fail by diverged",
ctx: command.ProjectContext{
PlanRequirements: []string{raw.UnDivergedRequirement},
},
setup: func(workingDir *mocks.MockWorkingDir) {
When(workingDir.HasDiverged(matchers.AnyLoggingSimpleLogging(), AnyString())).ThenReturn(true)
},
wantFailure: "Default branch must be rebased onto pull request before running plan.",
wantErr: assert.NoError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
RegisterMockTestingT(t)
workingDir := mocks.NewMockWorkingDir()
a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir}
if tt.setup != nil {
tt.setup(workingDir)
}
gotFailure, err := a.ValidatePlanProject(repoDir, tt.ctx)
if !tt.wantErr(t, err, fmt.Sprintf("ValidatePlanProject(%v, %v)", repoDir, tt.ctx)) {
return
}
assert.Equalf(t, tt.wantFailure, gotFailure, "ValidatePlanProject(%v, %v)", repoDir, tt.ctx)
})
}
}
func TestAggregateApplyRequirements_ValidateApplyProject(t *testing.T) {
repoDir := "repoDir"
fullRequirements := []string{
raw.ApprovedRequirement,
valid.PoliciesPassedCommandReq,
raw.MergeableRequirement,
raw.UnDivergedRequirement,
}
tests := []struct {
name string
ctx command.ProjectContext
setup func(workingDir *mocks.MockWorkingDir)
wantFailure string
wantErr assert.ErrorAssertionFunc
}{
{
name: "pass no requirements",
ctx: command.ProjectContext{},
wantErr: assert.NoError,
},
{
name: "pass full requirements",
ctx: command.ProjectContext{
ApplyRequirements: fullRequirements,
PullReqStatus: models.PullReqStatus{
ApprovalStatus: models.ApprovalStatus{IsApproved: true},
Mergeable: true,
},
ProjectPlanStatus: models.PassedPolicyCheckStatus,
},
setup: func(workingDir *mocks.MockWorkingDir) {
When(workingDir.HasDiverged(matchers.AnyLoggingSimpleLogging(), AnyString())).ThenReturn(false)
},
wantErr: assert.NoError,
},
{
name: "fail by no approved",
ctx: command.ProjectContext{
ApplyRequirements: []string{raw.ApprovedRequirement},
PullReqStatus: models.PullReqStatus{
ApprovalStatus: models.ApprovalStatus{IsApproved: false},
},
},
wantFailure: "Pull request must be approved by at least one person other than the author before running apply.",
wantErr: assert.NoError,
},
{
name: "fail by no policy passed",
ctx: command.ProjectContext{
ApplyRequirements: []string{valid.PoliciesPassedCommandReq},
ProjectPlanStatus: models.ErroredPolicyCheckStatus,
ProjectPolicyStatus: []models.PolicySetStatus{
{
PolicySetName: "policy1",
Passed: false,
Approvals: 0,
},
},
PolicySets: valid.PolicySets{
PolicySets: []valid.PolicySet{
{
Name: "policy1",
ApproveCount: 1,
},
},
},
},
wantFailure: "All policies must pass for project before running apply.",
wantErr: assert.NoError,
},
{
name: "fail by no mergeable",
ctx: command.ProjectContext{
ApplyRequirements: []string{raw.MergeableRequirement},
PullReqStatus: models.PullReqStatus{Mergeable: false},
},
wantFailure: "Pull request must be mergeable before running apply.",
wantErr: assert.NoError,
},
{
name: "fail by diverged",
ctx: command.ProjectContext{
ApplyRequirements: []string{raw.UnDivergedRequirement},
},
setup: func(workingDir *mocks.MockWorkingDir) {
When(workingDir.HasDiverged(matchers.AnyLoggingSimpleLogging(), AnyString())).ThenReturn(true)
},
wantFailure: "Default branch must be rebased onto pull request before running apply.",
wantErr: assert.NoError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
RegisterMockTestingT(t)
workingDir := mocks.NewMockWorkingDir()
a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir}
if tt.setup != nil {
tt.setup(workingDir)
}
gotFailure, err := a.ValidateApplyProject(repoDir, tt.ctx)
if !tt.wantErr(t, err, fmt.Sprintf("ValidateApplyProject(%v, %v)", repoDir, tt.ctx)) {
return
}
assert.Equalf(t, tt.wantFailure, gotFailure, "ValidateApplyProject(%v, %v)", repoDir, tt.ctx)
})
}
}
func TestAggregateApplyRequirements_ValidateImportProject(t *testing.T) {
repoDir := "repoDir"
fullRequirements := []string{
raw.ApprovedRequirement,
raw.MergeableRequirement,
raw.UnDivergedRequirement,
}
tests := []struct {
name string
ctx command.ProjectContext
setup func(workingDir *mocks.MockWorkingDir)
wantFailure string
wantErr assert.ErrorAssertionFunc
}{
{
name: "pass no requirements",
ctx: command.ProjectContext{},
wantErr: assert.NoError,
},
{
name: "pass full requirements",
ctx: command.ProjectContext{
ImportRequirements: fullRequirements,
PullReqStatus: models.PullReqStatus{
ApprovalStatus: models.ApprovalStatus{IsApproved: true},
Mergeable: true,
},
ProjectPlanStatus: models.PassedPolicyCheckStatus,
},
setup: func(workingDir *mocks.MockWorkingDir) {
When(workingDir.HasDiverged(matchers.AnyLoggingSimpleLogging(), AnyString())).ThenReturn(false)
},
wantErr: assert.NoError,
},
{
name: "fail by no approved",
ctx: command.ProjectContext{
ImportRequirements: []string{raw.ApprovedRequirement},
PullReqStatus: models.PullReqStatus{
ApprovalStatus: models.ApprovalStatus{IsApproved: false},
},
},
wantFailure: "Pull request must be approved by at least one person other than the author before running import.",
wantErr: assert.NoError,
},
{
name: "fail by no mergeable",
ctx: command.ProjectContext{
ImportRequirements: []string{raw.MergeableRequirement},
PullReqStatus: models.PullReqStatus{Mergeable: false},
},
wantFailure: "Pull request must be mergeable before running import.",
wantErr: assert.NoError,
},
{
name: "fail by diverged",
ctx: command.ProjectContext{
ImportRequirements: []string{raw.UnDivergedRequirement},
},
setup: func(workingDir *mocks.MockWorkingDir) {
When(workingDir.HasDiverged(matchers.AnyLoggingSimpleLogging(), AnyString())).ThenReturn(true)
},
wantFailure: "Default branch must be rebased onto pull request before running import.",
wantErr: assert.NoError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
RegisterMockTestingT(t)
workingDir := mocks.NewMockWorkingDir()
a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir}
if tt.setup != nil {
tt.setup(workingDir)
}
gotFailure, err := a.ValidateImportProject(repoDir, tt.ctx)
if !tt.wantErr(t, err, fmt.Sprintf("ValidateImportProject(%v, %v)", repoDir, tt.ctx)) {
return
}
assert.Equalf(t, tt.wantFailure, gotFailure, "ValidateImportProject(%v, %v)", repoDir, tt.ctx)
})
}
}