Skip to content

Commit

Permalink
Add tests for TF Distribution and fix styles
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Borg <[email protected]>
  • Loading branch information
abborg committed Dec 20, 2024
1 parent 5bbf855 commit 4aed6c9
Show file tree
Hide file tree
Showing 16 changed files with 655 additions and 59 deletions.
31 changes: 15 additions & 16 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,22 +142,21 @@ const (
SSLCertFileFlag = "ssl-cert-file"
SSLKeyFileFlag = "ssl-key-file"
RestrictFileList = "restrict-file-list"
// TFDistributionFlag is deprecated for DefaultTFDistributionFlag
TFDistributionFlag = "tf-distribution"
TFDownloadFlag = "tf-download"
TFDownloadURLFlag = "tf-download-url"
UseTFPluginCache = "use-tf-plugin-cache"
VarFileAllowlistFlag = "var-file-allowlist"
VCSStatusName = "vcs-status-name"
IgnoreVCSStatusNames = "ignore-vcs-status-names"
TFEHostnameFlag = "tfe-hostname"
TFELocalExecutionModeFlag = "tfe-local-execution-mode"
TFETokenFlag = "tfe-token"
WriteGitCredsFlag = "write-git-creds" // nolint: gosec
WebBasicAuthFlag = "web-basic-auth"
WebUsernameFlag = "web-username"
WebPasswordFlag = "web-password"
WebsocketCheckOrigin = "websocket-check-origin"
TFDistributionFlag = "tf-distribution" // deprecated for DefaultTFDistributionFlag
TFDownloadFlag = "tf-download"
TFDownloadURLFlag = "tf-download-url"
UseTFPluginCache = "use-tf-plugin-cache"
VarFileAllowlistFlag = "var-file-allowlist"
VCSStatusName = "vcs-status-name"
IgnoreVCSStatusNames = "ignore-vcs-status-names"
TFEHostnameFlag = "tfe-hostname"
TFELocalExecutionModeFlag = "tfe-local-execution-mode"
TFETokenFlag = "tfe-token"
WriteGitCredsFlag = "write-git-creds" // nolint: gosec
WebBasicAuthFlag = "web-basic-auth"
WebUsernameFlag = "web-username"
WebPasswordFlag = "web-password"
WebsocketCheckOrigin = "websocket-check-origin"

// NOTE: Must manually set these as defaults in the setDefaults function.
DefaultADBasicUser = ""
Expand Down
40 changes: 40 additions & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,46 @@ func TestExecute_AutoplanFileList(t *testing.T) {
}
}

func TestExecute_ValidateDefaultTFDistribution(t *testing.T) {
cases := []struct {
description string
flags map[string]interface{}
expectErr string
}{
{
"terraform",
map[string]interface{}{
DefaultTFDistributionFlag: "terraform",
},
"",
},
{
"opentofu",
map[string]interface{}{
DefaultTFDistributionFlag: "opentofu",
},
"",
},
{
"errs on invalid distribution",
map[string]interface{}{
DefaultTFDistributionFlag: "invalid_distribution",
},
"invalid tf distribution: expected one of terraform or opentofu",
},
}
for _, testCase := range cases {
t.Log("Should validate default tf distribution when " + testCase.description)
c := setupWithDefaults(testCase.flags, t)
err := c.Execute()
if testCase.expectErr != "" {
ErrEquals(t, testCase.expectErr, err)
} else {
Ok(t, err)
}
}
}

