diff --git a/CHANGELOG.md b/CHANGELOG.md index 980415288e..180e2186ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ NEW FEATURES: ENHANCEMENTS: BUG FIXES: +* Added a check in the `tofu test` to validate that the names of test run blocks do not contain spaces. ([#1489](https://github.com/opentofu/opentofu/pull/1489)) ## Previous Releases diff --git a/internal/command/e2etest/testdata/multiple-run-blocks/main.tftest.hcl b/internal/command/e2etest/testdata/multiple-run-blocks/main.tftest.hcl index cf6252a808..de9605bc0b 100644 --- a/internal/command/e2etest/testdata/multiple-run-blocks/main.tftest.hcl +++ b/internal/command/e2etest/testdata/multiple-run-blocks/main.tftest.hcl @@ -1,30 +1,30 @@ -run "test 01" { command = plan } -run "test 02" { command = plan } -run "test 03" { command = plan } -run "test 04" { command = plan } -run "test 05" { command = plan } -run "test 06" { command = plan } -run "test 07" { command = plan } -run "test 08" { command = plan } -run "test 09" { command = plan } -run "test 10" { command = plan } -run "test 11" { command = plan } -run "test 12" { command = plan } -run "test 13" { command = plan } -run "test 14" { command = plan } -run "test 15" { command = plan } -run "test 16" { command = plan } -run "test 17" { command = plan } -run "test 18" { command = plan } -run "test 19" { command = plan } -run "test 20" { command = plan } -run "test 21" { command = plan } -run "test 22" { command = plan } -run "test 23" { command = plan } -run "test 24" { command = plan } -run "test 25" { command = plan } -run "test 26" { command = plan } -run "test 27" { command = plan } -run "test 28" { command = plan } -run "test 29" { command = plan } -run "test 30" { command = plan } +run "test_01" { command = plan } +run "test_02" { command = plan } +run "test_03" { command = plan } +run "test_04" { command = plan } +run "test_05" { command = plan } +run "test_06" { command = plan } +run "test_07" { command = plan } +run "test_08" { command = plan } +run "test_09" { command = plan } +run "test_10" { command = plan } +run "test_11" { command = plan } +run "test_12" { command = plan } +run "test_13" { command = plan } +run "test_14" { command = plan } +run "test_15" { command = plan } +run "test_16" { command = plan } +run "test_17" { command = plan } +run "test_18" { command = plan } +run "test_19" { command = plan } +run "test_20" { command = plan } +run "test_21" { command = plan } +run "test_22" { command = plan } +run "test_23" { command = plan } +run "test_24" { command = plan } +run "test_25" { command = plan } +run "test_26" { command = plan } +run "test_27" { command = plan } +run "test_28" { command = plan } +run "test_29" { command = plan } +run "test_30" { command = plan } diff --git a/internal/command/test_test.go b/internal/command/test_test.go index 291ad108d6..04a77d9edc 100644 --- a/internal/command/test_test.go +++ b/internal/command/test_test.go @@ -254,7 +254,7 @@ func TestTest_Full_Output(t *testing.T) { code: 1, }, "is_sorted": { - expected: "1.tftest.hcl... pass\n run \"1\"... pass\n2.tftest.hcl... pass\n run \"2\"... pass\n3.tftest.hcl... pass\n run \"3\"... pass", + expected: "1.tftest.hcl... pass\n run \"a\"... pass\n2.tftest.hcl... pass\n run \"b\"... pass\n3.tftest.hcl... pass\n run \"c\"... pass", code: 0, args: []string{"-no-color"}, }, @@ -1196,3 +1196,63 @@ Success! 2 passed, 0 failed. t.Errorf("should have deleted all resources on completion but left %v", provider.ResourceString()) } } + +func TestTest_RunBlock(t *testing.T) { + tcs := map[string]struct { + expected string + code int + skip bool + }{ + "invalid_run_block_name": { + expected: ` +Error: Invalid run block name + + on tests/main.tftest.hcl line 1, in run "sample run": + 1: run "sample run" { + +A name must start with a letter or underscore and may contain only letters, +digits, underscores, and dashes. +`, + code: 1, + }, + } + + for name, tc := range tcs { + t.Run(name, func(t *testing.T) { + if tc.skip { + t.Skip() + } + + file := name + + td := t.TempDir() + testCopyDir(t, testFixturePath(path.Join("test", file)), td) + defer testChdir(t, td)() + + provider := testing_command.NewProvider(nil) + providerSource, close := newMockProviderSource(t, map[string][]string{ + "test": {"1.0.0"}, + }) + defer close() + + streams, _ := terminal.StreamsForTesting(t) + view := views.NewView(streams) + ui := new(cli.MockUi) + meta := Meta{ + testingOverrides: metaOverridesForProvider(provider.Provider), + Ui: ui, + View: view, + Streams: streams, + ProviderSource: providerSource, + } + + init := &InitCommand{ + Meta: meta, + } + + if code := init.Run(nil); code != tc.code { + t.Fatalf("expected status code 0 but got %d: %s", code, ui.ErrorWriter) + } + }) + } +} diff --git a/internal/command/testdata/test/invalid_run_block_name/main.tf b/internal/command/testdata/test/invalid_run_block_name/main.tf new file mode 100644 index 0000000000..f9c3e7081b --- /dev/null +++ b/internal/command/testdata/test/invalid_run_block_name/main.tf @@ -0,0 +1,3 @@ +provider "test" { + value = "foo" +} \ No newline at end of file diff --git a/internal/command/testdata/test/invalid_run_block_name/tests/main.tftest.hcl b/internal/command/testdata/test/invalid_run_block_name/tests/main.tftest.hcl new file mode 100644 index 0000000000..18c2d875e0 --- /dev/null +++ b/internal/command/testdata/test/invalid_run_block_name/tests/main.tftest.hcl @@ -0,0 +1,5 @@ +run "sample run" { + module { + source = "./.." + } +} \ No newline at end of file diff --git a/internal/command/testdata/test/is_sorted/1.tftest.hcl b/internal/command/testdata/test/is_sorted/1.tftest.hcl index c0cb2809e0..1374421a98 100644 --- a/internal/command/testdata/test/is_sorted/1.tftest.hcl +++ b/internal/command/testdata/test/is_sorted/1.tftest.hcl @@ -1,4 +1,4 @@ -run "1" { +run "a" { assert { condition = test_resource.resource.value == null error_message = "should pass" diff --git a/internal/command/testdata/test/is_sorted/2.tftest.hcl b/internal/command/testdata/test/is_sorted/2.tftest.hcl index 88e21e9a10..a0c45332f5 100644 --- a/internal/command/testdata/test/is_sorted/2.tftest.hcl +++ b/internal/command/testdata/test/is_sorted/2.tftest.hcl @@ -1,4 +1,4 @@ -run "2" { +run "b" { assert { condition = test_resource.resource.value == null error_message = "should pass" diff --git a/internal/command/testdata/test/is_sorted/3.tftest.hcl b/internal/command/testdata/test/is_sorted/3.tftest.hcl index ba774d8693..b1c1cda2e6 100644 --- a/internal/command/testdata/test/is_sorted/3.tftest.hcl +++ b/internal/command/testdata/test/is_sorted/3.tftest.hcl @@ -1,4 +1,4 @@ -run "3" { +run "c" { assert { condition = test_resource.resource.value == null error_message = "should pass" diff --git a/internal/configs/test_file.go b/internal/configs/test_file.go index 379f5b2aa3..22af7b4286 100644 --- a/internal/configs/test_file.go +++ b/internal/configs/test_file.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" + "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/opentofu/opentofu/internal/addrs" "github.com/opentofu/opentofu/internal/getmodules" @@ -252,6 +253,16 @@ func decodeTestRunBlock(block *hcl.Block) (*TestRun, hcl.Diagnostics) { NameDeclRange: block.LabelRanges[0], DeclRange: block.DefRange, } + + if !hclsyntax.ValidIdentifier(r.Name) { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid run block name", + Detail: badIdentifierDetail, + Subject: &block.LabelRanges[0], + }) + } + for _, block := range content.Blocks { switch block.Type { case "assert": diff --git a/internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl b/internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl index fbd536f519..d0c1034795 100644 --- a/internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl +++ b/internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl @@ -11,7 +11,7 @@ provider "bar" { run "default_should_be_fine" {} -run "bit_complicated_still_okay "{ +run "bit_complicated_still_okay"{ providers = { foo = foo