command/show: tests for -json output (#19980)
* command/show: added test scaffold for json output More test cases will be added once the basic shape of the tests is validated. - command/json* packages now sort resources by address, matching behavior elsewhere - using cmp in tests instead of reflect.DeepEqual for the diffs - updating expected output in tests to match sorting
This commit is contained in:
parent
e168d81894
commit
5df9cd0f52
|
@ -3,6 +3,7 @@ package jsonconfig
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
|
@ -244,5 +245,8 @@ func marshalResources(resources map[string]*configs.Resource, schemas *terraform
|
|||
|
||||
rs = append(rs, r)
|
||||
}
|
||||
sort.Slice(rs, func(i, j int) bool {
|
||||
return rs[i].Address < rs[j].Address
|
||||
})
|
||||
return rs, nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package jsonplan
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
|
@ -210,6 +211,10 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
|||
|
||||
}
|
||||
|
||||
sort.Slice(p.ResourceChanges, func(i, j int) bool {
|
||||
return p.ResourceChanges[i].Address < p.ResourceChanges[j].Address
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,8 @@ func marshalAttributeValues(value cty.Value, schema *configschema.Block) attribu
|
|||
return ret
|
||||
}
|
||||
|
||||
// marshalPlannedOutputs takes a list of changes and returns two output maps,
|
||||
// the former with output values and the latter with true/false in place of
|
||||
// values indicating whether the values are known at plan time.
|
||||
// marshalPlannedOutputs takes a list of changes and returns a map of output
|
||||
// values
|
||||
func marshalPlannedOutputs(changes *plans.Changes) (map[string]output, error) {
|
||||
if changes.Outputs == nil {
|
||||
// No changes - we're done here!
|
||||
|
|
|
@ -3,6 +3,7 @@ package jsonstate
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||
|
@ -273,5 +274,9 @@ func marshalResources(resources map[string]*states.Resource, schemas *terraform.
|
|||
|
||||
}
|
||||
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
return ret[i].Address < ret[j].Address
|
||||
})
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
|
@ -150,6 +154,92 @@ func TestShow_state(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPlan_json_output(t *testing.T) {
|
||||
fixtureDir := "test-fixtures/show-json"
|
||||
testDirs, err := ioutil.ReadDir(fixtureDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, entry := range testDirs {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(entry.Name(), func(t *testing.T) {
|
||||
inputDir := filepath.Join(fixtureDir, entry.Name())
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if err := os.Chdir(inputDir); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Chdir(cwd)
|
||||
|
||||
p := showFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
pc := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-out=terraform.plan",
|
||||
}
|
||||
|
||||
if code := pc.Run(args); code != 0 {
|
||||
t.Fatalf("wrong exit status %d; want 0\nstderr: %s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// flush the plan output from the mock ui
|
||||
ui.OutputWriter.Reset()
|
||||
sc := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
args = []string{
|
||||
"-json",
|
||||
"terraform.plan",
|
||||
}
|
||||
defer os.Remove("terraform.plan")
|
||||
|
||||
if code := sc.Run(args); code != 0 {
|
||||
t.Fatalf("wrong exit status %d; want 0\nstderr: %s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// compare ui output to wanted output
|
||||
var got, want plan
|
||||
|
||||
gotString := ui.OutputWriter.String()
|
||||
json.Unmarshal([]byte(gotString), &got)
|
||||
|
||||
wantFile, err := os.Open("output.json")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer wantFile.Close()
|
||||
byteValue, err := ioutil.ReadAll(wantFile)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
json.Unmarshal([]byte(byteValue), &want)
|
||||
|
||||
if !cmp.Equal(got, want) {
|
||||
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// showFixtureSchema returns a schema suitable for processing the configuration
|
||||
// in test-fixtures/show. This schema should be assigned to a mock provider
|
||||
// named "test".
|
||||
|
@ -225,3 +315,14 @@ func showFixturePlanFile(t *testing.T) string {
|
|||
plan,
|
||||
)
|
||||
}
|
||||
|
||||
// this simplified plan struct allows us to preserve field order when marshaling
|
||||
// the command output.
|
||||
type plan struct {
|
||||
FormatVersion string `json:"format_version,omitempty"`
|
||||
PlannedValues map[string]interface{} `json:"planned_values,omitempty"`
|
||||
ResourceChanges []interface{} `json:"resource_changes,omitempty"`
|
||||
OutputChanges map[string]interface{} `json:"output_changes,omitempty"`
|
||||
PriorState string `json:"prior_state,omitempty"`
|
||||
Config string `json:"configuration,omitempty"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
variable "test_var" {
|
||||
default = "bar"
|
||||
}
|
||||
resource "test_instance" "test" {
|
||||
ami = var.test_var
|
||||
}
|
||||
|
||||
output "test" {
|
||||
value = var.test_var
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"format_version": "0.1",
|
||||
"planned_values": {
|
||||
"outputs": {
|
||||
"test": {
|
||||
"sensitive": false,
|
||||
"value": "bar"
|
||||
}
|
||||
},
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_name": "test",
|
||||
"schema_version": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resource_changes": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"deposed": true,
|
||||
"change": {
|
||||
"actions": [
|
||||
"Create"
|
||||
],
|
||||
"before": null,
|
||||
"after_unknown": {
|
||||
"ami": false,
|
||||
"id": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"output_changes": {
|
||||
"test": {
|
||||
"actions": [
|
||||
"Create"
|
||||
],
|
||||
"before": null,
|
||||
"after": "bar",
|
||||
"after_unknown": false
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"root_module": {
|
||||
"outputs": {
|
||||
"test": {
|
||||
"expression": {
|
||||
"references": [
|
||||
"var.test_var"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_config_key": "provider.test",
|
||||
"schema_version": 0,
|
||||
"count_expression": {},
|
||||
"for_each_expression": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
variable "test_var" {
|
||||
default = "bar"
|
||||
}
|
||||
resource "test_instance" "test" {
|
||||
ami = var.test_var
|
||||
}
|
||||
|
||||
output "test" {
|
||||
value = var.test_var
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
{
|
||||
"format_version": "0.1",
|
||||
"planned_values": {
|
||||
"outputs": {
|
||||
"test": {
|
||||
"sensitive": false,
|
||||
"value": "bar"
|
||||
}
|
||||
},
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_name": "test",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"ami": {},
|
||||
"id": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resource_changes": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"deposed": true,
|
||||
"change": {
|
||||
"actions": [
|
||||
"Update"
|
||||
],
|
||||
"before": {
|
||||
"ami": "foo",
|
||||
"id": null
|
||||
},
|
||||
"after": {
|
||||
"ami": "bar",
|
||||
"id": null
|
||||
},
|
||||
"after_unknown": {
|
||||
"ami": false,
|
||||
"id": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "test_instance.test-delete",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test-delete",
|
||||
"deposed": true,
|
||||
"change": {
|
||||
"actions": [
|
||||
"Delete"
|
||||
],
|
||||
"before": {
|
||||
"ami": "foo",
|
||||
"id": null
|
||||
},
|
||||
"after": null,
|
||||
"after_unknown": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"output_changes": {
|
||||
"test": {
|
||||
"actions": [
|
||||
"Create"
|
||||
],
|
||||
"before": null,
|
||||
"after": "bar",
|
||||
"after_unknown": false
|
||||
}
|
||||
},
|
||||
"prior_state": {
|
||||
"format_version": "0.1",
|
||||
"values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_name": "test",
|
||||
"values": {
|
||||
"ami": {},
|
||||
"id": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "test_instance.test-delete",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test-delete",
|
||||
"provider_name": "test",
|
||||
"values": {
|
||||
"ami": {},
|
||||
"id": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"root_module": {
|
||||
"outputs": {
|
||||
"test": {
|
||||
"expression": {
|
||||
"references": [
|
||||
"var.test_var"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_config_key": "provider.test",
|
||||
"schema_version": 0,
|
||||
"count_expression": {},
|
||||
"for_each_expression": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"version": 4,
|
||||
"terraform_version": "0.12.0",
|
||||
"serial": 7,
|
||||
"lineage": "configuredUnchanged",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider": "provider.test",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"ami": "foo"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test-delete",
|
||||
"provider": "provider.test",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"ami": "foo"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
variable "test_var" {
|
||||
default = "bar"
|
||||
}
|
||||
resource "test_instance" "test" {
|
||||
ami = var.test_var
|
||||
}
|
||||
|
||||
output "test" {
|
||||
value = var.test_var
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"format_version": "0.1",
|
||||
"planned_values": {
|
||||
"outputs": {
|
||||
"test": {
|
||||
"sensitive": false,
|
||||
"value": "bar"
|
||||
}
|
||||
},
|
||||
"root_module": {}
|
||||
},
|
||||
"resource_changes": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"deposed": true,
|
||||
"change": {
|
||||
"actions": [
|
||||
"NoOp"
|
||||
],
|
||||
"before": {
|
||||
"ami": "bar",
|
||||
"id": null
|
||||
},
|
||||
"after": {
|
||||
"ami": "bar",
|
||||
"id": null
|
||||
},
|
||||
"after_unknown": {
|
||||
"ami": false,
|
||||
"id": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"output_changes": {
|
||||
"test": {
|
||||
"actions": [
|
||||
"Create"
|
||||
],
|
||||
"before": null,
|
||||
"after": "bar",
|
||||
"after_unknown": false
|
||||
}
|
||||
},
|
||||
"prior_state": {
|
||||
"format_version": "0.1",
|
||||
"values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_name": "test",
|
||||
"values": {
|
||||
"ami": {},
|
||||
"id": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"root_module": {
|
||||
"outputs": {
|
||||
"test": {
|
||||
"expression": {
|
||||
"references": [
|
||||
"var.test_var"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"address": "test_instance.test",
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider_config_key": "provider.test",
|
||||
"schema_version": 0,
|
||||
"count_expression": {},
|
||||
"for_each_expression": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"version": 4,
|
||||
"terraform_version": "0.12.0",
|
||||
"serial": 7,
|
||||
"lineage": "configuredUnchanged",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "test_instance",
|
||||
"name": "test",
|
||||
"provider": "provider.test",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"ami": "bar"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue