github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/state/remote/testing.go (about)

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