Merge pull request #30850 from hashicorp/brandonc/cloud_test_revisions

test(cloud): ensure mocks are used for backend configure tests
This commit is contained in:
Brandon Croft 2022-04-14 09:31:49 -06:00 committed by GitHub
commit 42da030090
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 155 additions and 49 deletions

View File

@ -253,30 +253,32 @@ func (b *Cloud) Configure(obj cty.Value) tfdiags.Diagnostics {
return diags
}
cfg := &tfe.Config{
Address: service.String(),
BasePath: service.Path,
Token: token,
Headers: make(http.Header),
RetryLogHook: b.retryLogHook,
}
if b.client == nil {
cfg := &tfe.Config{
Address: service.String(),
BasePath: service.Path,
Token: token,
Headers: make(http.Header),
RetryLogHook: b.retryLogHook,
}
// Set the version header to the current version.
cfg.Headers.Set(tfversion.Header, tfversion.Version)
cfg.Headers.Set(headerSourceKey, headerSourceValue)
// Set the version header to the current version.
cfg.Headers.Set(tfversion.Header, tfversion.Version)
cfg.Headers.Set(headerSourceKey, headerSourceValue)
// Create the TFC/E API client.
b.client, err = tfe.NewClient(cfg)
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Failed to create the Terraform Cloud/Enterprise client",
fmt.Sprintf(
`Encountered an unexpected error while creating the `+
`Terraform Cloud/Enterprise client: %s.`, err,
),
))
return diags
// Create the TFC/E API client.
b.client, err = tfe.NewClient(cfg)
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Failed to create the Terraform Cloud/Enterprise client",
fmt.Sprintf(
`Encountered an unexpected error while creating the `+
`Terraform Cloud/Enterprise client: %s.`, err,
),
))
return diags
}
}
// Check if the organization exists by reading its entitlements.
@ -383,7 +385,7 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics {
var tags []string
err := gocty.FromCtyValue(val, &tags)
if err != nil {
log.Panicf("An unxpected error occurred: %s", err)
log.Panicf("An unexpected error occurred: %s", err)
}
b.WorkspaceMapping.Tags = tags

View File

@ -223,6 +223,7 @@ func TestCloud_PrepareConfigWithEnvVars(t *testing.T) {
func TestCloud_configWithEnvVars(t *testing.T) {
cases := map[string]struct {
setup func(b *Cloud)
config cty.Value
vars map[string]string
expectedOrganization string
@ -271,13 +272,13 @@ func TestCloud_configWithEnvVars(t *testing.T) {
}),
}),
vars: map[string]string{
"TF_HOSTNAME": "app.terraform.io",
"TF_HOSTNAME": "private.hashicorp.engineering",
},
expectedHostname: "app.terraform.io",
expectedHostname: "private.hashicorp.engineering",
},
"with hostname and env var specified": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.StringVal("app.terraform.io"),
"hostname": cty.StringVal("private.hashicorp.engineering"),
"token": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
@ -288,11 +289,11 @@ func TestCloud_configWithEnvVars(t *testing.T) {
vars: map[string]string{
"TF_HOSTNAME": "mycool.tfe-host.io",
},
expectedHostname: "app.terraform.io",
expectedHostname: "private.hashicorp.engineering",
},
"an invalid workspace env var": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.StringVal("app.terraform.io"),
"hostname": cty.NullVal(cty.String),
"token": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"workspaces": cty.NullVal(cty.Object(map[string]cty.Type{
@ -307,25 +308,98 @@ func TestCloud_configWithEnvVars(t *testing.T) {
},
"workspaces and env var specified": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.StringVal("app.terraform.io"),
"hostname": cty.NullVal(cty.String),
"token": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"organization": cty.StringVal("mordor"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"name": cty.StringVal("mt-doom"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
vars: map[string]string{
"TF_WORKSPACE": "mt-doom",
"TF_WORKSPACE": "shire",
},
expectedWorkspaceName: "prod",
expectedWorkspaceName: "mt-doom",
},
"env var workspace does not have specified tag": {
setup: func(b *Cloud) {
b.client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
Name: tfe.String("mordor"),
})
b.client.Workspaces.Create(context.Background(), "mordor", tfe.WorkspaceCreateOptions{
Name: tfe.String("shire"),
})
},
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"token": cty.NullVal(cty.String),
"organization": cty.StringVal("mordor"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"tags": cty.SetVal([]cty.Value{
cty.StringVal("cloud"),
}),
}),
}),
vars: map[string]string{
"TF_WORKSPACE": "shire",
},
expectedErr: "Terraform failed to find workspace \"shire\" with the tags specified in your configuration:\n[cloud]",
},
"env var workspace has specified tag": {
setup: func(b *Cloud) {
b.client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
Name: tfe.String("mordor"),
})
b.client.Workspaces.Create(context.Background(), "mordor", tfe.WorkspaceCreateOptions{
Name: tfe.String("shire"),
Tags: []*tfe.Tag{
{
Name: "hobbity",
},
},
})
},
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"token": cty.NullVal(cty.String),
"organization": cty.StringVal("mordor"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"tags": cty.SetVal([]cty.Value{
cty.StringVal("hobbity"),
}),
}),
}),
vars: map[string]string{
"TF_WORKSPACE": "shire",
},
expectedWorkspaceName: "", // No error is raised, but workspace is not set
},
"with everything set as env vars": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"token": cty.NullVal(cty.String),
"organization": cty.NullVal(cty.String),
"workspaces": cty.NullVal(cty.String),
}),
vars: map[string]string{
"TF_ORGANIZATION": "mordor",
"TF_WORKSPACE": "mt-doom",
"TF_HOSTNAME": "mycool.tfe-host.io",
},
expectedOrganization: "mordor",
expectedWorkspaceName: "mt-doom",
expectedHostname: "mycool.tfe-host.io",
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
s := testServer(t)
b := New(testDisco(s))
b, cleanup := testUnconfiguredBackend(t)
t.Cleanup(cleanup)
for k, v := range tc.vars {
os.Setenv(k, v)
@ -342,6 +416,10 @@ func TestCloud_configWithEnvVars(t *testing.T) {
t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
}
if tc.setup != nil {
tc.setup(b)
}
diags := b.Configure(tc.config)
if (diags.Err() != nil || tc.expectedErr != "") &&
(diags.Err() == nil || !strings.Contains(diags.Err().Error(), tc.expectedErr)) {
@ -369,18 +447,6 @@ func TestCloud_config(t *testing.T) {
confErr string
valErr string
}{
"with_a_nonexisting_organization": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"organization": cty.StringVal("nonexisting"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
confErr: "organization \"nonexisting\" at host app.terraform.io not found",
},
"with_an_unknown_host": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.StringVal("nonexisting.local"),
@ -466,8 +532,8 @@ func TestCloud_config(t *testing.T) {
}
for name, tc := range cases {
s := testServer(t)
b := New(testDisco(s))
b, cleanup := testUnconfiguredBackend(t)
t.Cleanup(cleanup)
// Validate
_, valDiags := b.PrepareConfig(tc.config)

View File

@ -178,6 +178,44 @@ func testBackend(t *testing.T, obj cty.Value) (*Cloud, func()) {
return b, s.Close
}
// testUnconfiguredBackend is used for testing the configuration of the backend
// with the mock client
func testUnconfiguredBackend(t *testing.T) (*Cloud, func()) {
s := testServer(t)
b := New(testDisco(s))
// Normally, the client is created during configuration, but the configuration uses the
// client to read entitlements.
var err error
b.client, err = tfe.NewClient(&tfe.Config{
Token: "fake-token",
})
if err != nil {
t.Fatal(err)
}
// Get a new mock client.
mc := NewMockClient()
// Replace the services we use with our mock services.
b.CLI = cli.NewMockUi()
b.client.Applies = mc.Applies
b.client.ConfigurationVersions = mc.ConfigurationVersions
b.client.CostEstimates = mc.CostEstimates
b.client.Organizations = mc.Organizations
b.client.Plans = mc.Plans
b.client.PolicyChecks = mc.PolicyChecks
b.client.Runs = mc.Runs
b.client.StateVersions = mc.StateVersions
b.client.Variables = mc.Variables
b.client.Workspaces = mc.Workspaces
// Set local to a local test backend.
b.local = testLocalBackend(t, b)
return b, s.Close
}
func testLocalBackend(t *testing.T, cloud *Cloud) backend.Enhanced {
b := backendLocal.NewWithBackend(cloud)