func setup(flags map[string]interface{}, t *testing.T) *cobra.Command {
vipr := viper.New()
for k, v := range flags {
Expand Down
1 change: 1 addition & 0 deletions server/controllers/events/events_controller_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion),
RunStepRunner: &runtime.RunStepRunner{
TerraformExecutor: terraformClient,
DefaultTFDistribution: defaultTFDistribution,
DefaultTFVersion: defaultTFVersion,
ProjectCmdOutputHandler: projectCmdOutputHandler,
},
Expand Down
2 changes: 1 addition & 1 deletion server/core/config/raw/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func validImportReq(value interface{}) error {
func validDistribution(value interface{}) error {
distribution := value.(*string)
if distribution != nil && *distribution != "terraform" && *distribution != "opentofu" {
return fmt.Errorf("%q is not a valid terraform_distribution, only %q and %q are supported", *distribution, "terraform", "opentofu")
return fmt.Errorf("'%s' is not a valid terraform_distribution, only '%s' and '%s' are supported", *distribution, "terraform", "opentofu")
}
return nil
}
38 changes: 37 additions & 1 deletion server/core/runtime/apply_step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func TestRun_AppliesCorrectProjectPlan(t *testing.T) {
Assert(t, os.IsNotExist(err), "planfile should be deleted")
}

func TestRun_UsesConfiguredTFVersion(t *testing.T) {
func TestApplyStepRunner_TestRun_UsesConfiguredTFVersion(t *testing.T) {
tmpDir := t.TempDir()
planPath := filepath.Join(tmpDir, "workspace.tfplan")
err := os.WriteFile(planPath, nil, 0600)
Expand Down Expand Up @@ -147,6 +147,42 @@ func TestRun_UsesConfiguredTFVersion(t *testing.T) {
Assert(t, os.IsNotExist(err), "planfile should be deleted")
}

func TestApplyStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) {
tmpDir := t.TempDir()
planPath := filepath.Join(tmpDir, "workspace.tfplan")
err := os.WriteFile(planPath, nil, 0600)
Ok(t, err)

logger := logging.NewNoopLogger(t)
mockDownloader := mocks.NewMockDownloader()
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
tfVersion, _ := version.NewVersion("0.11.0")
projTFDistribution := "opentofu"
ctx := command.ProjectContext{
Workspace: "workspace",
RepoRelDir: ".",
EscapedCommentArgs: []string{"comment", "args"},
TerraformDistribution: &projTFDistribution,
Log: logger,
}

RegisterMockTestingT(t)
terraform := tfclientmocks.NewMockClient()
o := runtime.ApplyStepRunner{
TerraformExecutor: terraform,
DefaultTFDistribution: tfDistribution,
DefaultTFVersion: tfVersion,
}
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), NotEq[tf.Distribution](tfDistribution), Any[*version.Version](), Any[string]())).
ThenReturn("output", nil)
output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
Ok(t, err)
Equals(t, "output", output)
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq(tmpDir), Eq([]string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}), Eq(map[string]string(nil)), NotEq[tf.Distribution](tfDistribution), Eq(tfVersion), Eq("workspace"))
_, err = os.Stat(planPath)
Assert(t, os.IsNotExist(err), "planfile should be deleted")
}

// Apply ignores the -target flag when used with a planfile so we should give
// an error if it's being used with -target.
func TestRun_UsingTarget(t *testing.T) {
Expand Down
41 changes: 41 additions & 0 deletions server/core/runtime/import_step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,44 @@ func TestImportStepRunner_Run_Workspace(t *testing.T) {
_, err = os.Stat(planPath)
Assert(t, os.IsNotExist(err), "planfile should be deleted")
}

func TestImportStepRunner_Run_UsesConfiguredDistribution(t *testing.T) {
logger := logging.NewNoopLogger(t)
workspace := "something"
tmpDir := t.TempDir()
planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace))
err := os.WriteFile(planPath, nil, 0600)
Ok(t, err)

projTFDistribution := "opentofu"
context := command.ProjectContext{
Log: logger,
EscapedCommentArgs: []string{"-var", "foo=bar", "addr", "id"},
Workspace: workspace,
TerraformDistribution: &projTFDistribution,
}

RegisterMockTestingT(t)
terraform := tfclientmocks.NewMockClient()
tfVersion, _ := version.NewVersion("0.15.0")
mockDownloader := mocks.NewMockDownloader()
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
s := NewImportStepRunner(terraform, tfDistribution, tfVersion)

