Skip to content

Commit 9d40a84

Browse files
committed
Move init command test cases up to the 'command testing' level. This is currently only possible for testing init commands interacting with the PSS command
1 parent b1efad9 commit 9d40a84

File tree

3 files changed

+270
-127
lines changed

3 files changed

+270
-127
lines changed

internal/command/init_test.go

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/zclconf/go-cty/cty"
2121

2222
"github.com/hashicorp/terraform/internal/addrs"
23+
"github.com/hashicorp/terraform/internal/backend"
2324
"github.com/hashicorp/terraform/internal/command/arguments"
2425
"github.com/hashicorp/terraform/internal/command/views"
2526
"github.com/hashicorp/terraform/internal/configs"
@@ -3227,6 +3228,111 @@ func TestInit_testsWithModule(t *testing.T) {
32273228
}
32283229
}
32293230

3231+
// Testing init's behaviors when run in an empty working directory
3232+
func TestInit_stateStore_newWorkingDir(t *testing.T) {
3233+
t.Run("an init command creates the default workspace by default", func(t *testing.T) {
3234+
// Create a temporary, uninitialized working directory with configuration including a state store
3235+
td := t.TempDir()
3236+
testCopyDir(t, testFixturePath("init-with-state-store"), td)
3237+
t.Chdir(td)
3238+
3239+
mockProvider := mockPluggableStateStorageProvider()
3240+
mockProviderAddress := addrs.NewDefaultProvider("test")
3241+
providerSource, close := newMockProviderSource(t, map[string][]string{
3242+
"hashicorp/test": {"1.0.0"},
3243+
})
3244+
defer close()
3245+
3246+
ui := new(cli.MockUi)
3247+
view, done := testView(t)
3248+
c := &InitCommand{
3249+
Meta: Meta{
3250+
Ui: ui,
3251+
View: view,
3252+
AllowExperimentalFeatures: true,
3253+
testingOverrides: &testingOverrides{
3254+
Providers: map[addrs.Provider]providers.Factory{
3255+
mockProviderAddress: providers.FactoryFixed(mockProvider),
3256+
},
3257+
},
3258+
ProviderSource: providerSource,
3259+
},
3260+
}
3261+
3262+
args := []string{"-enable-pluggable-state-storage-experiment=true"}
3263+
code := c.Run(args)
3264+
testOutput := done(t)
3265+
if code != 0 {
3266+
t.Fatalf("expected code 0 exit code, got %d, output: \n%s", code, testOutput.All())
3267+
}
3268+
3269+
// Check output
3270+
output := testOutput.All()
3271+
expectedOutput := `Initializing the state store...`
3272+
if !strings.Contains(output, expectedOutput) {
3273+
t.Fatalf("expected output to include %q, but got':\n %s", expectedOutput, output)
3274+
}
3275+
3276+
// Assert the default workspace was created
3277+
if _, exists := mockProvider.MockStates[backend.DefaultStateName]; !exists {
3278+
t.Fatal("expected the default workspace to be created during init, but it is missing")
3279+
}
3280+
})
3281+
3282+
t.Run("an init command with the flag -create-default-workspace=false will not make the default workspace", func(t *testing.T) {
3283+
// Create a temporary, uninitialized working directory with configuration including a state store
3284+
td := t.TempDir()
3285+
testCopyDir(t, testFixturePath("init-with-state-store"), td)
3286+
t.Chdir(td)
3287+
3288+
mockProvider := mockPluggableStateStorageProvider()
3289+
mockProviderAddress := addrs.NewDefaultProvider("test")
3290+
providerSource, close := newMockProviderSource(t, map[string][]string{
3291+
"hashicorp/test": {"1.0.0"},
3292+
})
3293+
defer close()
3294+
3295+
ui := new(cli.MockUi)
3296+
view, done := testView(t)
3297+
c := &InitCommand{
3298+
Meta: Meta{
3299+
Ui: ui,
3300+
View: view,
3301+
AllowExperimentalFeatures: true,
3302+
testingOverrides: &testingOverrides{
3303+
Providers: map[addrs.Provider]providers.Factory{
3304+
mockProviderAddress: providers.FactoryFixed(mockProvider),
3305+
},
3306+
},
3307+
ProviderSource: providerSource,
3308+
},
3309+
}
3310+
3311+
args := []string{"-enable-pluggable-state-storage-experiment=true", "-create-default-workspace=false"}
3312+
code := c.Run(args)
3313+
testOutput := done(t)
3314+
if code != 0 {
3315+
t.Fatalf("expected code 0 exit code, got %d, output: \n%s", code, testOutput.All())
3316+
}
3317+
3318+
// Check output
3319+
output := testOutput.All()
3320+
expectedOutput := `Initializing the state store...`
3321+
if !strings.Contains(output, expectedOutput) {
3322+
t.Fatalf("expected output to include %q, but got':\n %s", expectedOutput, output)
3323+
}
3324+
3325+
// Assert the default workspace was created
3326+
if _, exists := mockProvider.MockStates[backend.DefaultStateName]; exists {
3327+
t.Fatal("expected Terraform to skip creating the default workspace, but it has been created")
3328+
}
3329+
})
3330+
3331+
// TODO: Add test cases below once PSS feature isn't experimental.
3332+
// Currently these tests are handled at a lower level in `internal/command/meta_backend_test.go`:
3333+
// > "during a non-init command, the command ends in with an error telling the user to run an init command"
3334+
}
3335+
32303336
// newMockProviderSource is a helper to succinctly construct a mock provider
32313337
// source that contains a set of packages matching the given provider versions
32323338
// that are available for installation (from temporary local files).
@@ -3367,3 +3473,65 @@ func expectedPackageInstallPath(name, version string, exe bool) string {
33673473
baseDir, fmt.Sprintf("registry.terraform.io/hashicorp/%s/%s/%s", name, version, platform),
33683474
))
33693475
}
3476+
3477+
func mockPluggableStateStorageProvider() *testing_provider.MockProvider {
3478+
// Create a mock provider to use for PSS
3479+
// Get mock provider factory to be used during init
3480+
//
3481+
// This imagines a provider called `test` that contains
3482+
// a pluggable state store implementation called `store`.
3483+
pssName := "test_store"
3484+
mock := testing_provider.MockProvider{
3485+
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
3486+
Provider: providers.Schema{
3487+
Body: &configschema.Block{
3488+
Attributes: map[string]*configschema.Attribute{
3489+
"region": {Type: cty.String, Optional: true},
3490+
},
3491+
},
3492+
},
3493+
DataSources: map[string]providers.Schema{},
3494+
ResourceTypes: map[string]providers.Schema{},
3495+
ListResourceTypes: map[string]providers.Schema{},
3496+
StateStores: map[string]providers.Schema{
3497+
pssName: {
3498+
Body: &configschema.Block{
3499+
Attributes: map[string]*configschema.Attribute{
3500+
"bar": {
3501+
Type: cty.String,
3502+
Required: true,
3503+
},
3504+
},
3505+
},
3506+
},
3507+
},
3508+
},
3509+
}
3510+
mock.WriteStateBytesFn = func(req providers.WriteStateBytesRequest) providers.WriteStateBytesResponse {
3511+
// Workspaces exist once the artefact representing it is written
3512+
if _, exist := mock.MockStates[req.StateId]; !exist {
3513+
// Ensure non-nil map
3514+
if mock.MockStates == nil {
3515+
mock.MockStates = make(map[string]interface{})
3516+
}
3517+
3518+
mock.MockStates[req.StateId] = req.Bytes
3519+
}
3520+
return providers.WriteStateBytesResponse{
3521+
Diagnostics: nil, // success
3522+
}
3523+
}
3524+
mock.ReadStateBytesFn = func(req providers.ReadStateBytesRequest) providers.ReadStateBytesResponse {
3525+
state := []byte{}
3526+
if v, exist := mock.MockStates[req.StateId]; exist {
3527+
if s, ok := v.([]byte); ok {
3528+
state = s
3529+
}
3530+
}
3531+
return providers.ReadStateBytesResponse{
3532+
Bytes: state,
3533+
Diagnostics: nil, // success
3534+
}
3535+
}
3536+
return &mock
3537+
}

0 commit comments

Comments
 (0)