blob: e1811a93419f7b6c9c7ea79da91c77c55bccc397 [file] [edit]
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1
package command
import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"google.golang.org/grpc/metadata"
)
func TestStacksPluginConfig_ToMetadata(t *testing.T) {
t.Parallel()
expected := metadata.Pairs(
"tfc-address", "https://app.staging.terraform.io",
"tfc-base-path", "/api/v2/",
"tfc-display-hostname", "app.staging.terraform.io",
"tfc-token", "not-a-legit-token",
"tfc-organization", "example-corp",
"tfc-project", "example-project",
"tfc-stack", "example-stack",
"terraform-binary-path", "",
"terminal-width", "78",
)
inputStruct := StacksPluginConfig{
Address: "https://app.staging.terraform.io",
BasePath: "/api/v2/",
DisplayHostname: "app.staging.terraform.io",
Token: "not-a-legit-token",
OrganizationName: "example-corp",
ProjectName: "example-project",
StackName: "example-stack",
TerraformBinaryPath: "",
TerminalWidth: 78,
}
result := inputStruct.ToMetadata()
if !reflect.DeepEqual(expected, result) {
t.Fatalf("Expected: %#v\nGot: %#v\n", expected, result)
}
}
func TestStacks_resolveDisplayHostname(t *testing.T) {
tests := []struct {
name string
tfStacksHostname string
tfCloudHostname string
credentialsJSON string
wantHostname string
wantErrContains string
wantWarnContains string
}{
{
name: "uses TF_STACKS_HOSTNAME first",
tfStacksHostname: "stacks.example.com",
tfCloudHostname: "cloud.example.com",
credentialsJSON: `{"credentials":{"cred.example.com":{"token":"x"}}}`,
wantHostname: "stacks.example.com",
},
{
name: "uses TF_CLOUD_HOSTNAME when stacks hostname missing",
tfCloudHostname: "cloud.example.com",
credentialsJSON: `{"credentials":{"cred.example.com":{"token":"x"}}}`,
wantHostname: "cloud.example.com",
},
{
name: "uses single credentials hostname",
credentialsJSON: `{"credentials":{"tfe.company.com":{"token":"x"}}}`,
wantHostname: "tfe.company.com",
},
{
name: "multiple credentials hostnames returns error",
credentialsJSON: `{"credentials":{"app.terraform.io":{"token":"x"},"tfe.company.com":{"token":"y"}}}`,
wantErrContains: "Multiple hostnames found in credentials file",
},
{
name: "missing credentials file falls back to default",
wantHostname: defaultHostname,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
// Override HOME so cliconfig.ConfigDir() resolves to a temp dir
// we control, avoiding interference from real credentials on the
// developer's machine.
home := t.TempDir()
t.Setenv("HOME", home)
if test.credentialsJSON != "" {
// CredentialsConfigFile() returns $HOME/.terraform.d/credentials.tfrc.json
configDir := filepath.Join(home, ".terraform.d")
if err := os.MkdirAll(configDir, 0700); err != nil {
t.Fatalf("failed to create config dir: %s", err)
}
filename := filepath.Join(configDir, "credentials.tfrc.json")
if err := os.WriteFile(filename, []byte(test.credentialsJSON), 0600); err != nil {
t.Fatalf("failed to write credentials file: %s", err)
}
}
t.Setenv("TF_STACKS_HOSTNAME", test.tfStacksHostname)
t.Setenv("TF_CLOUD_HOSTNAME", test.tfCloudHostname)
c := &StacksCommand{Meta: Meta{}}
hostname, diags := c.resolveDisplayHostname()
if test.wantErrContains != "" {
if !diags.HasErrors() {
t.Fatalf("expected error diagnostics")
}
if got := diags.Err().Error(); !strings.Contains(got, test.wantErrContains) {
t.Fatalf("wrong error\ngot: %s\nwant: %s", got, test.wantErrContains)
}
return
}
if diags.HasErrors() {
t.Fatalf("unexpected error diagnostics: %s", diags.Err().Error())
}
if hostname != test.wantHostname {
t.Fatalf("wrong hostname\ngot: %q\nwant: %q", hostname, test.wantHostname)
}
if test.wantWarnContains == "" {
if diags.HasWarnings() {
t.Fatalf("unexpected warnings: %s", diags.ErrWithWarnings().Error())
}
return
}
if !diags.HasWarnings() {
t.Fatalf("expected warning diagnostics")
}
if got := diags.ErrWithWarnings().Error(); !strings.Contains(got, test.wantWarnContains) {
t.Fatalf("wrong warning\ngot: %s\nwant: %s", got, test.wantWarnContains)
}
})
}
}