github.com/hugorut/terraform@v1.1.3/src/backend/remote-state/gcs/backend_test.go (about) 1 package gcs 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "strings" 8 "testing" 9 "time" 10 11 "cloud.google.com/go/storage" 12 "github.com/hugorut/terraform/src/backend" 13 "github.com/hugorut/terraform/src/states/remote" 14 ) 15 16 const ( 17 noPrefix = "" 18 noEncryptionKey = "" 19 ) 20 21 // See https://cloud.google.com/storage/docs/using-encryption-keys#generating_your_own_encryption_key 22 var encryptionKey = "yRyCOikXi1ZDNE0xN3yiFsJjg7LGimoLrGFcLZgQoVk=" 23 24 func TestStateFile(t *testing.T) { 25 t.Parallel() 26 27 cases := []struct { 28 prefix string 29 name string 30 wantStateFile string 31 wantLockFile string 32 }{ 33 {"state", "default", "state/default.tfstate", "state/default.tflock"}, 34 {"state", "test", "state/test.tfstate", "state/test.tflock"}, 35 {"state", "test", "state/test.tfstate", "state/test.tflock"}, 36 {"state", "test", "state/test.tfstate", "state/test.tflock"}, 37 } 38 for _, c := range cases { 39 b := &Backend{ 40 prefix: c.prefix, 41 } 42 43 if got := b.stateFile(c.name); got != c.wantStateFile { 44 t.Errorf("stateFile(%q) = %q, want %q", c.name, got, c.wantStateFile) 45 } 46 47 if got := b.lockFile(c.name); got != c.wantLockFile { 48 t.Errorf("lockFile(%q) = %q, want %q", c.name, got, c.wantLockFile) 49 } 50 } 51 } 52 53 func TestRemoteClient(t *testing.T) { 54 t.Parallel() 55 56 bucket := bucketName(t) 57 be := setupBackend(t, bucket, noPrefix, noEncryptionKey) 58 defer teardownBackend(t, be, noPrefix) 59 60 ss, err := be.StateMgr(backend.DefaultStateName) 61 if err != nil { 62 t.Fatalf("be.StateMgr(%q) = %v", backend.DefaultStateName, err) 63 } 64 65 rs, ok := ss.(*remote.State) 66 if !ok { 67 t.Fatalf("be.StateMgr(): got a %T, want a *remote.State", ss) 68 } 69 70 remote.TestClient(t, rs.Client) 71 } 72 func TestRemoteClientWithEncryption(t *testing.T) { 73 t.Parallel() 74 75 bucket := bucketName(t) 76 be := setupBackend(t, bucket, noPrefix, encryptionKey) 77 defer teardownBackend(t, be, noPrefix) 78 79 ss, err := be.StateMgr(backend.DefaultStateName) 80 if err != nil { 81 t.Fatalf("be.StateMgr(%q) = %v", backend.DefaultStateName, err) 82 } 83 84 rs, ok := ss.(*remote.State) 85 if !ok { 86 t.Fatalf("be.StateMgr(): got a %T, want a *remote.State", ss) 87 } 88 89 remote.TestClient(t, rs.Client) 90 } 91 92 func TestRemoteLocks(t *testing.T) { 93 t.Parallel() 94 95 bucket := bucketName(t) 96 be := setupBackend(t, bucket, noPrefix, noEncryptionKey) 97 defer teardownBackend(t, be, noPrefix) 98 99 remoteClient := func() (remote.Client, error) { 100 ss, err := be.StateMgr(backend.DefaultStateName) 101 if err != nil { 102 return nil, err 103 } 104 105 rs, ok := ss.(*remote.State) 106 if !ok { 107 return nil, fmt.Errorf("be.StateMgr(): got a %T, want a *remote.State", ss) 108 } 109 110 return rs.Client, nil 111 } 112 113 c0, err := remoteClient() 114 if err != nil { 115 t.Fatalf("remoteClient(0) = %v", err) 116 } 117 c1, err := remoteClient() 118 if err != nil { 119 t.Fatalf("remoteClient(1) = %v", err) 120 } 121 122 remote.TestRemoteLocks(t, c0, c1) 123 } 124 125 func TestBackend(t *testing.T) { 126 t.Parallel() 127 128 bucket := bucketName(t) 129 130 be0 := setupBackend(t, bucket, noPrefix, noEncryptionKey) 131 defer teardownBackend(t, be0, noPrefix) 132 133 be1 := setupBackend(t, bucket, noPrefix, noEncryptionKey) 134 135 backend.TestBackendStates(t, be0) 136 backend.TestBackendStateLocks(t, be0, be1) 137 backend.TestBackendStateForceUnlock(t, be0, be1) 138 } 139 140 func TestBackendWithPrefix(t *testing.T) { 141 t.Parallel() 142 143 prefix := "test/prefix" 144 bucket := bucketName(t) 145 146 be0 := setupBackend(t, bucket, prefix, noEncryptionKey) 147 defer teardownBackend(t, be0, prefix) 148 149 be1 := setupBackend(t, bucket, prefix+"/", noEncryptionKey) 150 151 backend.TestBackendStates(t, be0) 152 backend.TestBackendStateLocks(t, be0, be1) 153 } 154 func TestBackendWithEncryption(t *testing.T) { 155 t.Parallel() 156 157 bucket := bucketName(t) 158 159 be0 := setupBackend(t, bucket, noPrefix, encryptionKey) 160 defer teardownBackend(t, be0, noPrefix) 161 162 be1 := setupBackend(t, bucket, noPrefix, encryptionKey) 163 164 backend.TestBackendStates(t, be0) 165 backend.TestBackendStateLocks(t, be0, be1) 166 } 167 168 // setupBackend returns a new GCS backend. 169 func setupBackend(t *testing.T, bucket, prefix, key string) backend.Backend { 170 t.Helper() 171 172 projectID := os.Getenv("GOOGLE_PROJECT") 173 if projectID == "" || os.Getenv("TF_ACC") == "" { 174 t.Skip("This test creates a bucket in GCS and populates it. " + 175 "Since this may incur costs, it will only run if " + 176 "the TF_ACC and GOOGLE_PROJECT environment variables are set.") 177 } 178 179 config := map[string]interface{}{ 180 "bucket": bucket, 181 "prefix": prefix, 182 "encryption_key": key, 183 } 184 185 b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)) 186 be := b.(*Backend) 187 188 // create the bucket if it doesn't exist 189 bkt := be.storageClient.Bucket(bucket) 190 _, err := bkt.Attrs(be.storageContext) 191 if err != nil { 192 if err != storage.ErrBucketNotExist { 193 t.Fatal(err) 194 } 195 196 attrs := &storage.BucketAttrs{ 197 Location: os.Getenv("GOOGLE_REGION"), 198 } 199 err := bkt.Create(be.storageContext, projectID, attrs) 200 if err != nil { 201 t.Fatal(err) 202 } 203 } 204 205 return b 206 } 207 208 // teardownBackend deletes all states from be except the default state. 209 func teardownBackend(t *testing.T, be backend.Backend, prefix string) { 210 t.Helper() 211 gcsBE, ok := be.(*Backend) 212 if !ok { 213 t.Fatalf("be is a %T, want a *gcsBackend", be) 214 } 215 ctx := gcsBE.storageContext 216 217 bucket := gcsBE.storageClient.Bucket(gcsBE.bucketName) 218 objs := bucket.Objects(ctx, nil) 219 220 for o, err := objs.Next(); err == nil; o, err = objs.Next() { 221 if err := bucket.Object(o.Name).Delete(ctx); err != nil { 222 log.Printf("Error trying to delete object: %s %s\n\n", o.Name, err) 223 } else { 224 log.Printf("Object deleted: %s", o.Name) 225 } 226 } 227 228 // Delete the bucket itself. 229 if err := bucket.Delete(ctx); err != nil { 230 t.Errorf("deleting bucket %q failed, manual cleanup may be required: %v", gcsBE.bucketName, err) 231 } 232 } 233 234 // bucketName returns a valid bucket name for this test. 235 func bucketName(t *testing.T) string { 236 name := fmt.Sprintf("tf-%x-%s", time.Now().UnixNano(), t.Name()) 237 238 // Bucket names must contain 3 to 63 characters. 239 if len(name) > 63 { 240 name = name[:63] 241 } 242 243 return strings.ToLower(name) 244 }