github.com/opentofu/opentofu@v1.7.1/internal/backend/remote-state/cos/backend_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package cos 7 8 import ( 9 "crypto/md5" 10 "fmt" 11 "os" 12 "testing" 13 "time" 14 15 "github.com/opentofu/opentofu/internal/backend" 16 "github.com/opentofu/opentofu/internal/encryption" 17 "github.com/opentofu/opentofu/internal/states/remote" 18 ) 19 20 const ( 21 defaultPrefix = "" 22 defaultKey = "terraform.tfstate" 23 ) 24 25 // Testing Thanks to GCS 26 27 func TestStateFile(t *testing.T) { 28 t.Parallel() 29 30 cases := []struct { 31 prefix string 32 stateName string 33 key string 34 wantStateFile string 35 wantLockFile string 36 }{ 37 {"", "default", "default.tfstate", "default.tfstate", "default.tfstate.tflock"}, 38 {"", "default", "test.tfstate", "test.tfstate", "test.tfstate.tflock"}, 39 {"", "dev", "test.tfstate", "dev/test.tfstate", "dev/test.tfstate.tflock"}, 40 {"terraform/test", "default", "default.tfstate", "terraform/test/default.tfstate", "terraform/test/default.tfstate.tflock"}, 41 {"terraform/test", "default", "test.tfstate", "terraform/test/test.tfstate", "terraform/test/test.tfstate.tflock"}, 42 {"terraform/test", "dev", "test.tfstate", "terraform/test/dev/test.tfstate", "terraform/test/dev/test.tfstate.tflock"}, 43 } 44 45 for _, c := range cases { 46 t.Run(fmt.Sprintf("%s %s %s", c.prefix, c.key, c.stateName), func(t *testing.T) { 47 b := &Backend{ 48 prefix: c.prefix, 49 key: c.key, 50 } 51 if got, want := b.stateFile(c.stateName), c.wantStateFile; got != want { 52 t.Errorf("wrong state file name\ngot: %s\nwant: %s", got, want) 53 } 54 if got, want := b.lockFile(c.stateName), c.wantLockFile; got != want { 55 t.Errorf("wrong lock file name\ngot: %s\nwant: %s", got, want) 56 } 57 }) 58 } 59 } 60 61 func TestRemoteClient(t *testing.T) { 62 t.Parallel() 63 64 bucket := bucketName(t) 65 66 be := setupBackend(t, bucket, defaultPrefix, defaultKey, false) 67 defer teardownBackend(t, be) 68 69 ss, err := be.StateMgr(backend.DefaultStateName) 70 if err != nil { 71 t.Fatalf("unexpected error: %s", err) 72 } 73 74 rs, ok := ss.(*remote.State) 75 if !ok { 76 t.Fatalf("wrong state manager type\ngot: %T\nwant: %T", ss, rs) 77 } 78 79 remote.TestClient(t, rs.Client) 80 } 81 82 func TestRemoteClientWithPrefix(t *testing.T) { 83 t.Parallel() 84 85 prefix := "prefix/test" 86 bucket := bucketName(t) 87 88 be := setupBackend(t, bucket, prefix, defaultKey, false) 89 defer teardownBackend(t, be) 90 91 ss, err := be.StateMgr(backend.DefaultStateName) 92 if err != nil { 93 t.Fatalf("unexpected error: %s", err) 94 } 95 96 rs, ok := ss.(*remote.State) 97 if !ok { 98 t.Fatalf("wrong state manager type\ngot: %T\nwant: %T", ss, rs) 99 } 100 101 remote.TestClient(t, rs.Client) 102 } 103 104 func TestRemoteClientWithEncryption(t *testing.T) { 105 t.Parallel() 106 107 bucket := bucketName(t) 108 109 be := setupBackend(t, bucket, defaultPrefix, defaultKey, true) 110 defer teardownBackend(t, be) 111 112 ss, err := be.StateMgr(backend.DefaultStateName) 113 if err != nil { 114 t.Fatalf("unexpected error: %s", err) 115 } 116 117 rs, ok := ss.(*remote.State) 118 if !ok { 119 t.Fatalf("wrong state manager type\ngot: %T\nwant: %T", ss, rs) 120 } 121 122 remote.TestClient(t, rs.Client) 123 } 124 125 func TestRemoteLocks(t *testing.T) { 126 t.Parallel() 127 128 bucket := bucketName(t) 129 130 be := setupBackend(t, bucket, defaultPrefix, defaultKey, false) 131 defer teardownBackend(t, be) 132 133 remoteClient := func() (remote.Client, error) { 134 ss, err := be.StateMgr(backend.DefaultStateName) 135 if err != nil { 136 return nil, err 137 } 138 139 rs, ok := ss.(*remote.State) 140 if !ok { 141 return nil, fmt.Errorf("be.StateMgr(): got a %T, want a *remote.State", ss) 142 } 143 144 return rs.Client, nil 145 } 146 147 c0, err := remoteClient() 148 if err != nil { 149 t.Fatalf("unexpected error: %s", err) 150 } 151 152 c1, err := remoteClient() 153 if err != nil { 154 t.Fatalf("unexpected error: %s", err) 155 } 156 157 remote.TestRemoteLocks(t, c0, c1) 158 } 159 160 func TestBackend(t *testing.T) { 161 t.Parallel() 162 163 bucket := bucketName(t) 164 165 be0 := setupBackend(t, bucket, defaultPrefix, defaultKey, false) 166 defer teardownBackend(t, be0) 167 168 be1 := setupBackend(t, bucket, defaultPrefix, defaultKey, false) 169 defer teardownBackend(t, be1) 170 171 backend.TestBackendStates(t, be0) 172 backend.TestBackendStateLocks(t, be0, be1) 173 backend.TestBackendStateForceUnlock(t, be0, be1) 174 } 175 176 func TestBackendWithPrefix(t *testing.T) { 177 t.Parallel() 178 179 prefix := "prefix/test" 180 bucket := bucketName(t) 181 182 be0 := setupBackend(t, bucket, prefix, defaultKey, false) 183 defer teardownBackend(t, be0) 184 185 be1 := setupBackend(t, bucket, prefix+"/", defaultKey, false) 186 defer teardownBackend(t, be1) 187 188 backend.TestBackendStates(t, be0) 189 backend.TestBackendStateLocks(t, be0, be1) 190 } 191 192 func TestBackendWithEncryption(t *testing.T) { 193 t.Parallel() 194 195 bucket := bucketName(t) 196 197 be0 := setupBackend(t, bucket, defaultPrefix, defaultKey, true) 198 defer teardownBackend(t, be0) 199 200 be1 := setupBackend(t, bucket, defaultPrefix, defaultKey, true) 201 defer teardownBackend(t, be1) 202 203 backend.TestBackendStates(t, be0) 204 backend.TestBackendStateLocks(t, be0, be1) 205 } 206 207 func setupBackend(t *testing.T, bucket, prefix, key string, encrypt bool) backend.Backend { 208 t.Helper() 209 210 skip := os.Getenv("TF_COS_APPID") == "" 211 if skip { 212 t.Skip("This test require setting TF_COS_APPID environment variables") 213 } 214 215 if os.Getenv(PROVIDER_REGION) == "" { 216 t.Setenv(PROVIDER_REGION, "ap-guangzhou") 217 } 218 219 appId := os.Getenv("TF_COS_APPID") 220 region := os.Getenv(PROVIDER_REGION) 221 222 config := map[string]interface{}{ 223 "region": region, 224 "bucket": bucket + appId, 225 "prefix": prefix, 226 "key": key, 227 } 228 229 b := backend.TestBackendConfig(t, New(encryption.StateEncryptionDisabled()), backend.TestWrapConfig(config)) 230 be := b.(*Backend) 231 232 c, err := be.client("tencentcloud") 233 if err != nil { 234 t.Fatalf("unexpected error: %s", err) 235 } 236 237 err = c.putBucket() 238 if err != nil { 239 t.Fatalf("unexpected error: %s", err) 240 } 241 242 return b 243 } 244 245 func teardownBackend(t *testing.T, b backend.Backend) { 246 t.Helper() 247 248 c, err := b.(*Backend).client("tencentcloud") 249 if err != nil { 250 t.Fatalf("unexpected error: %s", err) 251 } 252 253 err = c.deleteBucket(true) 254 if err != nil { 255 t.Fatalf("unexpected error: %s", err) 256 } 257 } 258 259 func bucketName(t *testing.T) string { 260 unique := fmt.Sprintf("%s-%x", t.Name(), time.Now().UnixNano()) 261 return fmt.Sprintf("terraform-test-%s-%s", fmt.Sprintf("%x", md5.Sum([]byte(unique)))[:10], "") 262 }