When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
ThenReturn("output", nil)
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
Ok(t, err)
Equals(t, "output", output)

// switch workspace
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "show"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "select", workspace}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))

// exec import
commands := []string{"import", "-var", "foo=bar", "addr", "id"}
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq(commands), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))

_, err = os.Stat(planPath)
Assert(t, os.IsNotExist(err), "planfile should be deleted")
}
67 changes: 67 additions & 0 deletions server/core/runtime/init_step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,73 @@ func TestRun_UsesGetOrInitForRightVersion(t *testing.T) {
}
}

func TestInitStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) {
RegisterMockTestingT(t)
mockDownloader := mocks.NewMockDownloader()
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
cases := []struct {
version string
distribution string
expCmd string
}{
{
"0.8.9",
"opentofu",
"get",
},
{
"0.8.9",
"terraform",
"get",
},
{
"0.9.0",
"opentofu",
"init",
},
{
"0.9.1",
"terraform",
"init",
},
}

for _, c := range cases {
t.Run(c.version, func(t *testing.T) {
terraform := tfclientmocks.NewMockClient()

logger := logging.NewNoopLogger(t)
ctx := command.ProjectContext{
Workspace: "workspace",
RepoRelDir: ".",
Log: logger,
TerraformDistribution: &c.distribution,
}

tfVersion, _ := version.NewVersion(c.version)
iso := runtime.InitStepRunner{
TerraformExecutor: terraform,
DefaultTFDistribution: tfDistribution,
DefaultTFVersion: tfVersion,
}
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
ThenReturn("output", nil)

output, err := iso.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
Ok(t, err)
// When there is no error, should not return init output to PR.
Equals(t, "", output)

// If using init then we specify -input=false but not for get.
expArgs := []string{c.expCmd, "-input=false", "-upgrade", "extra", "args"}
if c.expCmd == "get" {
expArgs = []string{c.expCmd, "-upgrade", "extra", "args"}
}
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq("/path"), Eq(expArgs), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("workspace"))
})
}
}

func TestRun_ShowInitOutputOnError(t *testing.T) {
// If there was an error during init then we want the output to be returned.
RegisterMockTestingT(t)
Expand Down
76 changes: 76 additions & 0 deletions server/core/runtime/plan_step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,82 @@ Plan: 0 to add, 0 to change, 1 to destroy.`, output)
}
}

func TestPlanStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) {
RegisterMockTestingT(t)

expPlanArgs := []string{
"plan",
"-input=false",
"-refresh",
"-out",
fmt.Sprintf("%q", "/path/default.tfplan"),
"extra",
"args",
"comment",
"args",
}

cases := []struct {
name string
tfVersion string
tfDistribution string
}{
{
"stable version",
"0.12.0",
"terraform",
},
{
"with prerelease",
"0.14.0-rc1",
"opentofu",
},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
terraform := tfclientmocks.NewMockClient()
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
When(terraform.RunCommandWithVersion(
Any[command.ProjectContext](),
Any[string](),
Any[[]string](),
Any[map[string]string](),
Any[tf.Distribution](),
Any[*version.Version](),
Any[string]())).ThenReturn("output", nil)

mockDownloader := mocks.NewMockDownloader()
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
tfVersion, _ := version.NewVersion(c.tfVersion)
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
ctx := command.ProjectContext{
Workspace: "default",
RepoRelDir: ".",
User: models.User{Username: "username"},
EscapedCommentArgs: []string{"comment", "args"},
Pull: models.PullRequest{
Num: 2,
},
BaseRepo: models.Repo{
FullName: "owner/repo",
Owner: "owner",
Name: "repo",
},
TerraformDistribution: &c.tfDistribution,
}

output, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
Ok(t, err)
Equals(t, "output", output)

terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq("/path"), Eq(expPlanArgs), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("default"))
})
}

}

type remotePlanMock struct {
// LinesToSend will be sent on the channel.
LinesToSend string
Expand Down
Loading

0 comments on commit 4aed6c9

Please sign in to comment.