github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/plans/planfile/planfile_test.go (about) 1 package planfile 2 3 import ( 4 "io/ioutil" 5 "path/filepath" 6 "reflect" 7 "testing" 8 9 "github.com/davecgh/go-spew/spew" 10 11 "github.com/hashicorp/terraform-plugin-sdk/internal/configs/configload" 12 "github.com/hashicorp/terraform-plugin-sdk/internal/plans" 13 "github.com/hashicorp/terraform-plugin-sdk/internal/states" 14 "github.com/hashicorp/terraform-plugin-sdk/internal/states/statefile" 15 tfversion "github.com/hashicorp/terraform-plugin-sdk/internal/version" 16 ) 17 18 func TestRoundtrip(t *testing.T) { 19 fixtureDir := filepath.Join("testdata", "test-config") 20 loader, err := configload.NewLoader(&configload.Config{ 21 ModulesDir: filepath.Join(fixtureDir, ".terraform", "modules"), 22 }) 23 if err != nil { 24 t.Fatal(err) 25 } 26 27 _, snapIn, diags := loader.LoadConfigWithSnapshot(fixtureDir) 28 if diags.HasErrors() { 29 t.Fatal(diags.Error()) 30 } 31 32 // Just a minimal state file so we can test that it comes out again at all. 33 // We don't need to test the entire thing because the state file 34 // serialization is already tested in its own package. 35 stateFileIn := &statefile.File{ 36 TerraformVersion: tfversion.SemVer, 37 Serial: 1, 38 Lineage: "abc123", 39 State: states.NewState(), 40 } 41 42 // Minimal plan too, since the serialization of the tfplan portion of the 43 // file is tested more fully in tfplan_test.go . 44 planIn := &plans.Plan{ 45 Changes: &plans.Changes{ 46 Resources: []*plans.ResourceInstanceChangeSrc{}, 47 Outputs: []*plans.OutputChangeSrc{}, 48 }, 49 ProviderSHA256s: map[string][]byte{}, 50 VariableValues: map[string]plans.DynamicValue{ 51 "foo": plans.DynamicValue([]byte("foo placeholder")), 52 }, 53 Backend: plans.Backend{ 54 Type: "local", 55 Config: plans.DynamicValue([]byte("config placeholder")), 56 Workspace: "default", 57 }, 58 } 59 60 workDir, err := ioutil.TempDir("", "tf-planfile") 61 if err != nil { 62 t.Fatal(err) 63 } 64 planFn := filepath.Join(workDir, "tfplan") 65 66 err = Create(planFn, snapIn, stateFileIn, planIn) 67 if err != nil { 68 t.Fatalf("failed to create plan file: %s", err) 69 } 70 71 pr, err := Open(planFn) 72 if err != nil { 73 t.Fatalf("failed to open plan file for reading: %s", err) 74 } 75 76 t.Run("ReadPlan", func(t *testing.T) { 77 planOut, err := pr.ReadPlan() 78 if err != nil { 79 t.Fatalf("failed to read plan: %s", err) 80 } 81 if !reflect.DeepEqual(planIn, planOut) { 82 t.Errorf("plan did not survive round-trip\nresult: %sinput: %s", spew.Sdump(planOut), spew.Sdump(planIn)) 83 } 84 }) 85 86 t.Run("ReadStateFile", func(t *testing.T) { 87 stateFileOut, err := pr.ReadStateFile() 88 if err != nil { 89 t.Fatalf("failed to read state: %s", err) 90 } 91 if !reflect.DeepEqual(stateFileIn, stateFileOut) { 92 t.Errorf("state file did not survive round-trip\nresult: %sinput: %s", spew.Sdump(stateFileOut), spew.Sdump(stateFileIn)) 93 } 94 }) 95 96 t.Run("ReadConfigSnapshot", func(t *testing.T) { 97 snapOut, err := pr.ReadConfigSnapshot() 98 if err != nil { 99 t.Fatalf("failed to read config snapshot: %s", err) 100 } 101 if !reflect.DeepEqual(snapIn, snapOut) { 102 t.Errorf("config snapshot did not survive round-trip\nresult: %sinput: %s", spew.Sdump(snapOut), spew.Sdump(snapIn)) 103 } 104 }) 105 106 t.Run("ReadConfig", func(t *testing.T) { 107 // Reading from snapshots is tested in the configload package, so 108 // here we'll just test that we can successfully do it, to see if the 109 // glue code in _this_ package is correct. 110 _, diags := pr.ReadConfig() 111 if diags.HasErrors() { 112 t.Errorf("when reading config: %s", diags.Err()) 113 } 114 }) 115 }