From 8c7fc7804425caadfdd557c6df12df240646abb8 Mon Sep 17 00:00:00 2001 From: Sarah French Date: Tue, 11 Nov 2025 17:11:14 +0000 Subject: [PATCH] test: Add E2E tests for `state list` and `state show` commands --- .../e2etest/pluggable_state_store_test.go | 78 +++++++++++++++++++ .../.terraform.lock.hcl | 6 ++ .../hashicorp/simple6/0.0.1/.gitkeep | 0 .../.terraform/terraform.tfstate | 16 ++++ .../main.tf | 25 ++++++ .../states/default/terraform.tfstate | 40 ++++++++++ 6 files changed, 165 insertions(+) create mode 100644 internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform.lock.hcl create mode 100644 internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/providers/registry.terraform.io/hashicorp/simple6/0.0.1/.gitkeep create mode 100644 internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/terraform.tfstate create mode 100644 internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/main.tf create mode 100644 internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/states/default/terraform.tfstate diff --git a/internal/command/e2etest/pluggable_state_store_test.go b/internal/command/e2etest/pluggable_state_store_test.go index a8f59183b988..09f802ce8cca 100644 --- a/internal/command/e2etest/pluggable_state_store_test.go +++ b/internal/command/e2etest/pluggable_state_store_test.go @@ -11,10 +11,12 @@ import ( "strings" "testing" + "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform/internal/e2e" "github.com/hashicorp/terraform/internal/getproviders" ) +// Tests using `terraform workspace` commands in combination with pluggable state storage. func TestPrimary_stateStore_workspaceCmd(t *testing.T) { if !canRunGoBuild { // We're running in a separate-build-then-run context, so we can't @@ -119,3 +121,79 @@ func TestPrimary_stateStore_workspaceCmd(t *testing.T) { t.Errorf("unexpected output, expected %q, but got:\n%s", expectedMsg, stdout) } } + +// Tests using `terraform state` subcommands in combination with pluggable state storage: +// > `terraform state show` +// > `terraform state list` +func TestPrimary_stateStore_stateCmds(t *testing.T) { + + if !canRunGoBuild { + // We're running in a separate-build-then-run context, so we can't + // currently execute this test which depends on being able to build + // new executable at runtime. + // + // (See the comment on canRunGoBuild's declaration for more information.) + t.Skip("can't run without building a new provider executable") + } + + t.Setenv(e2e.TestExperimentFlag, "true") + tfBin := e2e.GoBuild("github.com/hashicorp/terraform", "terraform") + + fixturePath := filepath.Join("testdata", "initialized-directory-with-state-store-fs") + tf := e2e.NewBinary(t, tfBin, fixturePath) + + workspaceDirName := "states" // see test fixture value for workspace_dir + + // In order to test integration with PSS we need a provider plugin implementing a state store. + // Here will build the simple6 (built with protocol v6) provider, which implements PSS. + simple6Provider := filepath.Join(tf.WorkDir(), "terraform-provider-simple6") + simple6ProviderExe := e2e.GoBuild("github.com/hashicorp/terraform/internal/provider-simple-v6/main", simple6Provider) + + // Move the provider binaries into the correct directory .terraform/providers/ directory + // that will contain provider binaries in an initialized working directory. + platform := getproviders.CurrentPlatform.String() + if err := os.MkdirAll(tf.Path(".terraform/providers/registry.terraform.io/hashicorp/simple6/0.0.1/", platform), os.ModePerm); err != nil { + t.Fatal(err) + } + if err := os.Rename(simple6ProviderExe, tf.Path(".terraform/providers/registry.terraform.io/hashicorp/simple6/0.0.1/", platform, "terraform-provider-simple6")); err != nil { + t.Fatal(err) + } + + // Assert that the test starts with the default state present from test fixtures + defaultStateId := "default" + fi, err := os.Stat(path.Join(tf.WorkDir(), workspaceDirName, defaultStateId, "terraform.tfstate")) + if err != nil { + t.Fatalf("failed to open default workspace's state file: %s", err) + } + if fi.Size() == 0 { + t.Fatal("default workspace's state file should not have size 0 bytes") + } + + //// List State: terraform state list + expectedResourceAddr := "terraform_data.my-data" + stdout, stderr, err := tf.Run("state", "list", "-no-color") + if err != nil { + t.Fatalf("unexpected error: %s\nstderr:\n%s", err, stderr) + } + expectedMsg := expectedResourceAddr + "\n" // This is the only resource instance in the test fixture state + if stdout != expectedMsg { + t.Errorf("unexpected output, expected %q, but got:\n%s", expectedMsg, stdout) + } + + //// Show State: terraform state show + stdout, stderr, err = tf.Run("state", "show", expectedResourceAddr, "-no-color") + if err != nil { + t.Fatalf("unexpected error: %s\nstderr:\n%s", err, stderr) + } + // show displays the state for the specified resource + expectedMsg = `# terraform_data.my-data: +resource "terraform_data" "my-data" { + id = "d71fb368-2ba1-fb4c-5bd9-6a2b7f05d60c" + input = "hello world" + output = "hello world" +} +` + if diff := cmp.Diff(stdout, expectedMsg); diff != "" { + t.Errorf("wrong result, diff:\n%s", diff) + } +} diff --git a/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform.lock.hcl b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform.lock.hcl new file mode 100644 index 000000000000..7a0db0a25a93 --- /dev/null +++ b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform.lock.hcl @@ -0,0 +1,6 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/simple6" { + version = "0.0.1" +} diff --git a/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/providers/registry.terraform.io/hashicorp/simple6/0.0.1/.gitkeep b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/providers/registry.terraform.io/hashicorp/simple6/0.0.1/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/terraform.tfstate b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/terraform.tfstate new file mode 100644 index 000000000000..e297b792ce7b --- /dev/null +++ b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/.terraform/terraform.tfstate @@ -0,0 +1,16 @@ +{ + "version": 3, + "terraform_version": "1.15.0", + "state_store": { + "type": "simple6_fs", + "provider": { + "version": "0.0.1", + "source": "registry.terraform.io/hashicorp/simple6", + "config": {} + }, + "config": { + "workspace_dir": "states" + }, + "hash": 3942813381 + } +} \ No newline at end of file diff --git a/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/main.tf b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/main.tf new file mode 100644 index 000000000000..d2c773a6fca9 --- /dev/null +++ b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/main.tf @@ -0,0 +1,25 @@ +terraform { + required_providers { + simple6 = { + source = "registry.terraform.io/hashicorp/simple6" + } + } + + state_store "simple6_fs" { + provider "simple6" {} + + workspace_dir = "states" + } +} + +variable "name" { + default = "world" +} + +resource "terraform_data" "my-data" { + input = "hello ${var.name}" +} + +output "greeting" { + value = resource.terraform_data.my-data.output +} diff --git a/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/states/default/terraform.tfstate b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/states/default/terraform.tfstate new file mode 100644 index 000000000000..4feaaed87a08 --- /dev/null +++ b/internal/command/e2etest/testdata/initialized-directory-with-state-store-fs/states/default/terraform.tfstate @@ -0,0 +1,40 @@ +{ + "version": 4, + "terraform_version": "1.15.0", + "serial": 1, + "lineage": "9e13d881-e480-7a63-d47a-b4f5224e6743", + "outputs": { + "greeting": { + "value": "hello world", + "type": "string" + } + }, + "resources": [ + { + "mode": "managed", + "type": "terraform_data", + "name": "my-data", + "provider": "provider[\"terraform.io/builtin/terraform\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "d71fb368-2ba1-fb4c-5bd9-6a2b7f05d60c", + "input": { + "value": "hello world", + "type": "string" + }, + "output": { + "value": "hello world", + "type": "string" + }, + "triggers_replace": null + }, + "sensitive_attributes": [], + "identity_schema_version": 0 + } + ] + } + ], + "check_results": null +} \ No newline at end of file