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