| package cloud |
| |
| import ( |
| "context" |
| "errors" |
| "strings" |
| "testing" |
| |
| "github.com/golang/mock/gomock" |
| "github.com/hashicorp/go-tfe" |
| tfemocks "github.com/hashicorp/go-tfe/mocks" |
| ) |
| |
| func MockAllTaskStages(t *testing.T, client *tfe.Client) (RunID string) { |
| ctrl := gomock.NewController(t) |
| |
| RunID = "run-all_task_stages" |
| |
| mockRunsAPI := tfemocks.NewMockRuns(ctrl) |
| |
| goodRun := tfe.Run{ |
| TaskStages: []*tfe.TaskStage{ |
| { |
| Stage: tfe.PrePlan, |
| }, |
| { |
| Stage: tfe.PostPlan, |
| }, |
| { |
| Stage: tfe.PreApply, |
| }, |
| }, |
| } |
| mockRunsAPI. |
| EXPECT(). |
| ReadWithOptions(gomock.Any(), RunID, gomock.Any()). |
| Return(&goodRun, nil). |
| AnyTimes() |
| |
| // Mock a bad Read response |
| mockRunsAPI. |
| EXPECT(). |
| ReadWithOptions(gomock.Any(), gomock.Any(), gomock.Any()). |
| Return(nil, tfe.ErrInvalidOrg). |
| AnyTimes() |
| |
| // Wire up the mock interfaces |
| client.Runs = mockRunsAPI |
| return |
| } |
| |
| func MockPrePlanTaskStage(t *testing.T, client *tfe.Client) (RunID string) { |
| ctrl := gomock.NewController(t) |
| |
| RunID = "run-pre_plan_task_stage" |
| |
| mockRunsAPI := tfemocks.NewMockRuns(ctrl) |
| |
| goodRun := tfe.Run{ |
| TaskStages: []*tfe.TaskStage{ |
| { |
| Stage: tfe.PrePlan, |
| }, |
| }, |
| } |
| mockRunsAPI. |
| EXPECT(). |
| ReadWithOptions(gomock.Any(), RunID, gomock.Any()). |
| Return(&goodRun, nil). |
| AnyTimes() |
| |
| // Mock a bad Read response |
| mockRunsAPI. |
| EXPECT(). |
| ReadWithOptions(gomock.Any(), gomock.Any(), gomock.Any()). |
| Return(nil, tfe.ErrInvalidOrg). |
| AnyTimes() |
| |
| // Wire up the mock interfaces |
| client.Runs = mockRunsAPI |
| return |
| } |
| |
| func MockTaskStageUnsupported(t *testing.T, client *tfe.Client) (RunID string) { |
| ctrl := gomock.NewController(t) |
| |
| RunID = "run-unsupported_task_stage" |
| |
| mockRunsAPI := tfemocks.NewMockRuns(ctrl) |
| |
| mockRunsAPI. |
| EXPECT(). |
| ReadWithOptions(gomock.Any(), RunID, gomock.Any()). |
| Return(nil, errors.New("Invalid include parameter")). |
| AnyTimes() |
| |
| mockRunsAPI. |
| EXPECT(). |
| ReadWithOptions(gomock.Any(), gomock.Any(), gomock.Any()). |
| Return(nil, tfe.ErrInvalidOrg). |
| AnyTimes() |
| |
| client.Runs = mockRunsAPI |
| return |
| } |
| |
| func TestTaskStagesWithAllStages(t *testing.T) { |
| b, bCleanup := testBackendWithName(t) |
| defer bCleanup() |
| |
| config := &tfe.Config{ |
| Token: "not-a-token", |
| } |
| client, _ := tfe.NewClient(config) |
| runID := MockAllTaskStages(t, client) |
| |
| ctx := context.TODO() |
| taskStages, err := b.runTaskStages(ctx, client, runID) |
| |
| if err != nil { |
| t.Fatalf("Expected to not error but received %s", err) |
| } |
| |
| for _, stageName := range []tfe.Stage{ |
| tfe.PrePlan, |
| tfe.PostPlan, |
| tfe.PreApply, |
| } { |
| if stage, ok := taskStages[stageName]; ok { |
| if stage.Stage != stageName { |
| t.Errorf("Expected task stage indexed by %s to find a Task Stage with the same index, but receieved %s", stageName, stage.Stage) |
| } |
| } else { |
| t.Errorf("Expected task stage indexed by %s to exist, but it did not", stageName) |
| } |
| } |
| } |
| |
| func TestTaskStagesWithOneStage(t *testing.T) { |
| b, bCleanup := testBackendWithName(t) |
| defer bCleanup() |
| |
| config := &tfe.Config{ |
| Token: "not-a-token", |
| } |
| client, _ := tfe.NewClient(config) |
| runID := MockPrePlanTaskStage(t, client) |
| |
| ctx := context.TODO() |
| taskStages, err := b.runTaskStages(ctx, client, runID) |
| |
| if err != nil { |
| t.Fatalf("Expected to not error but received %s", err) |
| } |
| |
| if _, ok := taskStages[tfe.PrePlan]; !ok { |
| t.Errorf("Expected task stage indexed by %s to exist, but it did not", tfe.PrePlan) |
| } |
| |
| for _, stageName := range []tfe.Stage{ |
| tfe.PostPlan, |
| tfe.PreApply, |
| } { |
| if _, ok := taskStages[stageName]; ok { |
| t.Errorf("Expected task stage indexed by %s to not exist, but it did", stageName) |
| } |
| } |
| } |
| |
| func TestTaskStagesWithOldTFC(t *testing.T) { |
| b, bCleanup := testBackendWithName(t) |
| defer bCleanup() |
| |
| config := &tfe.Config{ |
| Token: "not-a-token", |
| } |
| client, _ := tfe.NewClient(config) |
| runID := MockTaskStageUnsupported(t, client) |
| |
| ctx := context.TODO() |
| taskStages, err := b.runTaskStages(ctx, client, runID) |
| |
| if err != nil { |
| t.Fatalf("Expected to not error but received %s", err) |
| } |
| |
| if len(taskStages) != 0 { |
| t.Errorf("Expected task stage to be empty, but found %d stages", len(taskStages)) |
| } |
| } |
| |
| func TestTaskStagesWithErrors(t *testing.T) { |
| b, bCleanup := testBackendWithName(t) |
| defer bCleanup() |
| |
| config := &tfe.Config{ |
| Token: "not-a-token", |
| } |
| client, _ := tfe.NewClient(config) |
| MockTaskStageUnsupported(t, client) |
| |
| ctx := context.TODO() |
| _, err := b.runTaskStages(ctx, client, "this run ID will not exist is invalid anyway") |
| |
| if err == nil { |
| t.Error("Expected to error but did not") |
| } |
| } |
| |
| func TestTaskStageOverride(t *testing.T) { |
| b, bCleanup := testBackendWithName(t) |
| defer bCleanup() |
| |
| integrationContext, writer := newMockIntegrationContext(b, t) |
| |
| integrationContext.Op.UIOut = b.CLI |
| |
| cases := map[string]struct { |
| taskStageID string |
| isError bool |
| errMsg string |
| input *mockInput |
| cont bool |
| }{ |
| "override-pass": { |
| taskStageID: "ts-pass", |
| isError: false, |
| input: testInput(t, map[string]string{ |
| "→→ [bold]Override": "override", |
| }), |
| errMsg: "", |
| cont: true, |
| }, |
| "override-fail": { |
| taskStageID: "ts-err", |
| isError: true, |
| input: testInput(t, map[string]string{ |
| "→→ [bold]Override": "override", |
| }), |
| errMsg: "", |
| cont: false, |
| }, |
| "skip-override": { |
| taskStageID: "ts-err", |
| isError: true, |
| errMsg: "Failed to override: Apply discarded.", |
| input: testInput(t, map[string]string{ |
| "→→ [bold]Override": "no", |
| }), |
| cont: false, |
| }, |
| } |
| for _, c := range cases { |
| integrationContext.Op.UIIn = c.input |
| cont, err := b.processStageOverrides(integrationContext, writer, c.taskStageID) |
| if c.isError { |
| if err == nil { |
| t.Fatalf("Expected to fail with some error") |
| } |
| if c.errMsg != "" { |
| if !strings.Contains(err.Error(), c.errMsg) { |
| t.Fatalf("Expected: %s, got: %s", c.errMsg, err.Error()) |
| } |
| } |
| |
| } else { |
| if err != nil { |
| t.Fatalf("Expected to pass, got err: %s", err) |
| } |
| } |
| if c.cont != cont { |
| t.Fatalf("expected polling continue: %t, got: %t", c.cont, cont) |
| } |
| } |
| } |