github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/remote/testing.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package remote 5 6 import ( 7 "bytes" 8 "testing" 9 10 "github.com/terramate-io/tf/states/statefile" 11 "github.com/terramate-io/tf/states/statemgr" 12 ) 13 14 // TestClient is a generic function to test any client. 15 func TestClient(t *testing.T, c Client) { 16 var buf bytes.Buffer 17 s := statemgr.TestFullInitialState() 18 sf := statefile.New(s, "stub-lineage", 2) 19 err := statefile.Write(sf, &buf) 20 if err != nil { 21 t.Fatalf("err: %s", err) 22 } 23 data := buf.Bytes() 24 25 if err := c.Put(data); err != nil { 26 t.Fatalf("put: %s", err) 27 } 28 29 p, err := c.Get() 30 if err != nil { 31 t.Fatalf("get: %s", err) 32 } 33 if !bytes.Equal(p.Data, data) { 34 t.Fatalf("expected full state %q\n\ngot: %q", string(p.Data), string(data)) 35 } 36 37 if err := c.Delete(); err != nil { 38 t.Fatalf("delete: %s", err) 39 } 40 41 p, err = c.Get() 42 if err != nil { 43 t.Fatalf("get: %s", err) 44 } 45 if p != nil { 46 t.Fatalf("expected empty state, got: %q", string(p.Data)) 47 } 48 } 49 50 // Test the lock implementation for a remote.Client. 51 // This test requires 2 client instances, in oder to have multiple remote 52 // clients since some implementations may tie the client to the lock, or may 53 // have reentrant locks. 54 func TestRemoteLocks(t *testing.T, a, b Client) { 55 lockerA, ok := a.(statemgr.Locker) 56 if !ok { 57 t.Fatal("client A not a statemgr.Locker") 58 } 59 60 lockerB, ok := b.(statemgr.Locker) 61 if !ok { 62 t.Fatal("client B not a statemgr.Locker") 63 } 64 65 infoA := statemgr.NewLockInfo() 66 infoA.Operation = "test" 67 infoA.Who = "clientA" 68 69 infoB := statemgr.NewLockInfo() 70 infoB.Operation = "test" 71 infoB.Who = "clientB" 72 73 lockIDA, err := lockerA.Lock(infoA) 74 if err != nil { 75 t.Fatal("unable to get initial lock:", err) 76 } 77 78 _, err = lockerB.Lock(infoB) 79 if err == nil { 80 lockerA.Unlock(lockIDA) 81 t.Fatal("client B obtained lock while held by client A") 82 } 83 if _, ok := err.(*statemgr.LockError); !ok { 84 t.Errorf("expected a LockError, but was %t: %s", err, err) 85 } 86 87 if err := lockerA.Unlock(lockIDA); err != nil { 88 t.Fatal("error unlocking client A", err) 89 } 90 91 lockIDB, err := lockerB.Lock(infoB) 92 if err != nil { 93 t.Fatal("unable to obtain lock from client B") 94 } 95 96 if lockIDB == lockIDA { 97 t.Fatalf("duplicate lock IDs: %q", lockIDB) 98 } 99 100 if err = lockerB.Unlock(lockIDB); err != nil { 101 t.Fatal("error unlocking client B:", err) 102 } 103 104 // TODO: Should we enforce that Unlock requires the correct ID? 105 }