github.com/magodo/terraform@v0.11.12-beta1/backend/remote/backend_test.go (about) 1 package remote 2 3 import ( 4 "errors" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/hashicorp/terraform/backend" 10 "github.com/hashicorp/terraform/config" 11 "github.com/hashicorp/terraform/svchost/disco" 12 "github.com/hashicorp/terraform/terraform" 13 "github.com/hashicorp/terraform/version" 14 15 backendLocal "github.com/hashicorp/terraform/backend/local" 16 ) 17 18 func TestRemote(t *testing.T) { 19 var _ backend.Enhanced = New(nil) 20 var _ backend.CLI = New(nil) 21 } 22 23 func TestRemote_backendDefault(t *testing.T) { 24 b := testBackendDefault(t) 25 backend.TestBackendStates(t, b) 26 backend.TestBackendStateLocks(t, b, b) 27 backend.TestBackendStateForceUnlock(t, b, b) 28 } 29 30 func TestRemote_backendNoDefault(t *testing.T) { 31 b := testBackendNoDefault(t) 32 backend.TestBackendStates(t, b) 33 } 34 35 func TestRemote_config(t *testing.T) { 36 cases := map[string]struct { 37 config map[string]interface{} 38 err error 39 }{ 40 "with_a_name": { 41 config: map[string]interface{}{ 42 "organization": "hashicorp", 43 "workspaces": []interface{}{ 44 map[string]interface{}{ 45 "name": "prod", 46 }, 47 }, 48 }, 49 err: nil, 50 }, 51 "with_a_prefix": { 52 config: map[string]interface{}{ 53 "organization": "hashicorp", 54 "workspaces": []interface{}{ 55 map[string]interface{}{ 56 "prefix": "my-app-", 57 }, 58 }, 59 }, 60 err: nil, 61 }, 62 "without_either_a_name_and_a_prefix": { 63 config: map[string]interface{}{ 64 "organization": "hashicorp", 65 "workspaces": []interface{}{ 66 map[string]interface{}{}, 67 }, 68 }, 69 err: errors.New("either workspace 'name' or 'prefix' is required"), 70 }, 71 "with_both_a_name_and_a_prefix": { 72 config: map[string]interface{}{ 73 "organization": "hashicorp", 74 "workspaces": []interface{}{ 75 map[string]interface{}{ 76 "name": "prod", 77 "prefix": "my-app-", 78 }, 79 }, 80 }, 81 err: errors.New("only one of workspace 'name' or 'prefix' is allowed"), 82 }, 83 "with_an_unknown_host": { 84 config: map[string]interface{}{ 85 "hostname": "nonexisting.local", 86 "organization": "hashicorp", 87 "workspaces": []interface{}{ 88 map[string]interface{}{ 89 "name": "prod", 90 }, 91 }, 92 }, 93 err: errors.New("Failed to request discovery document"), 94 }, 95 } 96 97 for name, tc := range cases { 98 s := testServer(t) 99 b := New(testDisco(s)) 100 101 // Get the proper config structure 102 rc, err := config.NewRawConfig(tc.config) 103 if err != nil { 104 t.Fatalf("%s: error creating raw config: %v", name, err) 105 } 106 conf := terraform.NewResourceConfig(rc) 107 108 // Validate 109 warns, errs := b.Validate(conf) 110 if len(warns) > 0 { 111 t.Fatalf("%s: validation warnings: %v", name, warns) 112 } 113 if len(errs) > 0 { 114 t.Fatalf("%s: validation errors: %v", name, errs) 115 } 116 117 // Configure 118 err = b.Configure(conf) 119 if err != tc.err && err != nil && tc.err != nil && !strings.Contains(err.Error(), tc.err.Error()) { 120 t.Fatalf("%s: expected error %q, got: %q", name, tc.err, err) 121 } 122 } 123 } 124 125 func TestRemote_versionConstraints(t *testing.T) { 126 cases := map[string]struct { 127 config map[string]interface{} 128 prerelease string 129 version string 130 err error 131 }{ 132 "compatible version": { 133 config: map[string]interface{}{ 134 "organization": "hashicorp", 135 "workspaces": []interface{}{ 136 map[string]interface{}{ 137 "name": "prod", 138 }, 139 }, 140 }, 141 version: "0.11.1", 142 }, 143 "version too old": { 144 config: map[string]interface{}{ 145 "organization": "hashicorp", 146 "workspaces": []interface{}{ 147 map[string]interface{}{ 148 "name": "prod", 149 }, 150 }, 151 }, 152 version: "0.10.1", 153 err: errors.New("upgrade Terraform to >= 0.11.8"), 154 }, 155 "version too new": { 156 config: map[string]interface{}{ 157 "organization": "hashicorp", 158 "workspaces": []interface{}{ 159 map[string]interface{}{ 160 "name": "prod", 161 }, 162 }, 163 }, 164 version: "0.12.0", 165 err: errors.New("downgrade Terraform to <= 0.11.11"), 166 }, 167 } 168 169 // Save and restore the actual version. 170 p := version.Prerelease 171 v := version.Version 172 defer func() { 173 version.Prerelease = p 174 version.Version = v 175 }() 176 177 for name, tc := range cases { 178 s := testServer(t) 179 b := New(testDisco(s)) 180 181 // Set the version for this test. 182 version.Prerelease = tc.prerelease 183 version.Version = tc.version 184 185 // Get the proper config structure 186 rc, err := config.NewRawConfig(tc.config) 187 if err != nil { 188 t.Fatalf("%s: error creating raw config: %v", name, err) 189 } 190 conf := terraform.NewResourceConfig(rc) 191 192 // Validate 193 warns, errs := b.Validate(conf) 194 if len(warns) > 0 { 195 t.Fatalf("%s: validation warnings: %v", name, warns) 196 } 197 if len(errs) > 0 { 198 t.Fatalf("%s: validation errors: %v", name, errs) 199 } 200 201 // Configure 202 err = b.Configure(conf) 203 if err != tc.err && err != nil && tc.err != nil && !strings.Contains(err.Error(), tc.err.Error()) { 204 t.Fatalf("%s: expected error %q, got: %q", name, tc.err, err) 205 } 206 } 207 } 208 209 func TestRemote_localBackend(t *testing.T) { 210 b := testBackendDefault(t) 211 212 local, ok := b.local.(*backendLocal.Local) 213 if !ok { 214 t.Fatalf("expected b.local to be \"*local.Local\", got: %T", b.local) 215 } 216 217 remote, ok := local.Backend.(*Remote) 218 if !ok { 219 t.Fatalf("expected local.Backend to be *remote.Remote, got: %T", remote) 220 } 221 } 222 223 func TestRemote_addAndRemoveStatesDefault(t *testing.T) { 224 b := testBackendDefault(t) 225 if _, err := b.States(); err != backend.ErrNamedStatesNotSupported { 226 t.Fatalf("expected error %v, got %v", backend.ErrNamedStatesNotSupported, err) 227 } 228 229 if _, err := b.State(backend.DefaultStateName); err != nil { 230 t.Fatalf("expected no error, got %v", err) 231 } 232 233 if _, err := b.State("prod"); err != backend.ErrNamedStatesNotSupported { 234 t.Fatalf("expected error %v, got %v", backend.ErrNamedStatesNotSupported, err) 235 } 236 237 if err := b.DeleteState(backend.DefaultStateName); err != nil { 238 t.Fatalf("expected no error, got %v", err) 239 } 240 241 if err := b.DeleteState("prod"); err != backend.ErrNamedStatesNotSupported { 242 t.Fatalf("expected error %v, got %v", backend.ErrNamedStatesNotSupported, err) 243 } 244 } 245 246 func TestRemote_addAndRemoveStatesNoDefault(t *testing.T) { 247 b := testBackendNoDefault(t) 248 states, err := b.States() 249 if err != nil { 250 t.Fatal(err) 251 } 252 253 expectedStates := []string(nil) 254 if !reflect.DeepEqual(states, expectedStates) { 255 t.Fatalf("expected states %#+v, got %#+v", expectedStates, states) 256 } 257 258 if _, err := b.State(backend.DefaultStateName); err != backend.ErrDefaultStateNotSupported { 259 t.Fatalf("expected error %v, got %v", backend.ErrDefaultStateNotSupported, err) 260 } 261 262 expectedA := "test_A" 263 if _, err := b.State(expectedA); err != nil { 264 t.Fatal(err) 265 } 266 267 states, err = b.States() 268 if err != nil { 269 t.Fatal(err) 270 } 271 272 expectedStates = append(expectedStates, expectedA) 273 if !reflect.DeepEqual(states, expectedStates) { 274 t.Fatalf("expected %#+v, got %#+v", expectedStates, states) 275 } 276 277 expectedB := "test_B" 278 if _, err := b.State(expectedB); err != nil { 279 t.Fatal(err) 280 } 281 282 states, err = b.States() 283 if err != nil { 284 t.Fatal(err) 285 } 286 287 expectedStates = append(expectedStates, expectedB) 288 if !reflect.DeepEqual(states, expectedStates) { 289 t.Fatalf("expected %#+v, got %#+v", expectedStates, states) 290 } 291 292 if err := b.DeleteState(backend.DefaultStateName); err != backend.ErrDefaultStateNotSupported { 293 t.Fatalf("expected error %v, got %v", backend.ErrDefaultStateNotSupported, err) 294 } 295 296 if err := b.DeleteState(expectedA); err != nil { 297 t.Fatal(err) 298 } 299 300 states, err = b.States() 301 if err != nil { 302 t.Fatal(err) 303 } 304 305 expectedStates = []string{expectedB} 306 if !reflect.DeepEqual(states, expectedStates) { 307 t.Fatalf("expected %#+v got %#+v", expectedStates, states) 308 } 309 310 if err := b.DeleteState(expectedB); err != nil { 311 t.Fatal(err) 312 } 313 314 states, err = b.States() 315 if err != nil { 316 t.Fatal(err) 317 } 318 319 expectedStates = []string(nil) 320 if !reflect.DeepEqual(states, expectedStates) { 321 t.Fatalf("expected %#+v, got %#+v", expectedStates, states) 322 } 323 } 324 325 func TestRemote_checkConstraints(t *testing.T) { 326 b := testBackendDefault(t) 327 328 cases := map[string]struct { 329 constraints *disco.Constraints 330 prerelease string 331 version string 332 result string 333 }{ 334 "compatible version": { 335 constraints: &disco.Constraints{ 336 Minimum: "0.11.0", 337 Maximum: "0.11.11", 338 }, 339 version: "0.11.1", 340 result: "", 341 }, 342 "version too old": { 343 constraints: &disco.Constraints{ 344 Minimum: "0.11.0", 345 Maximum: "0.11.11", 346 }, 347 version: "0.10.1", 348 result: "upgrade Terraform to >= 0.11.0", 349 }, 350 "version too new": { 351 constraints: &disco.Constraints{ 352 Minimum: "0.11.0", 353 Maximum: "0.11.11", 354 }, 355 version: "0.12.0", 356 result: "downgrade Terraform to <= 0.11.11", 357 }, 358 "version excluded - ordered": { 359 constraints: &disco.Constraints{ 360 Minimum: "0.11.0", 361 Excluding: []string{"0.11.7", "0.11.8"}, 362 Maximum: "0.11.11", 363 }, 364 version: "0.11.7", 365 result: "upgrade Terraform to > 0.11.8", 366 }, 367 "version excluded - unordered": { 368 constraints: &disco.Constraints{ 369 Minimum: "0.11.0", 370 Excluding: []string{"0.11.8", "0.11.6"}, 371 Maximum: "0.11.11", 372 }, 373 version: "0.11.6", 374 result: "upgrade Terraform to > 0.11.8", 375 }, 376 "list versions": { 377 constraints: &disco.Constraints{ 378 Minimum: "0.11.0", 379 Maximum: "0.11.11", 380 }, 381 version: "0.10.1", 382 result: "versions >= 0.11.0, <= 0.11.11.", 383 }, 384 "list exclusion": { 385 constraints: &disco.Constraints{ 386 Minimum: "0.11.0", 387 Excluding: []string{"0.11.6"}, 388 Maximum: "0.11.11", 389 }, 390 version: "0.11.6", 391 result: "excluding version 0.11.6.", 392 }, 393 "list exclusions": { 394 constraints: &disco.Constraints{ 395 Minimum: "0.11.0", 396 Excluding: []string{"0.11.8", "0.11.6"}, 397 Maximum: "0.11.11", 398 }, 399 version: "0.11.6", 400 result: "excluding versions 0.11.6, 0.11.8.", 401 }, 402 } 403 404 for name, tc := range cases { 405 version.Prerelease = tc.prerelease 406 version.Version = tc.version 407 408 // Check the constraints. 409 err := b.checkConstraints(tc.constraints) 410 if (err != nil || tc.result != "") && 411 (err == nil || !strings.Contains(err.Error(), tc.result)) { 412 t.Fatalf("%s: unexpected constraints result: %v", name, err) 413 } 414 } 415 }