github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/remote/remote_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package remote 5 6 import ( 7 "crypto/md5" 8 "encoding/json" 9 "testing" 10 ) 11 12 func TestRemoteClient_noPayload(t *testing.T) { 13 s := &State{ 14 Client: nilClient{}, 15 } 16 if err := s.RefreshState(); err != nil { 17 t.Fatal("error refreshing empty remote state") 18 } 19 } 20 21 // nilClient returns nil for everything 22 type nilClient struct{} 23 24 func (nilClient) Get() (*Payload, error) { return nil, nil } 25 26 func (c nilClient) Put([]byte) error { return nil } 27 28 func (c nilClient) Delete() error { return nil } 29 30 // mockClient is a client that tracks persisted state snapshots only in 31 // memory and also logs what it has been asked to do for use in test 32 // assertions. 33 type mockClient struct { 34 current []byte 35 log []mockClientRequest 36 } 37 38 type mockClientRequest struct { 39 Method string 40 Content map[string]interface{} 41 } 42 43 func (c *mockClient) Get() (*Payload, error) { 44 c.appendLog("Get", c.current) 45 if c.current == nil { 46 return nil, nil 47 } 48 checksum := md5.Sum(c.current) 49 return &Payload{ 50 Data: c.current, 51 MD5: checksum[:], 52 }, nil 53 } 54 55 func (c *mockClient) Put(data []byte) error { 56 c.appendLog("Put", data) 57 c.current = data 58 return nil 59 } 60 61 func (c *mockClient) Delete() error { 62 c.appendLog("Delete", c.current) 63 c.current = nil 64 return nil 65 } 66 67 func (c *mockClient) appendLog(method string, content []byte) { 68 // For easier test assertions, we actually log the result of decoding 69 // the content JSON rather than the raw bytes. Callers are in principle 70 // allowed to provide any arbitrary bytes here, but we know we're only 71 // using this to test our own State implementation here and that always 72 // uses the JSON state format, so this is fine. 73 74 var contentVal map[string]interface{} 75 if content != nil { 76 err := json.Unmarshal(content, &contentVal) 77 if err != nil { 78 panic(err) // should never happen because our tests control this input 79 } 80 } 81 c.log = append(c.log, mockClientRequest{method, contentVal}) 82 } 83 84 // mockClientForcePusher is like mockClient, but also implements 85 // EnableForcePush, allowing testing for this behavior 86 type mockClientForcePusher struct { 87 current []byte 88 force bool 89 log []mockClientRequest 90 } 91 92 func (c *mockClientForcePusher) Get() (*Payload, error) { 93 c.appendLog("Get", c.current) 94 if c.current == nil { 95 return nil, nil 96 } 97 checksum := md5.Sum(c.current) 98 return &Payload{ 99 Data: c.current, 100 MD5: checksum[:], 101 }, nil 102 } 103 104 func (c *mockClientForcePusher) Put(data []byte) error { 105 if c.force { 106 c.appendLog("Force Put", data) 107 } else { 108 c.appendLog("Put", data) 109 } 110 c.current = data 111 return nil 112 } 113 114 // Implements remote.ClientForcePusher 115 func (c *mockClientForcePusher) EnableForcePush() { 116 c.force = true 117 } 118 119 func (c *mockClientForcePusher) Delete() error { 120 c.appendLog("Delete", c.current) 121 c.current = nil 122 return nil 123 } 124 func (c *mockClientForcePusher) appendLog(method string, content []byte) { 125 var contentVal map[string]interface{} 126 if content != nil { 127 err := json.Unmarshal(content, &contentVal) 128 if err != nil { 129 panic(err) // should never happen because our tests control this input 130 } 131 } 132 c.log = append(c.log, mockClientRequest{method, contentVal}) 133 }