mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 14:58:19 +00:00
419 lines
12 KiB
Go
419 lines
12 KiB
Go
package events_test
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
. "github.com/petergtz/pegomock/v4"
|
|
"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"
|
|
|
|
"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(Any[logging.SimpleLogging](), Any[string]())).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 according to the project's approval rules 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(Any[logging.SimpleLogging](), Any[string]())).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(Any[logging.SimpleLogging](), Any[string]())).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 according to the project's approval rules 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(Any[logging.SimpleLogging](), Any[string]())).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 TestRequirements_ValidateProjectDependencies(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ctx command.ProjectContext
|
|
setup func(workingDir *mocks.MockWorkingDir)
|
|
wantFailure string
|
|
wantErr assert.ErrorAssertionFunc
|
|
}{
|
|
{
|
|
name: "pass no dependencies",
|
|
ctx: command.ProjectContext{},
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "pass all dependencies applied",
|
|
ctx: command.ProjectContext{
|
|
DependsOn: []string{"project1"},
|
|
PullStatus: &models.PullStatus{
|
|
Projects: []models.ProjectStatus{
|
|
{
|
|
ProjectName: "project1",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "Fail all dependencies are not applied",
|
|
ctx: command.ProjectContext{
|
|
DependsOn: []string{"project1", "project2"},
|
|
PullStatus: &models.PullStatus{
|
|
Projects: []models.ProjectStatus{
|
|
{
|
|
ProjectName: "project1",
|
|
Status: models.PlannedPlanStatus,
|
|
},
|
|
{
|
|
ProjectName: "project2",
|
|
Status: models.ErroredApplyStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantFailure: "Can't apply your project unless you apply its dependencies: [project1]",
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "Fail one of dependencies is not applied",
|
|
ctx: command.ProjectContext{
|
|
DependsOn: []string{"project1", "project2"},
|
|
PullStatus: &models.PullStatus{
|
|
Projects: []models.ProjectStatus{
|
|
{
|
|
ProjectName: "project1",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
{
|
|
ProjectName: "project2",
|
|
Status: models.ErroredApplyStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantFailure: "Can't apply your project unless you apply its dependencies: [project2]",
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "Should not fail if one of dependencies is not applied but it has no changes to apply",
|
|
ctx: command.ProjectContext{
|
|
DependsOn: []string{"project1", "project2"},
|
|
PullStatus: &models.PullStatus{
|
|
Projects: []models.ProjectStatus{
|
|
{
|
|
ProjectName: "project1",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
{
|
|
ProjectName: "project2",
|
|
Status: models.PlannedNoChangesPlanStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "In the case of more than one dependency, should not continue to check dependencies if one of them is not in applied status",
|
|
ctx: command.ProjectContext{
|
|
DependsOn: []string{"project1", "project2"},
|
|
PullStatus: &models.PullStatus{
|
|
Projects: []models.ProjectStatus{
|
|
{
|
|
ProjectName: "project1",
|
|
Status: models.AppliedPlanStatus,
|
|
},
|
|
{
|
|
ProjectName: "project2",
|
|
Status: models.ErroredApplyStatus,
|
|
},
|
|
{
|
|
ProjectName: "project3",
|
|
Status: models.PlannedPlanStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantFailure: "Can't apply your project unless you apply its dependencies: [project2]",
|
|
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}
|
|
gotFailure, err := a.ValidateProjectDependencies(tt.ctx)
|
|
if !tt.wantErr(t, err, fmt.Sprintf("ValidateProjectDependencies(%v)", tt.ctx)) {
|
|
return
|
|
}
|
|
assert.Equalf(t, tt.wantFailure, gotFailure, "ValidateProjectDependencies(%v)", 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(Any[logging.SimpleLogging](), Any[string]())).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 according to the project's approval rules 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(Any[logging.SimpleLogging](), Any[string]())).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)
|
|
})
|
|
}
|
|
}
|