mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
d818d7850d
* Use the new renderer when rendering the state * remove confusing and unneeded comment
438 lines
10 KiB
Go
438 lines
10 KiB
Go
package jsonformat
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/mitchellh/colorstring"
|
|
|
|
"github.com/hashicorp/terraform/internal/command/format"
|
|
"github.com/hashicorp/terraform/internal/command/jsonprovider"
|
|
"github.com/hashicorp/terraform/internal/command/jsonstate"
|
|
"github.com/hashicorp/terraform/internal/states/statefile"
|
|
"github.com/hashicorp/terraform/internal/terminal"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
|
"github.com/hashicorp/terraform/internal/configs/configschema"
|
|
"github.com/hashicorp/terraform/internal/providers"
|
|
"github.com/hashicorp/terraform/internal/states"
|
|
"github.com/hashicorp/terraform/internal/terraform"
|
|
)
|
|
|
|
func TestState(t *testing.T) {
|
|
color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
|
|
|
|
tests := []struct {
|
|
State *format.StateOpts
|
|
Want string
|
|
}{
|
|
{
|
|
&format.StateOpts{
|
|
State: &states.State{},
|
|
Color: color,
|
|
Schemas: &terraform.Schemas{},
|
|
},
|
|
"The state file is empty. No resources are represented.\n",
|
|
},
|
|
{
|
|
&format.StateOpts{
|
|
State: basicState(t),
|
|
Color: color,
|
|
Schemas: testSchemas(),
|
|
},
|
|
basicStateOutput,
|
|
},
|
|
{
|
|
&format.StateOpts{
|
|
State: nestedState(t),
|
|
Color: color,
|
|
Schemas: testSchemas(),
|
|
},
|
|
nestedStateOutput,
|
|
},
|
|
{
|
|
&format.StateOpts{
|
|
State: deposedState(t),
|
|
Color: color,
|
|
Schemas: testSchemas(),
|
|
},
|
|
deposedNestedStateOutput,
|
|
},
|
|
{
|
|
&format.StateOpts{
|
|
State: onlyDeposedState(t),
|
|
Color: color,
|
|
Schemas: testSchemas(),
|
|
},
|
|
onlyDeposedOutput,
|
|
},
|
|
{
|
|
&format.StateOpts{
|
|
State: stateWithMoreOutputs(t),
|
|
Color: color,
|
|
Schemas: testSchemas(),
|
|
},
|
|
stateWithMoreOutputsOutput,
|
|
},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
|
|
|
root, outputs, err := jsonstate.MarshalForRenderer(&statefile.File{
|
|
State: tt.State.State,
|
|
}, tt.State.Schemas)
|
|
|
|
if err != nil {
|
|
t.Errorf("found err: %v", err)
|
|
return
|
|
}
|
|
|
|
streams, done := terminal.StreamsForTesting(t)
|
|
renderer := Renderer{
|
|
Colorize: color,
|
|
Streams: streams,
|
|
}
|
|
|
|
renderer.RenderHumanState(State{
|
|
StateFormatVersion: jsonstate.FormatVersion,
|
|
RootModule: root,
|
|
RootModuleOutputs: outputs,
|
|
ProviderFormatVersion: jsonprovider.FormatVersion,
|
|
ProviderSchemas: jsonprovider.MarshalForRenderer(tt.State.Schemas),
|
|
})
|
|
|
|
result := done(t).All()
|
|
if diff := cmp.Diff(result, tt.Want); diff != "" {
|
|
t.Errorf("wrong output\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", tt.Want, result, diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func testProvider() *terraform.MockProvider {
|
|
p := new(terraform.MockProvider)
|
|
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
|
|
return providers.ReadResourceResponse{NewState: req.PriorState}
|
|
}
|
|
|
|
p.GetProviderSchemaResponse = testProviderSchema()
|
|
|
|
return p
|
|
}
|
|
|
|
func testProviderSchema() *providers.GetProviderSchemaResponse {
|
|
return &providers.GetProviderSchemaResponse{
|
|
Provider: providers.Schema{
|
|
Block: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"region": {Type: cty.String, Optional: true},
|
|
},
|
|
},
|
|
},
|
|
ResourceTypes: map[string]providers.Schema{
|
|
"test_resource": {
|
|
Block: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"id": {Type: cty.String, Computed: true},
|
|
"foo": {Type: cty.String, Optional: true},
|
|
"woozles": {Type: cty.String, Optional: true},
|
|
},
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"nested": {
|
|
Nesting: configschema.NestingList,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"compute": {Type: cty.String, Optional: true},
|
|
"value": {Type: cty.String, Optional: true},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
DataSources: map[string]providers.Schema{
|
|
"test_data_source": {
|
|
Block: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"compute": {Type: cty.String, Optional: true},
|
|
"value": {Type: cty.String, Computed: true},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func testSchemas() *terraform.Schemas {
|
|
provider := testProvider()
|
|
return &terraform.Schemas{
|
|
Providers: map[addrs.Provider]*terraform.ProviderSchema{
|
|
addrs.NewDefaultProvider("test"): provider.ProviderSchema(),
|
|
},
|
|
}
|
|
}
|
|
|
|
const basicStateOutput = `# data.test_data_source.data:
|
|
data "test_data_source" "data" {
|
|
compute = "sure"
|
|
}
|
|
|
|
# test_resource.baz[0]:
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
}
|
|
|
|
|
|
Outputs:
|
|
|
|
bar = "bar value"
|
|
`
|
|
|
|
const nestedStateOutput = `# test_resource.baz[0]:
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
|
|
nested {
|
|
value = "42"
|
|
}
|
|
}
|
|
`
|
|
|
|
const deposedNestedStateOutput = `# test_resource.baz[0]:
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
|
|
nested {
|
|
value = "42"
|
|
}
|
|
}
|
|
|
|
# test_resource.baz[0]: (deposed object 1234)
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
|
|
nested {
|
|
value = "42"
|
|
}
|
|
}
|
|
`
|
|
|
|
const onlyDeposedOutput = `# test_resource.baz[0]: (deposed object 1234)
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
|
|
nested {
|
|
value = "42"
|
|
}
|
|
}
|
|
|
|
# test_resource.baz[0]: (deposed object 5678)
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
|
|
nested {
|
|
value = "42"
|
|
}
|
|
}
|
|
`
|
|
|
|
const stateWithMoreOutputsOutput = `# test_resource.baz[0]:
|
|
resource "test_resource" "baz" {
|
|
woozles = "confuzles"
|
|
}
|
|
|
|
|
|
Outputs:
|
|
|
|
bool_var = true
|
|
int_var = 42
|
|
map_var = {
|
|
"first" = "foo"
|
|
"second" = "bar"
|
|
}
|
|
sensitive_var = (sensitive value)
|
|
string_var = "string value"
|
|
`
|
|
|
|
func basicState(t *testing.T) *states.State {
|
|
state := states.NewState()
|
|
|
|
rootModule := state.RootModule()
|
|
if rootModule == nil {
|
|
t.Errorf("root module is nil; want valid object")
|
|
}
|
|
|
|
rootModule.SetLocalValue("foo", cty.StringVal("foo value"))
|
|
rootModule.SetOutputValue("bar", cty.StringVal("bar value"), false)
|
|
rootModule.SetResourceInstanceCurrent(
|
|
addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "baz",
|
|
}.Instance(addrs.IntKey(0)),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
rootModule.SetResourceInstanceCurrent(
|
|
addrs.Resource{
|
|
Mode: addrs.DataResourceMode,
|
|
Type: "test_data_source",
|
|
Name: "data",
|
|
}.Instance(addrs.NoKey),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"compute":"sure"}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
return state
|
|
}
|
|
|
|
func stateWithMoreOutputs(t *testing.T) *states.State {
|
|
state := states.NewState()
|
|
|
|
rootModule := state.RootModule()
|
|
if rootModule == nil {
|
|
t.Errorf("root module is nil; want valid object")
|
|
}
|
|
|
|
rootModule.SetOutputValue("string_var", cty.StringVal("string value"), false)
|
|
rootModule.SetOutputValue("int_var", cty.NumberIntVal(42), false)
|
|
rootModule.SetOutputValue("bool_var", cty.BoolVal(true), false)
|
|
rootModule.SetOutputValue("sensitive_var", cty.StringVal("secret!!!"), true)
|
|
rootModule.SetOutputValue("map_var", cty.MapVal(map[string]cty.Value{
|
|
"first": cty.StringVal("foo"),
|
|
"second": cty.StringVal("bar"),
|
|
}), false)
|
|
|
|
rootModule.SetResourceInstanceCurrent(
|
|
addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "baz",
|
|
}.Instance(addrs.IntKey(0)),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
return state
|
|
}
|
|
|
|
func nestedState(t *testing.T) *states.State {
|
|
state := states.NewState()
|
|
|
|
rootModule := state.RootModule()
|
|
if rootModule == nil {
|
|
t.Errorf("root module is nil; want valid object")
|
|
}
|
|
|
|
rootModule.SetResourceInstanceCurrent(
|
|
addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "baz",
|
|
}.Instance(addrs.IntKey(0)),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
return state
|
|
}
|
|
|
|
func deposedState(t *testing.T) *states.State {
|
|
state := nestedState(t)
|
|
rootModule := state.RootModule()
|
|
rootModule.SetResourceInstanceDeposed(
|
|
addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "baz",
|
|
}.Instance(addrs.IntKey(0)),
|
|
states.DeposedKey("1234"),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
return state
|
|
}
|
|
|
|
// replicate a corrupt resource where only a deposed exists
|
|
func onlyDeposedState(t *testing.T) *states.State {
|
|
state := states.NewState()
|
|
|
|
rootModule := state.RootModule()
|
|
if rootModule == nil {
|
|
t.Errorf("root module is nil; want valid object")
|
|
}
|
|
|
|
rootModule.SetResourceInstanceDeposed(
|
|
addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "baz",
|
|
}.Instance(addrs.IntKey(0)),
|
|
states.DeposedKey("1234"),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
rootModule.SetResourceInstanceDeposed(
|
|
addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "baz",
|
|
}.Instance(addrs.IntKey(0)),
|
|
states.DeposedKey("5678"),
|
|
&states.ResourceInstanceObjectSrc{
|
|
Status: states.ObjectReady,
|
|
SchemaVersion: 0,
|
|
AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`),
|
|
},
|
|
addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
)
|
|
return state
|
|
}
|