github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/plans/planfile/planfile_test.go (about) 1 package planfile 2 3 import ( 4 "io/ioutil" 5 "path/filepath" 6 "testing" 7 8 "github.com/google/go-cmp/cmp" 9 10 "github.com/iaas-resource-provision/iaas-rpc/internal/configs/configload" 11 "github.com/iaas-resource-provision/iaas-rpc/internal/plans" 12 "github.com/iaas-resource-provision/iaas-rpc/internal/states" 13 "github.com/iaas-resource-provision/iaas-rpc/internal/states/statefile" 14 tfversion "github.com/iaas-resource-provision/iaas-rpc/version" 15 ) 16 17 func TestRoundtrip(t *testing.T) { 18 fixtureDir := filepath.Join("testdata", "test-config") 19 loader, err := configload.NewLoader(&configload.Config{ 20 ModulesDir: filepath.Join(fixtureDir, ".terraform", "modules"), 21 }) 22 if err != nil { 23 t.Fatal(err) 24 } 25 26 _, snapIn, diags := loader.LoadConfigWithSnapshot(fixtureDir) 27 if diags.HasErrors() { 28 t.Fatal(diags.Error()) 29 } 30 31 // Just a minimal state file so we can test that it comes out again at all. 32 // We don't need to test the entire thing because the state file 33 // serialization is already tested in its own package. 34 stateFileIn := &statefile.File{ 35 TerraformVersion: tfversion.SemVer, 36 Serial: 2, 37 Lineage: "abc123", 38 State: states.NewState(), 39 } 40 prevStateFileIn := &statefile.File{ 41 TerraformVersion: tfversion.SemVer, 42 Serial: 1, 43 Lineage: "abc123", 44 State: states.NewState(), 45 } 46 47 // Minimal plan too, since the serialization of the tfplan portion of the 48 // file is tested more fully in tfplan_test.go . 49 planIn := &plans.Plan{ 50 Changes: &plans.Changes{ 51 Resources: []*plans.ResourceInstanceChangeSrc{}, 52 Outputs: []*plans.OutputChangeSrc{}, 53 }, 54 ProviderSHA256s: map[string][]byte{}, 55 VariableValues: map[string]plans.DynamicValue{ 56 "foo": plans.DynamicValue([]byte("foo placeholder")), 57 }, 58 Backend: plans.Backend{ 59 Type: "local", 60 Config: plans.DynamicValue([]byte("config placeholder")), 61 Workspace: "default", 62 }, 63 64 // Due to some historical oddities in how we've changed modelling over 65 // time, we also include the states (without the corresponding file 66 // headers) in the plans.Plan object. This is currently ignored by 67 // Create but will be returned by ReadPlan and so we need to include 68 // it here so that we'll get a match when we compare input and output 69 // below. 70 PrevRunState: prevStateFileIn.State, 71 PriorState: stateFileIn.State, 72 } 73 74 workDir, err := ioutil.TempDir("", "tf-planfile") 75 if err != nil { 76 t.Fatal(err) 77 } 78 planFn := filepath.Join(workDir, "tfplan") 79 80 err = Create(planFn, snapIn, prevStateFileIn, stateFileIn, planIn) 81 if err != nil { 82 t.Fatalf("failed to create plan file: %s", err) 83 } 84 85 pr, err := Open(planFn) 86 if err != nil { 87 t.Fatalf("failed to open plan file for reading: %s", err) 88 } 89 90 t.Run("ReadPlan", func(t *testing.T) { 91 planOut, err := pr.ReadPlan() 92 if err != nil { 93 t.Fatalf("failed to read plan: %s", err) 94 } 95 if diff := cmp.Diff(planIn, planOut); diff != "" { 96 t.Errorf("plan did not survive round-trip\n%s", diff) 97 } 98 }) 99 100 t.Run("ReadStateFile", func(t *testing.T) { 101 stateFileOut, err := pr.ReadStateFile() 102 if err != nil { 103 t.Fatalf("failed to read state: %s", err) 104 } 105 if diff := cmp.Diff(stateFileIn, stateFileOut); diff != "" { 106 t.Errorf("state file did not survive round-trip\n%s", diff) 107 } 108 }) 109 110 t.Run("ReadPrevStateFile", func(t *testing.T) { 111 prevStateFileOut, err := pr.ReadPrevStateFile() 112 if err != nil { 113 t.Fatalf("failed to read state: %s", err) 114 } 115 if diff := cmp.Diff(prevStateFileIn, prevStateFileOut); diff != "" { 116 t.Errorf("state file did not survive round-trip\n%s", diff) 117 } 118 }) 119 120 t.Run("ReadConfigSnapshot", func(t *testing.T) { 121 snapOut, err := pr.ReadConfigSnapshot() 122 if err != nil { 123 t.Fatalf("failed to read config snapshot: %s", err) 124 } 125 if diff := cmp.Diff(snapIn, snapOut); diff != "" { 126 t.Errorf("config snapshot did not survive round-trip\n%s", diff) 127 } 128 }) 129 130 t.Run("ReadConfig", func(t *testing.T) { 131 // Reading from snapshots is tested in the configload package, so 132 // here we'll just test that we can successfully do it, to see if the 133 // glue code in _this_ package is correct. 134 _, diags := pr.ReadConfig() 135 if diags.HasErrors() { 136 t.Errorf("when reading config: %s", diags.Err()) 137 } 138 }) 139 }