2021-02-12 02:52:10 +01:00
|
|
|
package views
|
2017-03-01 23:16:22 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-07-13 22:01:19 +02:00
|
|
|
"regexp"
|
2017-03-01 23:16:22 +01:00
|
|
|
"testing"
|
2017-03-13 21:09:25 +01:00
|
|
|
"time"
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
"strings"
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2021-05-17 21:00:50 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
2021-05-17 21:07:38 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/command/arguments"
|
2021-05-17 21:33:17 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/plans"
|
2021-05-17 19:40:40 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/providers"
|
2021-05-17 21:43:35 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/states"
|
2021-02-12 02:52:10 +01:00
|
|
|
"github.com/hashicorp/terraform/internal/terminal"
|
2021-05-17 21:46:19 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/terraform"
|
2017-03-01 23:16:22 +01:00
|
|
|
)
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
// Test the PreApply hook for creating a new resource
|
|
|
|
func TestUiHookPreApply_create(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
h.resources = map[string]uiResourceState{
|
|
|
|
"test_instance.foo": {
|
|
|
|
Op: uiResourceCreate,
|
|
|
|
Start: time.Now(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
priorState := cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"id": cty.String,
|
|
|
|
"bar": cty.List(cty.String),
|
|
|
|
}))
|
|
|
|
plannedNewState := cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("test"),
|
|
|
|
"bar": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("baz"),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
|
|
|
|
action, err := h.PreApply(addr, states.CurrentGen, plans.Create, priorState, plannedNewState)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
|
|
|
|
// stop the background writer
|
|
|
|
uiState := h.resources[addr.String()]
|
|
|
|
close(uiState.DoneCh)
|
|
|
|
<-uiState.done
|
|
|
|
|
|
|
|
expectedOutput := "test_instance.foo: Creating...\n"
|
|
|
|
result := done(t)
|
|
|
|
output := result.Stdout()
|
|
|
|
if output != expectedOutput {
|
|
|
|
t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedErrOutput := ""
|
|
|
|
errOutput := result.Stderr()
|
|
|
|
if errOutput != expectedErrOutput {
|
|
|
|
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test the PreApply hook's use of a periodic timer to display "still working"
|
|
|
|
// log lines
|
2017-03-13 21:09:25 +01:00
|
|
|
func TestUiHookPreApply_periodicTimer(t *testing.T) {
|
2021-02-12 02:52:10 +01:00
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
h.periodicUiTimer = 1 * time.Second
|
2017-03-13 21:09:25 +01:00
|
|
|
h.resources = map[string]uiResourceState{
|
2021-02-16 17:33:03 +01:00
|
|
|
"test_instance.foo": {
|
|
|
|
Op: uiResourceModify,
|
2017-03-13 21:09:25 +01:00
|
|
|
Start: time.Now(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
addr := addrs.Resource{
|
2021-02-16 17:33:03 +01:00
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
2018-10-13 19:47:46 +02:00
|
|
|
priorState := cty.ObjectVal(map[string]cty.Value{
|
2021-02-16 17:33:03 +01:00
|
|
|
"id": cty.StringVal("test"),
|
|
|
|
"bar": cty.ListValEmpty(cty.String),
|
|
|
|
})
|
|
|
|
plannedNewState := cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("test"),
|
|
|
|
"bar": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("baz"),
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
}),
|
|
|
|
})
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
action, err := h.PreApply(addr, states.CurrentGen, plans.Update, priorState, plannedNewState)
|
2017-03-13 21:09:25 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(3100 * time.Millisecond)
|
|
|
|
|
2017-03-17 16:04:27 +01:00
|
|
|
// stop the background writer
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
uiState := h.resources[addr.String()]
|
2017-03-17 16:04:27 +01:00
|
|
|
close(uiState.DoneCh)
|
|
|
|
<-uiState.done
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
expectedOutput := `test_instance.foo: Modifying... [id=test]
|
|
|
|
test_instance.foo: Still modifying... [id=test, 1s elapsed]
|
|
|
|
test_instance.foo: Still modifying... [id=test, 2s elapsed]
|
|
|
|
test_instance.foo: Still modifying... [id=test, 3s elapsed]
|
2017-03-13 21:09:25 +01:00
|
|
|
`
|
2021-02-12 02:52:10 +01:00
|
|
|
result := done(t)
|
|
|
|
output := result.Stdout()
|
2017-03-13 21:09:25 +01:00
|
|
|
if output != expectedOutput {
|
|
|
|
t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedErrOutput := ""
|
2021-02-12 02:52:10 +01:00
|
|
|
errOutput := result.Stderr()
|
2017-03-13 21:09:25 +01:00
|
|
|
if errOutput != expectedErrOutput {
|
|
|
|
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
// Test the PreApply hook's destroy path, including passing a deposed key as
|
|
|
|
// the gen argument.
|
2017-03-13 21:09:25 +01:00
|
|
|
func TestUiHookPreApply_destroy(t *testing.T) {
|
2021-02-12 02:52:10 +01:00
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
2017-03-13 21:09:25 +01:00
|
|
|
h.resources = map[string]uiResourceState{
|
2021-02-16 17:33:03 +01:00
|
|
|
"test_instance.foo": {
|
2017-03-13 21:09:25 +01:00
|
|
|
Op: uiResourceDestroy,
|
|
|
|
Start: time.Now(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
addr := addrs.Resource{
|
2021-02-16 17:33:03 +01:00
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
2018-10-13 19:47:46 +02:00
|
|
|
priorState := cty.ObjectVal(map[string]cty.Value{
|
2021-02-16 17:33:03 +01:00
|
|
|
"id": cty.StringVal("abc123"),
|
|
|
|
"verbs": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("boop"),
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
}),
|
|
|
|
})
|
2018-10-13 19:47:46 +02:00
|
|
|
plannedNewState := cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"id": cty.String,
|
2021-02-16 17:33:03 +01:00
|
|
|
"verbs": cty.List(cty.String),
|
2018-10-13 19:47:46 +02:00
|
|
|
}))
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
key := states.NewDeposedKey()
|
|
|
|
action, err := h.PreApply(addr, key, plans.Delete, priorState, plannedNewState)
|
2017-03-13 21:09:25 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
// stop the background writer
|
|
|
|
uiState := h.resources[addr.String()]
|
|
|
|
close(uiState.DoneCh)
|
|
|
|
<-uiState.done
|
|
|
|
|
2021-02-12 02:52:10 +01:00
|
|
|
result := done(t)
|
2021-05-13 00:18:25 +02:00
|
|
|
expectedOutput := fmt.Sprintf("test_instance.foo (deposed object %s): Destroying... [id=abc123]\n", key)
|
2021-02-12 02:52:10 +01:00
|
|
|
output := result.Stdout()
|
2017-03-13 21:09:25 +01:00
|
|
|
if output != expectedOutput {
|
|
|
|
t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedErrOutput := ""
|
2021-02-12 02:52:10 +01:00
|
|
|
errOutput := result.Stderr()
|
2017-03-13 21:09:25 +01:00
|
|
|
if errOutput != expectedErrOutput {
|
|
|
|
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
// Verify that colorize is called on format strings, not user input, by adding
|
|
|
|
// valid color codes as resource names and IDs.
|
|
|
|
func TestUiHookPostApply_colorInterpolation(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
view.Configure(&arguments.View{NoColor: false})
|
|
|
|
h := NewUiHook(view)
|
|
|
|
h.resources = map[string]uiResourceState{
|
|
|
|
"test_instance.foo[\"[red]\"]": {
|
|
|
|
Op: uiResourceCreate,
|
|
|
|
Start: time.Now(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.StringKey("[red]")).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
newState := cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("[blue]"),
|
|
|
|
})
|
|
|
|
|
|
|
|
action, err := h.PostApply(addr, states.CurrentGen, newState, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
reset := "\x1b[0m"
|
|
|
|
bold := "\x1b[1m"
|
|
|
|
wantPrefix := reset + bold + `test_instance.foo["[red]"]: Creation complete after`
|
|
|
|
wantSuffix := "[id=[blue]]" + reset + "\n"
|
|
|
|
output := result.Stdout()
|
|
|
|
|
|
|
|
if !strings.HasPrefix(output, wantPrefix) {
|
|
|
|
t.Fatalf("wrong output prefix\n got: %#v\nwant: %#v", output, wantPrefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.HasSuffix(output, wantSuffix) {
|
|
|
|
t.Fatalf("wrong output suffix\n got: %#v\nwant: %#v", output, wantSuffix)
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedErrOutput := ""
|
|
|
|
errOutput := result.Stderr()
|
|
|
|
if errOutput != expectedErrOutput {
|
|
|
|
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that the PostApply hook renders a total time.
|
2017-03-13 21:09:25 +01:00
|
|
|
func TestUiHookPostApply_emptyState(t *testing.T) {
|
2021-02-12 02:52:10 +01:00
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
2017-03-13 21:09:25 +01:00
|
|
|
h.resources = map[string]uiResourceState{
|
2021-02-16 17:33:03 +01:00
|
|
|
"data.google_compute_zones.available": {
|
2017-03-13 21:09:25 +01:00
|
|
|
Op: uiResourceDestroy,
|
|
|
|
Start: time.Now(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.DataResourceMode,
|
|
|
|
Type: "google_compute_zones",
|
|
|
|
Name: "available",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
newState := cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"id": cty.String,
|
|
|
|
"names": cty.List(cty.String),
|
|
|
|
}))
|
|
|
|
|
|
|
|
action, err := h.PostApply(addr, states.CurrentGen, newState, nil)
|
2017-03-13 21:09:25 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
2021-02-12 02:52:10 +01:00
|
|
|
result := done(t)
|
2017-03-13 21:09:25 +01:00
|
|
|
|
2019-01-31 13:25:57 +01:00
|
|
|
expectedRegexp := "^data.google_compute_zones.available: Destruction complete after -?[a-z0-9µ.]+\n$"
|
2021-02-12 02:52:10 +01:00
|
|
|
output := result.Stdout()
|
2017-07-13 22:01:19 +02:00
|
|
|
if matched, _ := regexp.MatchString(expectedRegexp, output); !matched {
|
|
|
|
t.Fatalf("Output didn't match regexp.\nExpected: %q\nGiven: %q", expectedRegexp, output)
|
2017-03-13 21:09:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
expectedErrOutput := ""
|
2021-02-12 02:52:10 +01:00
|
|
|
errOutput := result.Stderr()
|
2017-03-13 21:09:25 +01:00
|
|
|
if errOutput != expectedErrOutput {
|
|
|
|
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 17:33:03 +01:00
|
|
|
func TestPreProvisionInstanceStep(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
action, err := h.PreProvisionInstanceStep(addr, "local-exec")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
if got, want := result.Stdout(), "test_instance.foo: Provisioning with 'local-exec'...\n"; got != want {
|
|
|
|
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test ProvisionOutput, including lots of edge cases for the output
|
|
|
|
// whitespace/line ending logic.
|
|
|
|
func TestProvisionOutput(t *testing.T) {
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
provisioner string
|
|
|
|
input string
|
|
|
|
wantOutput string
|
|
|
|
}{
|
|
|
|
"single line": {
|
|
|
|
"local-exec",
|
|
|
|
"foo\n",
|
|
|
|
"test_instance.foo (local-exec): foo\n",
|
|
|
|
},
|
|
|
|
"multiple lines": {
|
|
|
|
"x",
|
|
|
|
`foo
|
|
|
|
bar
|
|
|
|
baz
|
|
|
|
`,
|
|
|
|
`test_instance.foo (x): foo
|
|
|
|
test_instance.foo (x): bar
|
|
|
|
test_instance.foo (x): baz
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"trailing whitespace": {
|
|
|
|
"x",
|
|
|
|
"foo \nbar\n",
|
|
|
|
"test_instance.foo (x): foo\ntest_instance.foo (x): bar\n",
|
|
|
|
},
|
|
|
|
"blank lines": {
|
|
|
|
"x",
|
|
|
|
"foo\n\nbar\n\n\nbaz\n",
|
|
|
|
`test_instance.foo (x): foo
|
|
|
|
test_instance.foo (x): bar
|
|
|
|
test_instance.foo (x): baz
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"no final newline": {
|
|
|
|
"x",
|
|
|
|
`foo
|
|
|
|
bar`,
|
|
|
|
`test_instance.foo (x): foo
|
|
|
|
test_instance.foo (x): bar
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"CR, no LF": {
|
|
|
|
"MacOS 9?",
|
|
|
|
"foo\rbar\r",
|
|
|
|
`test_instance.foo (MacOS 9?): foo
|
|
|
|
test_instance.foo (MacOS 9?): bar
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"CRLF": {
|
|
|
|
"winrm",
|
|
|
|
"foo\r\nbar\r\n",
|
|
|
|
`test_instance.foo (winrm): foo
|
|
|
|
test_instance.foo (winrm): bar
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
|
|
|
|
h.ProvisionOutput(addr, tc.provisioner, tc.input)
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
if got := result.Stdout(); got != tc.wantOutput {
|
|
|
|
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, tc.wantOutput)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test the PreRefresh hook in the normal path where the resource exists with
|
|
|
|
// an ID key and value in the state.
|
|
|
|
func TestPreRefresh(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
priorState := cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("test"),
|
|
|
|
"bar": cty.ListValEmpty(cty.String),
|
|
|
|
})
|
|
|
|
|
|
|
|
action, err := h.PreRefresh(addr, states.CurrentGen, priorState)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
if got, want := result.Stdout(), "test_instance.foo: Refreshing state... [id=test]\n"; got != want {
|
|
|
|
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that PreRefresh still works if no ID key and value can be determined
|
|
|
|
// from state.
|
|
|
|
func TestPreRefresh_noID(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
priorState := cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.ListValEmpty(cty.String),
|
|
|
|
})
|
|
|
|
|
|
|
|
action, err := h.PreRefresh(addr, states.CurrentGen, priorState)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
if got, want := result.Stdout(), "test_instance.foo: Refreshing state...\n"; got != want {
|
|
|
|
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test the very simple PreImportState hook.
|
|
|
|
func TestPreImportState(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
action, err := h.PreImportState(addr, "test")
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
if got, want := result.Stdout(), "test_instance.foo: Importing from ID \"test\"...\n"; got != want {
|
|
|
|
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test the PostImportState UI hook. Again, this hook behaviour seems odd to
|
|
|
|
// me (see below), so please don't consider these tests as justification for
|
|
|
|
// keeping this behaviour.
|
|
|
|
func TestPostImportState(t *testing.T) {
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
|
|
view := NewView(streams)
|
|
|
|
h := NewUiHook(view)
|
|
|
|
|
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
// The "Prepared [...] for import" lines display the type name of each of
|
|
|
|
// the imported resources passed to the hook. I'm not sure how it's
|
|
|
|
// possible for an import to result in a different resource type name than
|
|
|
|
// the target address, but the hook works like this so we're covering it.
|
|
|
|
imported := []providers.ImportedResource{
|
|
|
|
{
|
|
|
|
TypeName: "test_some_instance",
|
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("test"),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
TypeName: "test_other_instance",
|
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("test"),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
action, err := h.PostImportState(addr, imported)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("Expected hook to continue, given: %#v", action)
|
|
|
|
}
|
|
|
|
result := done(t)
|
|
|
|
|
|
|
|
want := `test_instance.foo: Import prepared!
|
|
|
|
Prepared test_some_instance for import
|
|
|
|
Prepared test_other_instance for import
|
|
|
|
`
|
|
|
|
if got := result.Stdout(); got != want {
|
|
|
|
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 23:16:22 +01:00
|
|
|
func TestTruncateId(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
Input string
|
|
|
|
Expected string
|
|
|
|
MaxLen int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "H...d",
|
|
|
|
MaxLen: 3,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "H...d",
|
|
|
|
MaxLen: 5,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "He...d",
|
|
|
|
MaxLen: 6,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "He...ld",
|
|
|
|
MaxLen: 7,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "Hel...ld",
|
|
|
|
MaxLen: 8,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "Hel...rld",
|
|
|
|
MaxLen: 9,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "Hell...rld",
|
|
|
|
MaxLen: 10,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "Hello world",
|
|
|
|
MaxLen: 11,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "Hello world",
|
|
|
|
Expected: "Hello world",
|
|
|
|
MaxLen: 12,
|
|
|
|
},
|
2018-09-09 17:21:24 +02:00
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あ...さ",
|
|
|
|
MaxLen: 3,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あ...さ",
|
|
|
|
MaxLen: 5,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あい...さ",
|
|
|
|
MaxLen: 6,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あい...こさ",
|
|
|
|
MaxLen: 7,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あいう...こさ",
|
|
|
|
MaxLen: 8,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あいう...けこさ",
|
|
|
|
MaxLen: 9,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あいうえ...けこさ",
|
|
|
|
MaxLen: 10,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あいうえおかきくけこさ",
|
|
|
|
MaxLen: 11,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Input: "あいうえおかきくけこさ",
|
|
|
|
Expected: "あいうえおかきくけこさ",
|
|
|
|
MaxLen: 12,
|
|
|
|
},
|
2017-03-01 23:16:22 +01:00
|
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
|
|
testName := fmt.Sprintf("%d", i)
|
|
|
|
t.Run(testName, func(t *testing.T) {
|
|
|
|
out := truncateId(tc.Input, tc.MaxLen)
|
|
|
|
if out != tc.Expected {
|
|
|
|
t.Fatalf("Expected %q to be shortened to %d as %q (given: %q)",
|
|
|
|
tc.Input, tc.MaxLen, tc.Expected, out)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|