mirror of https://github.com/hashicorp/terraform
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
934 lines
30 KiB
934 lines
30 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package cloud
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/hashicorp/go-tfe"
|
|
|
|
"github.com/hashicorp/terraform/internal/command/arguments"
|
|
"github.com/hashicorp/terraform/internal/command/jsonformat"
|
|
"github.com/hashicorp/terraform/internal/command/views"
|
|
"github.com/hashicorp/terraform/internal/configs/configload"
|
|
"github.com/hashicorp/terraform/internal/terminal"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
)
|
|
|
|
func TestTest(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
if _, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
}); err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test",
|
|
TestingDirectory: "tests",
|
|
Config: nil, // We don't need this for this test.
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: context.Background(),
|
|
CancelledCtx: context.Background(),
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: &jsonformat.Renderer{
|
|
Streams: streams,
|
|
Colorize: colorize,
|
|
RunningInAutomation: false,
|
|
},
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
_, diags := runner.Test()
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := done(t)
|
|
actual := output.All()
|
|
expected := `main.tftest.hcl... in progress
|
|
defaults... pass
|
|
overrides... pass
|
|
main.tftest.hcl... tearing down
|
|
main.tftest.hcl... pass
|
|
|
|
Success! 2 passed, 0 failed.
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
}
|
|
|
|
func TestTest_JSON(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
if _, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
}); err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test",
|
|
TestingDirectory: "tests",
|
|
Config: nil, // We don't need this for this test.
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: context.Background(),
|
|
CancelledCtx: context.Background(),
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: nil, // This should force the logs to render as JSON.
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
_, diags := runner.Test()
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := done(t)
|
|
actual := output.All()
|
|
expected := `{"@level":"info","@message":"Terraform 1.6.0-dev","@module":"terraform.ui","@timestamp":"2023-09-12T08:29:27.257413+02:00","terraform":"1.6.0-dev","type":"version","ui":"1.2"}
|
|
{"@level":"info","@message":"Found 1 file and 2 run blocks","@module":"terraform.ui","@timestamp":"2023-09-12T08:29:27.268731+02:00","test_abstract":{"main.tftest.hcl":["defaults","overrides"]},"type":"test_abstract"}
|
|
{"@level":"info","@message":"main.tftest.hcl... in progress","@module":"terraform.ui","@testfile":"main.tftest.hcl","@timestamp":"2023-09-12T08:29:27.268889+02:00","test_file":{"path":"main.tftest.hcl","progress":"starting"},"type":"test_file"}
|
|
{"@level":"info","@message":" \"defaults\"... pass","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"defaults","@timestamp":"2023-09-12T08:29:27.710541+02:00","test_run":{"path":"main.tftest.hcl","run":"defaults","progress":"complete","status":"pass"},"type":"test_run"}
|
|
{"@level":"info","@message":" \"overrides\"... pass","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"overrides","@timestamp":"2023-09-12T08:29:27.833351+02:00","test_run":{"path":"main.tftest.hcl","run":"overrides","progress":"complete","status":"pass"},"type":"test_run"}
|
|
{"@level":"info","@message":"main.tftest.hcl... tearing down","@module":"terraform.ui","@testfile":"main.tftest.hcl","@timestamp":"2023-09-12T08:29:27.833375+02:00","test_file":{"path":"main.tftest.hcl","progress":"teardown"},"type":"test_file"}
|
|
{"@level":"info","@message":"main.tftest.hcl... pass","@module":"terraform.ui","@testfile":"main.tftest.hcl","@timestamp":"2023-09-12T08:29:27.956488+02:00","test_file":{"path":"main.tftest.hcl","progress":"complete","status":"pass"},"type":"test_file"}
|
|
{"@level":"info","@message":"Success! 2 passed, 0 failed.","@module":"terraform.ui","@timestamp":"2023-09-12T08:29:27.956510+02:00","test_summary":{"status":"pass","passed":2,"failed":0,"errored":0,"skipped":0},"type":"test_summary"}
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
}
|
|
|
|
func TestTest_Verbose(t *testing.T) {
|
|
|
|
directory := "testdata/test-verbose"
|
|
|
|
loader, close := configload.NewLoaderForTests(t)
|
|
defer close()
|
|
|
|
config, configDiags := loader.LoadConfigWithTests(directory, "tests")
|
|
if configDiags.HasErrors() {
|
|
t.Fatalf("failed to load config: %v", configDiags.Error())
|
|
}
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
if _, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
}); err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: directory,
|
|
TestingDirectory: "tests",
|
|
Config: config,
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: context.Background(),
|
|
CancelledCtx: context.Background(),
|
|
|
|
// The test options don't actually matter, as we just retrieve whatever
|
|
// is set in the log file.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: &jsonformat.Renderer{
|
|
Streams: streams,
|
|
Colorize: colorize,
|
|
RunningInAutomation: false,
|
|
},
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
_, diags := runner.Test()
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := done(t)
|
|
actual := output.All()
|
|
expected := `main.tftest.hcl... in progress
|
|
defaults... pass
|
|
|
|
Changes to Outputs:
|
|
+ input = "Hello, world!"
|
|
|
|
You can apply this plan to save these new output values to the Terraform
|
|
state, without changing any real infrastructure.
|
|
╷
|
|
│ Warning: Deprecated
|
|
│
|
|
│ with data.null_data_source.values,
|
|
│ on main.tf line 7, in data "null_data_source" "values":
|
|
│ 7: data "null_data_source" "values" {
|
|
│
|
|
│ The null_data_source was historically used to construct intermediate values
|
|
│ to re-use elsewhere in configuration, the same can now be achieved using
|
|
│ locals
|
|
╵
|
|
╷
|
|
│ Warning: Deprecated
|
|
│
|
|
│ with data.null_data_source.values,
|
|
│ on main.tf line 7, in data "null_data_source" "values":
|
|
│ 7: data "null_data_source" "values" {
|
|
│
|
|
│ The null_data_source was historically used to construct intermediate values
|
|
│ to re-use elsewhere in configuration, the same can now be achieved using
|
|
│ locals
|
|
╵
|
|
overrides... pass
|
|
# data.null_data_source.values:
|
|
data "null_data_source" "values" {
|
|
has_computed_default = "default"
|
|
id = "static"
|
|
inputs = {
|
|
"data" = "Hello, universe!"
|
|
}
|
|
outputs = {
|
|
"data" = "Hello, universe!"
|
|
}
|
|
random = "8484833523059069761"
|
|
}
|
|
|
|
|
|
Outputs:
|
|
|
|
input = "Hello, universe!"
|
|
╷
|
|
│ Warning: Deprecated
|
|
│
|
|
│ with data.null_data_source.values,
|
|
│ on main.tf line 7, in data "null_data_source" "values":
|
|
│ 7: data "null_data_source" "values" {
|
|
│
|
|
│ The null_data_source was historically used to construct intermediate values
|
|
│ to re-use elsewhere in configuration, the same can now be achieved using
|
|
│ locals
|
|
╵
|
|
╷
|
|
│ Warning: Deprecated
|
|
│
|
|
│ with data.null_data_source.values,
|
|
│ on main.tf line 7, in data "null_data_source" "values":
|
|
│ 7: data "null_data_source" "values" {
|
|
│
|
|
│ The null_data_source was historically used to construct intermediate values
|
|
│ to re-use elsewhere in configuration, the same can now be achieved using
|
|
│ locals
|
|
╵
|
|
main.tftest.hcl... tearing down
|
|
main.tftest.hcl... pass
|
|
|
|
Success! 2 passed, 0 failed.
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
}
|
|
|
|
func TestTest_Cancel(t *testing.T) {
|
|
|
|
streams, outputFn := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
module, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
doneContext, done := context.WithCancel(context.Background())
|
|
stopContext, stop := context.WithCancel(context.Background())
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test-cancel",
|
|
TestingDirectory: "tests",
|
|
Config: nil, // We don't need this for this test.
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: stopContext,
|
|
CancelledCtx: context.Background(),
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: &jsonformat.Renderer{
|
|
Streams: streams,
|
|
Colorize: colorize,
|
|
RunningInAutomation: false,
|
|
},
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
// We're only going to be able to finish this if the cancellation calls
|
|
// are done correctly.
|
|
mock.TestRuns.targetCancels = 1
|
|
|
|
var diags tfdiags.Diagnostics
|
|
go func() {
|
|
defer done()
|
|
_, diags = runner.Test()
|
|
}()
|
|
|
|
stop() // immediately cancel
|
|
|
|
// Wait for finish!
|
|
<-doneContext.Done()
|
|
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := outputFn(t)
|
|
actual := output.All()
|
|
expected := `main.tftest.hcl... in progress
|
|
|
|
Interrupt received.
|
|
Please wait for Terraform to exit or data loss may occur.
|
|
Gracefully shutting down...
|
|
|
|
defaults... pass
|
|
overrides... skip
|
|
main.tftest.hcl... tearing down
|
|
main.tftest.hcl... pass
|
|
|
|
Success! 1 passed, 0 failed, 1 skipped.
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
|
|
// We want to make sure the cancel signal actually made it through.
|
|
// Luckily we can access the test runs directly in the mock client.
|
|
tr := mock.TestRuns.modules[module.ID][0]
|
|
if tr.Status != tfe.TestRunCanceled {
|
|
t.Errorf("expected test run to have been cancelled but was %s", tr.Status)
|
|
}
|
|
|
|
if mock.TestRuns.cancels != 1 {
|
|
t.Errorf("incorrect number of cancels, expected 1 but was %d", mock.TestRuns.cancels)
|
|
}
|
|
}
|
|
|
|
// TestTest_DelayedCancel just makes sure that if we trigger the cancellation
|
|
// during the log reading stage then it still cancels properly.
|
|
func TestTest_DelayedCancel(t *testing.T) {
|
|
|
|
streams, outputFn := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
module, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
doneContext, done := context.WithCancel(context.Background())
|
|
stopContext, stop := context.WithCancel(context.Background())
|
|
|
|
mock.TestRuns.delayedCancel = stop
|
|
|
|
// We're only going to be able to finish this if the cancellation calls
|
|
// are done correctly.
|
|
mock.TestRuns.targetCancels = 1
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test-cancel",
|
|
TestingDirectory: "tests",
|
|
Config: nil, // We don't need this for this test.
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: stopContext,
|
|
CancelledCtx: context.Background(),
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: &jsonformat.Renderer{
|
|
Streams: streams,
|
|
Colorize: colorize,
|
|
RunningInAutomation: false,
|
|
},
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
var diags tfdiags.Diagnostics
|
|
go func() {
|
|
defer done()
|
|
_, diags = runner.Test()
|
|
}()
|
|
|
|
// Wait for finish!
|
|
<-doneContext.Done()
|
|
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := outputFn(t)
|
|
actual := output.All()
|
|
expected := `main.tftest.hcl... in progress
|
|
|
|
Interrupt received.
|
|
Please wait for Terraform to exit or data loss may occur.
|
|
Gracefully shutting down...
|
|
|
|
defaults... pass
|
|
overrides... skip
|
|
main.tftest.hcl... tearing down
|
|
main.tftest.hcl... pass
|
|
|
|
Success! 1 passed, 0 failed, 1 skipped.
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
|
|
// We want to make sure the cancel signal actually made it through.
|
|
// Luckily we can access the test runs directly in the mock client.
|
|
tr := mock.TestRuns.modules[module.ID][0]
|
|
if tr.Status != tfe.TestRunCanceled {
|
|
t.Errorf("expected test run to have been cancelled but was %s", tr.Status)
|
|
}
|
|
}
|
|
|
|
func TestTest_ForceCancel(t *testing.T) {
|
|
|
|
loader, close := configload.NewLoaderForTests(t)
|
|
defer close()
|
|
|
|
config, configDiags := loader.LoadConfigWithTests("testdata/test-force-cancel", "tests")
|
|
if configDiags.HasErrors() {
|
|
t.Fatalf("failed to load config: %v", configDiags.Error())
|
|
}
|
|
|
|
streams, outputFn := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
module, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
doneContext, done := context.WithCancel(context.Background())
|
|
stopContext, stop := context.WithCancel(context.Background())
|
|
cancelContext, cancel := context.WithCancel(context.Background())
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test-force-cancel",
|
|
TestingDirectory: "tests",
|
|
Config: config,
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: stopContext,
|
|
CancelledCtx: cancelContext,
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: &jsonformat.Renderer{
|
|
Streams: streams,
|
|
Colorize: colorize,
|
|
RunningInAutomation: false,
|
|
},
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
// We're only going to be able to finish this if the cancellation calls
|
|
// are done correctly.
|
|
mock.TestRuns.targetCancels = 2
|
|
|
|
var diags tfdiags.Diagnostics
|
|
go func() {
|
|
defer done()
|
|
_, diags = runner.Test()
|
|
}()
|
|
|
|
stop()
|
|
cancel()
|
|
|
|
// Wait for finish!
|
|
<-doneContext.Done()
|
|
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := outputFn(t)
|
|
|
|
expectedErr := `Terraform was interrupted during test execution, and may not have performed
|
|
the expected cleanup operations.
|
|
|
|
Terraform was in the process of creating the following resources for
|
|
"overrides" from the module under test, and they may not have been destroyed:
|
|
- time_sleep.wait_5_seconds
|
|
- tfcoremock_simple_resource.resource
|
|
`
|
|
actualErr := output.Stderr()
|
|
if diff := cmp.Diff(expectedErr, actualErr); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expectedErr, actualErr, diff)
|
|
}
|
|
|
|
actualOut := output.Stdout()
|
|
expectedOut := `main.tftest.hcl... in progress
|
|
defaults... pass
|
|
|
|
Interrupt received.
|
|
Please wait for Terraform to exit or data loss may occur.
|
|
Gracefully shutting down...
|
|
|
|
|
|
Two interrupts received. Exiting immediately. Note that data loss may have occurred.
|
|
|
|
overrides... fail
|
|
╷
|
|
│ Error: Test interrupted
|
|
│
|
|
│ The test operation could not be completed due to an interrupt signal.
|
|
│ Please read the remaining diagnostics carefully for any sign of failed
|
|
│ state cleanup or dangling resources.
|
|
╵
|
|
╷
|
|
│ Error: Create time sleep error
|
|
│
|
|
│ with time_sleep.wait_5_seconds,
|
|
│ on main.tf line 7, in resource "time_sleep" "wait_5_seconds":
|
|
│ 7: resource "time_sleep" "wait_5_seconds" {
|
|
│
|
|
│ Original Error: context canceled
|
|
╵
|
|
╷
|
|
│ Error: execution halted
|
|
│
|
|
╵
|
|
╷
|
|
│ Error: execution halted
|
|
│
|
|
╵
|
|
main.tftest.hcl... tearing down
|
|
main.tftest.hcl... fail
|
|
|
|
Failure! 1 passed, 1 failed.
|
|
`
|
|
|
|
if diff := cmp.Diff(expectedOut, actualOut); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expectedOut, actualOut, diff)
|
|
}
|
|
|
|
// We want to make sure the cancel signal actually made it through.
|
|
// Luckily we can access the test runs directly in the mock client.
|
|
tr := mock.TestRuns.modules[module.ID][0]
|
|
if tr.Status != tfe.TestRunCanceled {
|
|
t.Errorf("expected test run to have been cancelled but was %s", tr.Status)
|
|
}
|
|
|
|
if mock.TestRuns.cancels != 2 {
|
|
t.Errorf("incorrect number of cancels, expected 2 but was %d", mock.TestRuns.cancels)
|
|
}
|
|
}
|
|
|
|
func TestTest_LongRunningTest(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
if _, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
}); err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test-long-running",
|
|
TestingDirectory: "tests",
|
|
Config: nil, // We don't need this for this test.
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: context.Background(),
|
|
CancelledCtx: context.Background(),
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: &jsonformat.Renderer{
|
|
Streams: streams,
|
|
Colorize: colorize,
|
|
RunningInAutomation: false,
|
|
},
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
_, diags := runner.Test()
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := done(t)
|
|
actual := output.All()
|
|
|
|
// The long running test logs actually contain additional progress updates,
|
|
// but this test should ignore them and just show the usual output.
|
|
|
|
expected := `main.tftest.hcl... in progress
|
|
just_go... pass
|
|
main.tftest.hcl... tearing down
|
|
main.tftest.hcl... pass
|
|
|
|
Success! 1 passed, 0 failed.
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
}
|
|
|
|
func TestTest_LongRunningTestJSON(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
view := views.NewTest(arguments.ViewHuman, views.NewView(streams))
|
|
|
|
colorize := mockColorize()
|
|
colorize.Disable = true
|
|
|
|
mock := NewMockClient()
|
|
client := &tfe.Client{
|
|
ConfigurationVersions: mock.ConfigurationVersions,
|
|
Organizations: mock.Organizations,
|
|
RegistryModules: mock.RegistryModules,
|
|
TestRuns: mock.TestRuns,
|
|
}
|
|
|
|
if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("organisation"),
|
|
}); err != nil {
|
|
t.Fatalf("failed to create organisation: %v", err)
|
|
}
|
|
|
|
if _, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{
|
|
Name: tfe.String("name"),
|
|
Provider: tfe.String("provider"),
|
|
RegistryName: "app.terraform.io",
|
|
Namespace: "organisation",
|
|
}); err != nil {
|
|
t.Fatalf("failed to create registry module: %v", err)
|
|
}
|
|
|
|
runner := TestSuiteRunner{
|
|
// Configuration data.
|
|
ConfigDirectory: "testdata/test-long-running",
|
|
TestingDirectory: "tests",
|
|
Config: nil, // We don't need this for this test.
|
|
Source: "app.terraform.io/organisation/name/provider",
|
|
|
|
// Cancellation controls, we won't be doing any cancellations in this
|
|
// test.
|
|
Stopped: false,
|
|
Cancelled: false,
|
|
StoppedCtx: context.Background(),
|
|
CancelledCtx: context.Background(),
|
|
|
|
// Test Options, empty for this test.
|
|
GlobalVariables: nil,
|
|
Verbose: false,
|
|
Filters: nil,
|
|
|
|
// Outputs
|
|
Renderer: nil, // This should force the logs to render as JSON.
|
|
View: view,
|
|
Streams: streams,
|
|
|
|
// Networking
|
|
Services: nil, // Don't need this when the client is overridden.
|
|
clientOverride: client,
|
|
}
|
|
|
|
_, diags := runner.Test()
|
|
if len(diags) > 0 {
|
|
t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings())
|
|
}
|
|
|
|
output := done(t)
|
|
actual := output.All()
|
|
|
|
// This test should still include the progress updates as we're doing the
|
|
// JSON output.
|
|
|
|
expected := `{"@level":"info","@message":"Terraform 1.7.0-dev","@module":"terraform.ui","@timestamp":"2023-09-28T14:57:09.175210+02:00","terraform":"1.7.0-dev","type":"version","ui":"1.2"}
|
|
{"@level":"info","@message":"Found 1 file and 1 run block","@module":"terraform.ui","@timestamp":"2023-09-28T14:57:09.189212+02:00","test_abstract":{"main.tftest.hcl":["just_go"]},"type":"test_abstract"}
|
|
{"@level":"info","@message":"main.tftest.hcl... in progress","@module":"terraform.ui","@testfile":"main.tftest.hcl","@timestamp":"2023-09-28T14:57:09.189386+02:00","test_file":{"path":"main.tftest.hcl","progress":"starting"},"type":"test_file"}
|
|
{"@level":"info","@message":" \"just_go\"... in progress","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"just_go","@timestamp":"2023-09-28T14:57:09.189429+02:00","test_run":{"path":"main.tftest.hcl","run":"just_go","progress":"starting","elapsed":0},"type":"test_run"}
|
|
{"@level":"info","@message":" \"just_go\"... in progress","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"just_go","@timestamp":"2023-09-28T14:57:11.341278+02:00","test_run":{"path":"main.tftest.hcl","run":"just_go","progress":"running","elapsed":2152},"type":"test_run"}
|
|
{"@level":"info","@message":" \"just_go\"... in progress","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"just_go","@timestamp":"2023-09-28T14:57:13.343465+02:00","test_run":{"path":"main.tftest.hcl","run":"just_go","progress":"running","elapsed":4154},"type":"test_run"}
|
|
{"@level":"info","@message":" \"just_go\"... pass","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"just_go","@timestamp":"2023-09-28T14:57:14.381552+02:00","test_run":{"path":"main.tftest.hcl","run":"just_go","progress":"complete","status":"pass"},"type":"test_run"}
|
|
{"@level":"info","@message":"main.tftest.hcl... tearing down","@module":"terraform.ui","@testfile":"main.tftest.hcl","@timestamp":"2023-09-28T14:57:14.381655+02:00","test_file":{"path":"main.tftest.hcl","progress":"teardown"},"type":"test_file"}
|
|
{"@level":"info","@message":" \"just_go\"... tearing down","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"just_go","@timestamp":"2023-09-28T14:57:14.381712+02:00","test_run":{"path":"main.tftest.hcl","run":"just_go","progress":"teardown","elapsed":0},"type":"test_run"}
|
|
{"@level":"info","@message":" \"just_go\"... tearing down","@module":"terraform.ui","@testfile":"main.tftest.hcl","@testrun":"just_go","@timestamp":"2023-09-28T14:57:16.477705+02:00","test_run":{"path":"main.tftest.hcl","run":"just_go","progress":"teardown","elapsed":2096},"type":"test_run"}
|
|
{"@level":"info","@message":"main.tftest.hcl... pass","@module":"terraform.ui","@testfile":"main.tftest.hcl","@timestamp":"2023-09-28T14:57:17.517309+02:00","test_file":{"path":"main.tftest.hcl","progress":"complete","status":"pass"},"type":"test_file"}
|
|
{"@level":"info","@message":"Success! 1 passed, 0 failed.","@module":"terraform.ui","@timestamp":"2023-09-28T14:57:17.517494+02:00","test_summary":{"status":"pass","passed":1,"failed":0,"errored":0,"skipped":0},"type":"test_summary"}
|
|
`
|
|
|
|
if diff := cmp.Diff(expected, actual); len(diff) > 0 {
|
|
t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
|
|
}
|
|
}
|