github.com/kevinklinger/open_terraform@v1.3.6/noninternal/cloud/state_test.go (about) 1 package cloud 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "testing" 7 8 tfe "github.com/hashicorp/go-tfe" 9 "github.com/kevinklinger/open_terraform/noninternal/states/statefile" 10 "github.com/kevinklinger/open_terraform/noninternal/states/statemgr" 11 ) 12 13 func TestState_impl(t *testing.T) { 14 var _ statemgr.Reader = new(State) 15 var _ statemgr.Writer = new(State) 16 var _ statemgr.Persister = new(State) 17 var _ statemgr.Refresher = new(State) 18 var _ statemgr.OutputReader = new(State) 19 var _ statemgr.Locker = new(State) 20 } 21 22 type ExpectedOutput struct { 23 Name string 24 Sensitive bool 25 IsNull bool 26 } 27 28 func TestState_GetRootOutputValues(t *testing.T) { 29 b, bCleanup := testBackendWithOutputs(t) 30 defer bCleanup() 31 32 state := &State{tfeClient: b.client, organization: b.organization, workspace: &tfe.Workspace{ 33 ID: "ws-abcd", 34 }} 35 outputs, err := state.GetRootOutputValues() 36 37 if err != nil { 38 t.Fatalf("error returned from GetRootOutputValues: %s", err) 39 } 40 41 cases := []ExpectedOutput{ 42 { 43 Name: "sensitive_output", 44 Sensitive: true, 45 IsNull: false, 46 }, 47 { 48 Name: "nonsensitive_output", 49 Sensitive: false, 50 IsNull: false, 51 }, 52 { 53 Name: "object_output", 54 Sensitive: false, 55 IsNull: false, 56 }, 57 { 58 Name: "list_output", 59 Sensitive: false, 60 IsNull: false, 61 }, 62 } 63 64 if len(outputs) != len(cases) { 65 t.Errorf("Expected %d item but %d were returned", len(cases), len(outputs)) 66 } 67 68 for _, testCase := range cases { 69 so, ok := outputs[testCase.Name] 70 if !ok { 71 t.Fatalf("Expected key %s but it was not found", testCase.Name) 72 } 73 if so.Value.IsNull() != testCase.IsNull { 74 t.Errorf("Key %s does not match null expectation %v", testCase.Name, testCase.IsNull) 75 } 76 if so.Sensitive != testCase.Sensitive { 77 t.Errorf("Key %s does not match sensitive expectation %v", testCase.Name, testCase.Sensitive) 78 } 79 } 80 } 81 82 func TestState(t *testing.T) { 83 var buf bytes.Buffer 84 s := statemgr.TestFullInitialState() 85 sf := statefile.New(s, "stub-lineage", 2) 86 err := statefile.Write(sf, &buf) 87 if err != nil { 88 t.Fatalf("err: %s", err) 89 } 90 data := buf.Bytes() 91 92 state := testCloudState(t) 93 94 jsonState, err := ioutil.ReadFile("../command/testdata/show-json-state/sensitive-variables/output.json") 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 jsonStateOutputs := []byte(` 100 { 101 "outputs": { 102 "foo": { 103 "type": "string", 104 "value": "bar" 105 } 106 } 107 }`) 108 109 if err := state.uploadState(state.lineage, state.serial, state.forcePush, data, jsonState, jsonStateOutputs); err != nil { 110 t.Fatalf("put: %s", err) 111 } 112 113 payload, err := state.getStatePayload() 114 if err != nil { 115 t.Fatalf("get: %s", err) 116 } 117 if !bytes.Equal(payload.Data, data) { 118 t.Fatalf("expected full state %q\n\ngot: %q", string(payload.Data), string(data)) 119 } 120 121 if err := state.Delete(); err != nil { 122 t.Fatalf("delete: %s", err) 123 } 124 125 p, err := state.getStatePayload() 126 if err != nil { 127 t.Fatalf("get: %s", err) 128 } 129 if p != nil { 130 t.Fatalf("expected empty state, got: %q", string(p.Data)) 131 } 132 } 133 134 func TestCloudLocks(t *testing.T) { 135 back, bCleanup := testBackendWithName(t) 136 defer bCleanup() 137 138 a, err := back.StateMgr(testBackendSingleWorkspaceName) 139 if err != nil { 140 t.Fatalf("expected no error, got %v", err) 141 } 142 b, err := back.StateMgr(testBackendSingleWorkspaceName) 143 if err != nil { 144 t.Fatalf("expected no error, got %v", err) 145 } 146 147 lockerA, ok := a.(statemgr.Locker) 148 if !ok { 149 t.Fatal("client A not a statemgr.Locker") 150 } 151 152 lockerB, ok := b.(statemgr.Locker) 153 if !ok { 154 t.Fatal("client B not a statemgr.Locker") 155 } 156 157 infoA := statemgr.NewLockInfo() 158 infoA.Operation = "test" 159 infoA.Who = "clientA" 160 161 infoB := statemgr.NewLockInfo() 162 infoB.Operation = "test" 163 infoB.Who = "clientB" 164 165 lockIDA, err := lockerA.Lock(infoA) 166 if err != nil { 167 t.Fatal("unable to get initial lock:", err) 168 } 169 170 _, err = lockerB.Lock(infoB) 171 if err == nil { 172 lockerA.Unlock(lockIDA) 173 t.Fatal("client B obtained lock while held by client A") 174 } 175 if _, ok := err.(*statemgr.LockError); !ok { 176 t.Errorf("expected a LockError, but was %t: %s", err, err) 177 } 178 179 if err := lockerA.Unlock(lockIDA); err != nil { 180 t.Fatal("error unlocking client A", err) 181 } 182 183 lockIDB, err := lockerB.Lock(infoB) 184 if err != nil { 185 t.Fatal("unable to obtain lock from client B") 186 } 187 188 if lockIDB == lockIDA { 189 t.Fatalf("duplicate lock IDs: %q", lockIDB) 190 } 191 192 if err = lockerB.Unlock(lockIDB); err != nil { 193 t.Fatal("error unlocking client B:", err) 194 } 195 }