github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/initwd/module_install_test.go (about) 1 package initwd 2 3 import ( 4 "bytes" 5 "context" 6 "flag" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 "testing" 13 14 "github.com/davecgh/go-spew/spew" 15 "github.com/go-test/deep" 16 "github.com/google/go-cmp/cmp" 17 version "github.com/hashicorp/go-version" 18 svchost "github.com/hashicorp/terraform-svchost" 19 "github.com/hashicorp/terraform/internal/addrs" 20 "github.com/hashicorp/terraform/internal/configs" 21 "github.com/hashicorp/terraform/internal/configs/configload" 22 "github.com/hashicorp/terraform/internal/copy" 23 "github.com/hashicorp/terraform/internal/registry" 24 "github.com/hashicorp/terraform/internal/tfdiags" 25 26 _ "github.com/hashicorp/terraform/internal/logging" 27 ) 28 29 func TestMain(m *testing.M) { 30 flag.Parse() 31 os.Exit(m.Run()) 32 } 33 34 func TestModuleInstaller(t *testing.T) { 35 fixtureDir := filepath.Clean("testdata/local-modules") 36 dir, done := tempChdir(t, fixtureDir) 37 defer done() 38 39 hooks := &testInstallHooks{} 40 41 modulesDir := filepath.Join(dir, ".terraform/modules") 42 inst := NewModuleInstaller(modulesDir, nil) 43 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 44 assertNoDiagnostics(t, diags) 45 46 wantCalls := []testInstallHookCall{ 47 { 48 Name: "Install", 49 ModuleAddr: "child_a", 50 PackageAddr: "", 51 LocalPath: "child_a", 52 }, 53 { 54 Name: "Install", 55 ModuleAddr: "child_a.child_b", 56 PackageAddr: "", 57 LocalPath: "child_a/child_b", 58 }, 59 } 60 61 if assertResultDeepEqual(t, hooks.Calls, wantCalls) { 62 return 63 } 64 65 loader, err := configload.NewLoader(&configload.Config{ 66 ModulesDir: modulesDir, 67 }) 68 if err != nil { 69 t.Fatal(err) 70 } 71 72 // Make sure the configuration is loadable now. 73 // (This ensures that correct information is recorded in the manifest.) 74 config, loadDiags := loader.LoadConfig(".") 75 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 76 77 wantTraces := map[string]string{ 78 "": "in root module", 79 "child_a": "in child_a module", 80 "child_a.child_b": "in child_b module", 81 } 82 gotTraces := map[string]string{} 83 config.DeepEach(func(c *configs.Config) { 84 path := strings.Join(c.Path, ".") 85 if c.Module.Variables["v"] == nil { 86 gotTraces[path] = "<missing>" 87 return 88 } 89 varDesc := c.Module.Variables["v"].Description 90 gotTraces[path] = varDesc 91 }) 92 assertResultDeepEqual(t, gotTraces, wantTraces) 93 } 94 95 func TestModuleInstaller_error(t *testing.T) { 96 fixtureDir := filepath.Clean("testdata/local-module-error") 97 dir, done := tempChdir(t, fixtureDir) 98 defer done() 99 100 hooks := &testInstallHooks{} 101 102 modulesDir := filepath.Join(dir, ".terraform/modules") 103 inst := NewModuleInstaller(modulesDir, nil) 104 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 105 106 if !diags.HasErrors() { 107 t.Fatal("expected error") 108 } else { 109 assertDiagnosticSummary(t, diags, "Invalid module source address") 110 } 111 } 112 113 func TestModuleInstaller_packageEscapeError(t *testing.T) { 114 fixtureDir := filepath.Clean("testdata/load-module-package-escape") 115 dir, done := tempChdir(t, fixtureDir) 116 defer done() 117 118 // For this particular test we need an absolute path in the root module 119 // that must actually resolve to our temporary directory in "dir", so 120 // we need to do a little rewriting. We replace the arbitrary placeholder 121 // %%BASE%% with the temporary directory path. 122 { 123 rootFilename := filepath.Join(dir, "package-escape.tf") 124 template, err := ioutil.ReadFile(rootFilename) 125 if err != nil { 126 t.Fatal(err) 127 } 128 final := bytes.ReplaceAll(template, []byte("%%BASE%%"), []byte(filepath.ToSlash(dir))) 129 err = ioutil.WriteFile(rootFilename, final, 0644) 130 if err != nil { 131 t.Fatal(err) 132 } 133 } 134 135 hooks := &testInstallHooks{} 136 137 modulesDir := filepath.Join(dir, ".terraform/modules") 138 inst := NewModuleInstaller(modulesDir, nil) 139 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 140 141 if !diags.HasErrors() { 142 t.Fatal("expected error") 143 } else { 144 assertDiagnosticSummary(t, diags, "Local module path escapes module package") 145 } 146 } 147 148 func TestModuleInstaller_explicitPackageBoundary(t *testing.T) { 149 fixtureDir := filepath.Clean("testdata/load-module-package-prefix") 150 dir, done := tempChdir(t, fixtureDir) 151 defer done() 152 153 // For this particular test we need an absolute path in the root module 154 // that must actually resolve to our temporary directory in "dir", so 155 // we need to do a little rewriting. We replace the arbitrary placeholder 156 // %%BASE%% with the temporary directory path. 157 { 158 rootFilename := filepath.Join(dir, "package-prefix.tf") 159 template, err := ioutil.ReadFile(rootFilename) 160 if err != nil { 161 t.Fatal(err) 162 } 163 final := bytes.ReplaceAll(template, []byte("%%BASE%%"), []byte(filepath.ToSlash(dir))) 164 err = ioutil.WriteFile(rootFilename, final, 0644) 165 if err != nil { 166 t.Fatal(err) 167 } 168 } 169 170 hooks := &testInstallHooks{} 171 172 modulesDir := filepath.Join(dir, ".terraform/modules") 173 inst := NewModuleInstaller(modulesDir, nil) 174 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 175 176 if diags.HasErrors() { 177 t.Fatalf("unexpected errors\n%s", diags.Err().Error()) 178 } 179 } 180 181 func TestModuleInstaller_invalid_version_constraint_error(t *testing.T) { 182 fixtureDir := filepath.Clean("testdata/invalid-version-constraint") 183 dir, done := tempChdir(t, fixtureDir) 184 defer done() 185 186 hooks := &testInstallHooks{} 187 188 modulesDir := filepath.Join(dir, ".terraform/modules") 189 inst := NewModuleInstaller(modulesDir, nil) 190 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 191 192 if !diags.HasErrors() { 193 t.Fatal("expected error") 194 } else { 195 // We use the presence of the "version" argument as a heuristic for 196 // user intent to use a registry module, and so we intentionally catch 197 // this as an invalid registry module address rather than an invalid 198 // version constraint, so we can surface the specific address parsing 199 // error instead of a generic version constraint error. 200 assertDiagnosticSummary(t, diags, "Invalid registry module source address") 201 } 202 } 203 204 func TestModuleInstaller_invalidVersionConstraintGetter(t *testing.T) { 205 fixtureDir := filepath.Clean("testdata/invalid-version-constraint") 206 dir, done := tempChdir(t, fixtureDir) 207 defer done() 208 209 hooks := &testInstallHooks{} 210 211 modulesDir := filepath.Join(dir, ".terraform/modules") 212 inst := NewModuleInstaller(modulesDir, nil) 213 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 214 215 if !diags.HasErrors() { 216 t.Fatal("expected error") 217 } else { 218 // We use the presence of the "version" argument as a heuristic for 219 // user intent to use a registry module, and so we intentionally catch 220 // this as an invalid registry module address rather than an invalid 221 // version constraint, so we can surface the specific address parsing 222 // error instead of a generic version constraint error. 223 assertDiagnosticSummary(t, diags, "Invalid registry module source address") 224 } 225 } 226 227 func TestModuleInstaller_invalidVersionConstraintLocal(t *testing.T) { 228 fixtureDir := filepath.Clean("testdata/invalid-version-constraint-local") 229 dir, done := tempChdir(t, fixtureDir) 230 defer done() 231 232 hooks := &testInstallHooks{} 233 234 modulesDir := filepath.Join(dir, ".terraform/modules") 235 inst := NewModuleInstaller(modulesDir, nil) 236 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 237 238 if !diags.HasErrors() { 239 t.Fatal("expected error") 240 } else { 241 // We use the presence of the "version" argument as a heuristic for 242 // user intent to use a registry module, and so we intentionally catch 243 // this as an invalid registry module address rather than an invalid 244 // version constraint, so we can surface the specific address parsing 245 // error instead of a generic version constraint error. 246 assertDiagnosticSummary(t, diags, "Invalid registry module source address") 247 } 248 } 249 250 func TestModuleInstaller_symlink(t *testing.T) { 251 fixtureDir := filepath.Clean("testdata/local-module-symlink") 252 dir, done := tempChdir(t, fixtureDir) 253 defer done() 254 255 hooks := &testInstallHooks{} 256 257 modulesDir := filepath.Join(dir, ".terraform/modules") 258 inst := NewModuleInstaller(modulesDir, nil) 259 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 260 assertNoDiagnostics(t, diags) 261 262 wantCalls := []testInstallHookCall{ 263 { 264 Name: "Install", 265 ModuleAddr: "child_a", 266 PackageAddr: "", 267 LocalPath: "child_a", 268 }, 269 { 270 Name: "Install", 271 ModuleAddr: "child_a.child_b", 272 PackageAddr: "", 273 LocalPath: "child_a/child_b", 274 }, 275 } 276 277 if assertResultDeepEqual(t, hooks.Calls, wantCalls) { 278 return 279 } 280 281 loader, err := configload.NewLoader(&configload.Config{ 282 ModulesDir: modulesDir, 283 }) 284 if err != nil { 285 t.Fatal(err) 286 } 287 288 // Make sure the configuration is loadable now. 289 // (This ensures that correct information is recorded in the manifest.) 290 config, loadDiags := loader.LoadConfig(".") 291 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 292 293 wantTraces := map[string]string{ 294 "": "in root module", 295 "child_a": "in child_a module", 296 "child_a.child_b": "in child_b module", 297 } 298 gotTraces := map[string]string{} 299 config.DeepEach(func(c *configs.Config) { 300 path := strings.Join(c.Path, ".") 301 if c.Module.Variables["v"] == nil { 302 gotTraces[path] = "<missing>" 303 return 304 } 305 varDesc := c.Module.Variables["v"].Description 306 gotTraces[path] = varDesc 307 }) 308 assertResultDeepEqual(t, gotTraces, wantTraces) 309 } 310 311 func TestLoaderInstallModules_registry(t *testing.T) { 312 if os.Getenv("TF_ACC") == "" { 313 t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it") 314 } 315 316 fixtureDir := filepath.Clean("testdata/registry-modules") 317 tmpDir, done := tempChdir(t, fixtureDir) 318 // the module installer runs filepath.EvalSymlinks() on the destination 319 // directory before copying files, and the resultant directory is what is 320 // returned by the install hooks. Without this, tests could fail on machines 321 // where the default temp dir was a symlink. 322 dir, err := filepath.EvalSymlinks(tmpDir) 323 if err != nil { 324 t.Error(err) 325 } 326 327 defer done() 328 329 hooks := &testInstallHooks{} 330 modulesDir := filepath.Join(dir, ".terraform/modules") 331 inst := NewModuleInstaller(modulesDir, registry.NewClient(nil, nil)) 332 _, diags := inst.InstallModules(context.Background(), dir, false, hooks) 333 assertNoDiagnostics(t, diags) 334 335 v := version.Must(version.NewVersion("0.0.1")) 336 337 wantCalls := []testInstallHookCall{ 338 // the configuration builder visits each level of calls in lexicographical 339 // order by name, so the following list is kept in the same order. 340 341 // acctest_child_a accesses //modules/child_a directly 342 { 343 Name: "Download", 344 ModuleAddr: "acctest_child_a", 345 PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", // intentionally excludes the subdir because we're downloading the whole package here 346 Version: v, 347 }, 348 { 349 Name: "Install", 350 ModuleAddr: "acctest_child_a", 351 Version: v, 352 // NOTE: This local path and the other paths derived from it below 353 // can vary depending on how the registry is implemented. At the 354 // time of writing this test, registry.terraform.io returns 355 // git repository source addresses and so this path refers to the 356 // root of the git clone, but historically the registry referred 357 // to GitHub-provided tar archives which meant that there was an 358 // extra level of subdirectory here for the typical directory 359 // nesting in tar archives, which would've been reflected as 360 // an extra segment on this path. If this test fails due to an 361 // additional path segment in future, then a change to the upstream 362 // registry might be the root cause. 363 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_a"), 364 }, 365 366 // acctest_child_a.child_b 367 // (no download because it's a relative path inside acctest_child_a) 368 { 369 Name: "Install", 370 ModuleAddr: "acctest_child_a.child_b", 371 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_b"), 372 }, 373 374 // acctest_child_b accesses //modules/child_b directly 375 { 376 Name: "Download", 377 ModuleAddr: "acctest_child_b", 378 PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", // intentionally excludes the subdir because we're downloading the whole package here 379 Version: v, 380 }, 381 { 382 Name: "Install", 383 ModuleAddr: "acctest_child_b", 384 Version: v, 385 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_b/modules/child_b"), 386 }, 387 388 // acctest_root 389 { 390 Name: "Download", 391 ModuleAddr: "acctest_root", 392 PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", 393 Version: v, 394 }, 395 { 396 Name: "Install", 397 ModuleAddr: "acctest_root", 398 Version: v, 399 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root"), 400 }, 401 402 // acctest_root.child_a 403 // (no download because it's a relative path inside acctest_root) 404 { 405 Name: "Install", 406 ModuleAddr: "acctest_root.child_a", 407 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_a"), 408 }, 409 410 // acctest_root.child_a.child_b 411 // (no download because it's a relative path inside acctest_root, via acctest_root.child_a) 412 { 413 Name: "Install", 414 ModuleAddr: "acctest_root.child_a.child_b", 415 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_b"), 416 }, 417 } 418 419 if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" { 420 t.Fatalf("wrong installer calls\n%s", diff) 421 } 422 423 //check that the registry reponses were cached 424 packageAddr := addrs.ModuleRegistryPackage{ 425 Host: svchost.Hostname("registry.terraform.io"), 426 Namespace: "hashicorp", 427 Name: "module-installer-acctest", 428 TargetSystem: "aws", 429 } 430 if _, ok := inst.registryPackageVersions[packageAddr]; !ok { 431 t.Errorf("module versions cache was not populated\ngot: %s\nwant: key hashicorp/module-installer-acctest/aws", spew.Sdump(inst.registryPackageVersions)) 432 } 433 if _, ok := inst.registryPackageSources[moduleVersion{module: packageAddr, version: "0.0.1"}]; !ok { 434 t.Errorf("module download url cache was not populated\ngot: %s", spew.Sdump(inst.registryPackageSources)) 435 } 436 437 loader, err := configload.NewLoader(&configload.Config{ 438 ModulesDir: modulesDir, 439 }) 440 if err != nil { 441 t.Fatal(err) 442 } 443 444 // Make sure the configuration is loadable now. 445 // (This ensures that correct information is recorded in the manifest.) 446 config, loadDiags := loader.LoadConfig(".") 447 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 448 449 wantTraces := map[string]string{ 450 "": "in local caller for registry-modules", 451 "acctest_root": "in root module", 452 "acctest_root.child_a": "in child_a module", 453 "acctest_root.child_a.child_b": "in child_b module", 454 "acctest_child_a": "in child_a module", 455 "acctest_child_a.child_b": "in child_b module", 456 "acctest_child_b": "in child_b module", 457 } 458 gotTraces := map[string]string{} 459 config.DeepEach(func(c *configs.Config) { 460 path := strings.Join(c.Path, ".") 461 if c.Module.Variables["v"] == nil { 462 gotTraces[path] = "<missing>" 463 return 464 } 465 varDesc := c.Module.Variables["v"].Description 466 gotTraces[path] = varDesc 467 }) 468 assertResultDeepEqual(t, gotTraces, wantTraces) 469 470 } 471 472 func TestLoaderInstallModules_goGetter(t *testing.T) { 473 if os.Getenv("TF_ACC") == "" { 474 t.Skip("this test accesses github.com; set TF_ACC=1 to run it") 475 } 476 477 fixtureDir := filepath.Clean("testdata/go-getter-modules") 478 tmpDir, done := tempChdir(t, fixtureDir) 479 // the module installer runs filepath.EvalSymlinks() on the destination 480 // directory before copying files, and the resultant directory is what is 481 // returned by the install hooks. Without this, tests could fail on machines 482 // where the default temp dir was a symlink. 483 dir, err := filepath.EvalSymlinks(tmpDir) 484 if err != nil { 485 t.Error(err) 486 } 487 defer done() 488 489 hooks := &testInstallHooks{} 490 modulesDir := filepath.Join(dir, ".terraform/modules") 491 inst := NewModuleInstaller(modulesDir, registry.NewClient(nil, nil)) 492 _, diags := inst.InstallModules(context.Background(), dir, false, hooks) 493 assertNoDiagnostics(t, diags) 494 495 wantCalls := []testInstallHookCall{ 496 // the configuration builder visits each level of calls in lexicographical 497 // order by name, so the following list is kept in the same order. 498 499 // acctest_child_a accesses //modules/child_a directly 500 { 501 Name: "Download", 502 ModuleAddr: "acctest_child_a", 503 PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1", // intentionally excludes the subdir because we're downloading the whole repo here 504 }, 505 { 506 Name: "Install", 507 ModuleAddr: "acctest_child_a", 508 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_a"), 509 }, 510 511 // acctest_child_a.child_b 512 // (no download because it's a relative path inside acctest_child_a) 513 { 514 Name: "Install", 515 ModuleAddr: "acctest_child_a.child_b", 516 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_b"), 517 }, 518 519 // acctest_child_b accesses //modules/child_b directly 520 { 521 Name: "Download", 522 ModuleAddr: "acctest_child_b", 523 PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1", // intentionally excludes the subdir because we're downloading the whole package here 524 }, 525 { 526 Name: "Install", 527 ModuleAddr: "acctest_child_b", 528 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_b/modules/child_b"), 529 }, 530 531 // acctest_root 532 { 533 Name: "Download", 534 ModuleAddr: "acctest_root", 535 PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1", 536 }, 537 { 538 Name: "Install", 539 ModuleAddr: "acctest_root", 540 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root"), 541 }, 542 543 // acctest_root.child_a 544 // (no download because it's a relative path inside acctest_root) 545 { 546 Name: "Install", 547 ModuleAddr: "acctest_root.child_a", 548 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_a"), 549 }, 550 551 // acctest_root.child_a.child_b 552 // (no download because it's a relative path inside acctest_root, via acctest_root.child_a) 553 { 554 Name: "Install", 555 ModuleAddr: "acctest_root.child_a.child_b", 556 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_b"), 557 }, 558 } 559 560 if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" { 561 t.Fatalf("wrong installer calls\n%s", diff) 562 } 563 564 loader, err := configload.NewLoader(&configload.Config{ 565 ModulesDir: modulesDir, 566 }) 567 if err != nil { 568 t.Fatal(err) 569 } 570 571 // Make sure the configuration is loadable now. 572 // (This ensures that correct information is recorded in the manifest.) 573 config, loadDiags := loader.LoadConfig(".") 574 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 575 576 wantTraces := map[string]string{ 577 "": "in local caller for go-getter-modules", 578 "acctest_root": "in root module", 579 "acctest_root.child_a": "in child_a module", 580 "acctest_root.child_a.child_b": "in child_b module", 581 "acctest_child_a": "in child_a module", 582 "acctest_child_a.child_b": "in child_b module", 583 "acctest_child_b": "in child_b module", 584 } 585 gotTraces := map[string]string{} 586 config.DeepEach(func(c *configs.Config) { 587 path := strings.Join(c.Path, ".") 588 if c.Module.Variables["v"] == nil { 589 gotTraces[path] = "<missing>" 590 return 591 } 592 varDesc := c.Module.Variables["v"].Description 593 gotTraces[path] = varDesc 594 }) 595 assertResultDeepEqual(t, gotTraces, wantTraces) 596 597 } 598 599 type testInstallHooks struct { 600 Calls []testInstallHookCall 601 } 602 603 type testInstallHookCall struct { 604 Name string 605 ModuleAddr string 606 PackageAddr string 607 Version *version.Version 608 LocalPath string 609 } 610 611 func (h *testInstallHooks) Download(moduleAddr, packageAddr string, version *version.Version) { 612 h.Calls = append(h.Calls, testInstallHookCall{ 613 Name: "Download", 614 ModuleAddr: moduleAddr, 615 PackageAddr: packageAddr, 616 Version: version, 617 }) 618 } 619 620 func (h *testInstallHooks) Install(moduleAddr string, version *version.Version, localPath string) { 621 h.Calls = append(h.Calls, testInstallHookCall{ 622 Name: "Install", 623 ModuleAddr: moduleAddr, 624 Version: version, 625 LocalPath: localPath, 626 }) 627 } 628 629 // tempChdir copies the contents of the given directory to a temporary 630 // directory and changes the test process's current working directory to 631 // point to that directory. Also returned is a function that should be 632 // called at the end of the test (e.g. via "defer") to restore the previous 633 // working directory. 634 // 635 // Tests using this helper cannot safely be run in parallel with other tests. 636 func tempChdir(t *testing.T, sourceDir string) (string, func()) { 637 t.Helper() 638 639 tmpDir, err := ioutil.TempDir("", "terraform-configload") 640 if err != nil { 641 t.Fatalf("failed to create temporary directory: %s", err) 642 return "", nil 643 } 644 645 if err := copy.CopyDir(tmpDir, sourceDir); err != nil { 646 t.Fatalf("failed to copy fixture to temporary directory: %s", err) 647 return "", nil 648 } 649 650 oldDir, err := os.Getwd() 651 if err != nil { 652 t.Fatalf("failed to determine current working directory: %s", err) 653 return "", nil 654 } 655 656 err = os.Chdir(tmpDir) 657 if err != nil { 658 t.Fatalf("failed to switch to temp dir %s: %s", tmpDir, err) 659 return "", nil 660 } 661 662 // Most of the tests need this, so we'll make it just in case. 663 os.MkdirAll(filepath.Join(tmpDir, ".terraform/modules"), os.ModePerm) 664 665 t.Logf("tempChdir switched to %s after copying from %s", tmpDir, sourceDir) 666 667 return tmpDir, func() { 668 err := os.Chdir(oldDir) 669 if err != nil { 670 panic(fmt.Errorf("failed to restore previous working directory %s: %s", oldDir, err)) 671 } 672 673 if os.Getenv("TF_CONFIGLOAD_TEST_KEEP_TMP") == "" { 674 os.RemoveAll(tmpDir) 675 } 676 } 677 } 678 679 func assertNoDiagnostics(t *testing.T, diags tfdiags.Diagnostics) bool { 680 t.Helper() 681 return assertDiagnosticCount(t, diags, 0) 682 } 683 684 func assertDiagnosticCount(t *testing.T, diags tfdiags.Diagnostics, want int) bool { 685 t.Helper() 686 if len(diags) != 0 { 687 t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want) 688 for _, diag := range diags { 689 t.Logf("- %#v", diag) 690 } 691 return true 692 } 693 return false 694 } 695 696 func assertDiagnosticSummary(t *testing.T, diags tfdiags.Diagnostics, want string) bool { 697 t.Helper() 698 699 for _, diag := range diags { 700 if diag.Description().Summary == want { 701 return false 702 } 703 } 704 705 t.Errorf("missing diagnostic summary %q", want) 706 for _, diag := range diags { 707 t.Logf("- %#v", diag) 708 } 709 return true 710 } 711 712 func assertResultDeepEqual(t *testing.T, got, want interface{}) bool { 713 t.Helper() 714 if diff := deep.Equal(got, want); diff != nil { 715 for _, problem := range diff { 716 t.Errorf("%s", problem) 717 } 718 return true 719 } 720 return false 721 }