github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/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/cycloidio/terraform/addrs" 20 "github.com/cycloidio/terraform/configs" 21 "github.com/cycloidio/terraform/configs/configload" 22 "github.com/cycloidio/terraform/copy" 23 "github.com/cycloidio/terraform/registry" 24 "github.com/cycloidio/terraform/tfdiags" 25 26 _ "github.com/cycloidio/terraform/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 assertDiagnosticSummary(t, diags, "Invalid version constraint") 196 } 197 } 198 199 func TestModuleInstaller_invalidVersionConstraintGetter(t *testing.T) { 200 fixtureDir := filepath.Clean("testdata/invalid-version-constraint") 201 dir, done := tempChdir(t, fixtureDir) 202 defer done() 203 204 hooks := &testInstallHooks{} 205 206 modulesDir := filepath.Join(dir, ".terraform/modules") 207 inst := NewModuleInstaller(modulesDir, nil) 208 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 209 210 if !diags.HasErrors() { 211 t.Fatal("expected error") 212 } else { 213 assertDiagnosticSummary(t, diags, "Invalid version constraint") 214 } 215 } 216 217 func TestModuleInstaller_invalidVersionConstraintLocal(t *testing.T) { 218 fixtureDir := filepath.Clean("testdata/invalid-version-constraint-local") 219 dir, done := tempChdir(t, fixtureDir) 220 defer done() 221 222 hooks := &testInstallHooks{} 223 224 modulesDir := filepath.Join(dir, ".terraform/modules") 225 inst := NewModuleInstaller(modulesDir, nil) 226 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 227 228 if !diags.HasErrors() { 229 t.Fatal("expected error") 230 } else { 231 assertDiagnosticSummary(t, diags, "Invalid version constraint") 232 } 233 } 234 235 func TestModuleInstaller_symlink(t *testing.T) { 236 fixtureDir := filepath.Clean("testdata/local-module-symlink") 237 dir, done := tempChdir(t, fixtureDir) 238 defer done() 239 240 hooks := &testInstallHooks{} 241 242 modulesDir := filepath.Join(dir, ".terraform/modules") 243 inst := NewModuleInstaller(modulesDir, nil) 244 _, diags := inst.InstallModules(context.Background(), ".", false, hooks) 245 assertNoDiagnostics(t, diags) 246 247 wantCalls := []testInstallHookCall{ 248 { 249 Name: "Install", 250 ModuleAddr: "child_a", 251 PackageAddr: "", 252 LocalPath: "child_a", 253 }, 254 { 255 Name: "Install", 256 ModuleAddr: "child_a.child_b", 257 PackageAddr: "", 258 LocalPath: "child_a/child_b", 259 }, 260 } 261 262 if assertResultDeepEqual(t, hooks.Calls, wantCalls) { 263 return 264 } 265 266 loader, err := configload.NewLoader(&configload.Config{ 267 ModulesDir: modulesDir, 268 }) 269 if err != nil { 270 t.Fatal(err) 271 } 272 273 // Make sure the configuration is loadable now. 274 // (This ensures that correct information is recorded in the manifest.) 275 config, loadDiags := loader.LoadConfig(".") 276 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 277 278 wantTraces := map[string]string{ 279 "": "in root module", 280 "child_a": "in child_a module", 281 "child_a.child_b": "in child_b module", 282 } 283 gotTraces := map[string]string{} 284 config.DeepEach(func(c *configs.Config) { 285 path := strings.Join(c.Path, ".") 286 if c.Module.Variables["v"] == nil { 287 gotTraces[path] = "<missing>" 288 return 289 } 290 varDesc := c.Module.Variables["v"].Description 291 gotTraces[path] = varDesc 292 }) 293 assertResultDeepEqual(t, gotTraces, wantTraces) 294 } 295 296 func TestLoaderInstallModules_registry(t *testing.T) { 297 if os.Getenv("TF_ACC") == "" { 298 t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it") 299 } 300 301 fixtureDir := filepath.Clean("testdata/registry-modules") 302 tmpDir, done := tempChdir(t, fixtureDir) 303 // the module installer runs filepath.EvalSymlinks() on the destination 304 // directory before copying files, and the resultant directory is what is 305 // returned by the install hooks. Without this, tests could fail on machines 306 // where the default temp dir was a symlink. 307 dir, err := filepath.EvalSymlinks(tmpDir) 308 if err != nil { 309 t.Error(err) 310 } 311 312 defer done() 313 314 hooks := &testInstallHooks{} 315 modulesDir := filepath.Join(dir, ".terraform/modules") 316 inst := NewModuleInstaller(modulesDir, registry.NewClient(nil, nil)) 317 _, diags := inst.InstallModules(context.Background(), dir, false, hooks) 318 assertNoDiagnostics(t, diags) 319 320 v := version.Must(version.NewVersion("0.0.1")) 321 322 wantCalls := []testInstallHookCall{ 323 // the configuration builder visits each level of calls in lexicographical 324 // order by name, so the following list is kept in the same order. 325 326 // acctest_child_a accesses //modules/child_a directly 327 { 328 Name: "Download", 329 ModuleAddr: "acctest_child_a", 330 PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", // intentionally excludes the subdir because we're downloading the whole package here 331 Version: v, 332 }, 333 { 334 Name: "Install", 335 ModuleAddr: "acctest_child_a", 336 Version: v, 337 // NOTE: This local path and the other paths derived from it below 338 // can vary depending on how the registry is implemented. At the 339 // time of writing this test, registry.terraform.io returns 340 // git repository source addresses and so this path refers to the 341 // root of the git clone, but historically the registry referred 342 // to GitHub-provided tar archives which meant that there was an 343 // extra level of subdirectory here for the typical directory 344 // nesting in tar archives, which would've been reflected as 345 // an extra segment on this path. If this test fails due to an 346 // additional path segment in future, then a change to the upstream 347 // registry might be the root cause. 348 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_a"), 349 }, 350 351 // acctest_child_a.child_b 352 // (no download because it's a relative path inside acctest_child_a) 353 { 354 Name: "Install", 355 ModuleAddr: "acctest_child_a.child_b", 356 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_b"), 357 }, 358 359 // acctest_child_b accesses //modules/child_b directly 360 { 361 Name: "Download", 362 ModuleAddr: "acctest_child_b", 363 PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", // intentionally excludes the subdir because we're downloading the whole package here 364 Version: v, 365 }, 366 { 367 Name: "Install", 368 ModuleAddr: "acctest_child_b", 369 Version: v, 370 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_b/modules/child_b"), 371 }, 372 373 // acctest_root 374 { 375 Name: "Download", 376 ModuleAddr: "acctest_root", 377 PackageAddr: "registry.terraform.io/hashicorp/module-installer-acctest/aws", 378 Version: v, 379 }, 380 { 381 Name: "Install", 382 ModuleAddr: "acctest_root", 383 Version: v, 384 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root"), 385 }, 386 387 // acctest_root.child_a 388 // (no download because it's a relative path inside acctest_root) 389 { 390 Name: "Install", 391 ModuleAddr: "acctest_root.child_a", 392 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_a"), 393 }, 394 395 // acctest_root.child_a.child_b 396 // (no download because it's a relative path inside acctest_root, via acctest_root.child_a) 397 { 398 Name: "Install", 399 ModuleAddr: "acctest_root.child_a.child_b", 400 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_b"), 401 }, 402 } 403 404 if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" { 405 t.Fatalf("wrong installer calls\n%s", diff) 406 } 407 408 //check that the registry reponses were cached 409 packageAddr := addrs.ModuleRegistryPackage{ 410 Host: svchost.Hostname("registry.terraform.io"), 411 Namespace: "hashicorp", 412 Name: "module-installer-acctest", 413 TargetSystem: "aws", 414 } 415 if _, ok := inst.registryPackageVersions[packageAddr]; !ok { 416 t.Errorf("module versions cache was not populated\ngot: %s\nwant: key hashicorp/module-installer-acctest/aws", spew.Sdump(inst.registryPackageVersions)) 417 } 418 if _, ok := inst.registryPackageSources[moduleVersion{module: packageAddr, version: "0.0.1"}]; !ok { 419 t.Errorf("module download url cache was not populated\ngot: %s", spew.Sdump(inst.registryPackageSources)) 420 } 421 422 loader, err := configload.NewLoader(&configload.Config{ 423 ModulesDir: modulesDir, 424 }) 425 if err != nil { 426 t.Fatal(err) 427 } 428 429 // Make sure the configuration is loadable now. 430 // (This ensures that correct information is recorded in the manifest.) 431 config, loadDiags := loader.LoadConfig(".") 432 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 433 434 wantTraces := map[string]string{ 435 "": "in local caller for registry-modules", 436 "acctest_root": "in root module", 437 "acctest_root.child_a": "in child_a module", 438 "acctest_root.child_a.child_b": "in child_b module", 439 "acctest_child_a": "in child_a module", 440 "acctest_child_a.child_b": "in child_b module", 441 "acctest_child_b": "in child_b module", 442 } 443 gotTraces := map[string]string{} 444 config.DeepEach(func(c *configs.Config) { 445 path := strings.Join(c.Path, ".") 446 if c.Module.Variables["v"] == nil { 447 gotTraces[path] = "<missing>" 448 return 449 } 450 varDesc := c.Module.Variables["v"].Description 451 gotTraces[path] = varDesc 452 }) 453 assertResultDeepEqual(t, gotTraces, wantTraces) 454 455 } 456 457 func TestLoaderInstallModules_goGetter(t *testing.T) { 458 if os.Getenv("TF_ACC") == "" { 459 t.Skip("this test accesses github.com; set TF_ACC=1 to run it") 460 } 461 462 fixtureDir := filepath.Clean("testdata/go-getter-modules") 463 tmpDir, done := tempChdir(t, fixtureDir) 464 // the module installer runs filepath.EvalSymlinks() on the destination 465 // directory before copying files, and the resultant directory is what is 466 // returned by the install hooks. Without this, tests could fail on machines 467 // where the default temp dir was a symlink. 468 dir, err := filepath.EvalSymlinks(tmpDir) 469 if err != nil { 470 t.Error(err) 471 } 472 defer done() 473 474 hooks := &testInstallHooks{} 475 modulesDir := filepath.Join(dir, ".terraform/modules") 476 inst := NewModuleInstaller(modulesDir, registry.NewClient(nil, nil)) 477 _, diags := inst.InstallModules(context.Background(), dir, false, hooks) 478 assertNoDiagnostics(t, diags) 479 480 wantCalls := []testInstallHookCall{ 481 // the configuration builder visits each level of calls in lexicographical 482 // order by name, so the following list is kept in the same order. 483 484 // acctest_child_a accesses //modules/child_a directly 485 { 486 Name: "Download", 487 ModuleAddr: "acctest_child_a", 488 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 489 }, 490 { 491 Name: "Install", 492 ModuleAddr: "acctest_child_a", 493 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_a"), 494 }, 495 496 // acctest_child_a.child_b 497 // (no download because it's a relative path inside acctest_child_a) 498 { 499 Name: "Install", 500 ModuleAddr: "acctest_child_a.child_b", 501 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_a/modules/child_b"), 502 }, 503 504 // acctest_child_b accesses //modules/child_b directly 505 { 506 Name: "Download", 507 ModuleAddr: "acctest_child_b", 508 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 509 }, 510 { 511 Name: "Install", 512 ModuleAddr: "acctest_child_b", 513 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_child_b/modules/child_b"), 514 }, 515 516 // acctest_root 517 { 518 Name: "Download", 519 ModuleAddr: "acctest_root", 520 PackageAddr: "git::https://github.com/hashicorp/terraform-aws-module-installer-acctest.git?ref=v0.0.1", 521 }, 522 { 523 Name: "Install", 524 ModuleAddr: "acctest_root", 525 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root"), 526 }, 527 528 // acctest_root.child_a 529 // (no download because it's a relative path inside acctest_root) 530 { 531 Name: "Install", 532 ModuleAddr: "acctest_root.child_a", 533 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_a"), 534 }, 535 536 // acctest_root.child_a.child_b 537 // (no download because it's a relative path inside acctest_root, via acctest_root.child_a) 538 { 539 Name: "Install", 540 ModuleAddr: "acctest_root.child_a.child_b", 541 LocalPath: filepath.Join(dir, ".terraform/modules/acctest_root/modules/child_b"), 542 }, 543 } 544 545 if diff := cmp.Diff(wantCalls, hooks.Calls); diff != "" { 546 t.Fatalf("wrong installer calls\n%s", diff) 547 } 548 549 loader, err := configload.NewLoader(&configload.Config{ 550 ModulesDir: modulesDir, 551 }) 552 if err != nil { 553 t.Fatal(err) 554 } 555 556 // Make sure the configuration is loadable now. 557 // (This ensures that correct information is recorded in the manifest.) 558 config, loadDiags := loader.LoadConfig(".") 559 assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) 560 561 wantTraces := map[string]string{ 562 "": "in local caller for go-getter-modules", 563 "acctest_root": "in root module", 564 "acctest_root.child_a": "in child_a module", 565 "acctest_root.child_a.child_b": "in child_b module", 566 "acctest_child_a": "in child_a module", 567 "acctest_child_a.child_b": "in child_b module", 568 "acctest_child_b": "in child_b module", 569 } 570 gotTraces := map[string]string{} 571 config.DeepEach(func(c *configs.Config) { 572 path := strings.Join(c.Path, ".") 573 if c.Module.Variables["v"] == nil { 574 gotTraces[path] = "<missing>" 575 return 576 } 577 varDesc := c.Module.Variables["v"].Description 578 gotTraces[path] = varDesc 579 }) 580 assertResultDeepEqual(t, gotTraces, wantTraces) 581 582 } 583 584 type testInstallHooks struct { 585 Calls []testInstallHookCall 586 } 587 588 type testInstallHookCall struct { 589 Name string 590 ModuleAddr string 591 PackageAddr string 592 Version *version.Version 593 LocalPath string 594 } 595 596 func (h *testInstallHooks) Download(moduleAddr, packageAddr string, version *version.Version) { 597 h.Calls = append(h.Calls, testInstallHookCall{ 598 Name: "Download", 599 ModuleAddr: moduleAddr, 600 PackageAddr: packageAddr, 601 Version: version, 602 }) 603 } 604 605 func (h *testInstallHooks) Install(moduleAddr string, version *version.Version, localPath string) { 606 h.Calls = append(h.Calls, testInstallHookCall{ 607 Name: "Install", 608 ModuleAddr: moduleAddr, 609 Version: version, 610 LocalPath: localPath, 611 }) 612 } 613 614 // tempChdir copies the contents of the given directory to a temporary 615 // directory and changes the test process's current working directory to 616 // point to that directory. Also returned is a function that should be 617 // called at the end of the test (e.g. via "defer") to restore the previous 618 // working directory. 619 // 620 // Tests using this helper cannot safely be run in parallel with other tests. 621 func tempChdir(t *testing.T, sourceDir string) (string, func()) { 622 t.Helper() 623 624 tmpDir, err := ioutil.TempDir("", "terraform-configload") 625 if err != nil { 626 t.Fatalf("failed to create temporary directory: %s", err) 627 return "", nil 628 } 629 630 if err := copy.CopyDir(tmpDir, sourceDir); err != nil { 631 t.Fatalf("failed to copy fixture to temporary directory: %s", err) 632 return "", nil 633 } 634 635 oldDir, err := os.Getwd() 636 if err != nil { 637 t.Fatalf("failed to determine current working directory: %s", err) 638 return "", nil 639 } 640 641 err = os.Chdir(tmpDir) 642 if err != nil { 643 t.Fatalf("failed to switch to temp dir %s: %s", tmpDir, err) 644 return "", nil 645 } 646 647 // Most of the tests need this, so we'll make it just in case. 648 os.MkdirAll(filepath.Join(tmpDir, ".terraform/modules"), os.ModePerm) 649 650 t.Logf("tempChdir switched to %s after copying from %s", tmpDir, sourceDir) 651 652 return tmpDir, func() { 653 err := os.Chdir(oldDir) 654 if err != nil { 655 panic(fmt.Errorf("failed to restore previous working directory %s: %s", oldDir, err)) 656 } 657 658 if os.Getenv("TF_CONFIGLOAD_TEST_KEEP_TMP") == "" { 659 os.RemoveAll(tmpDir) 660 } 661 } 662 } 663 664 func assertNoDiagnostics(t *testing.T, diags tfdiags.Diagnostics) bool { 665 t.Helper() 666 return assertDiagnosticCount(t, diags, 0) 667 } 668 669 func assertDiagnosticCount(t *testing.T, diags tfdiags.Diagnostics, want int) bool { 670 t.Helper() 671 if len(diags) != 0 { 672 t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want) 673 for _, diag := range diags { 674 t.Logf("- %#v", diag) 675 } 676 return true 677 } 678 return false 679 } 680 681 func assertDiagnosticSummary(t *testing.T, diags tfdiags.Diagnostics, want string) bool { 682 t.Helper() 683 684 for _, diag := range diags { 685 if diag.Description().Summary == want { 686 return false 687 } 688 } 689 690 t.Errorf("missing diagnostic summary %q", want) 691 for _, diag := range diags { 692 t.Logf("- %#v", diag) 693 } 694 return true 695 } 696 697 func assertResultDeepEqual(t *testing.T, got, want interface{}) bool { 698 t.Helper() 699 if diff := deep.Equal(got, want); diff != nil { 700 for _, problem := range diff { 701 t.Errorf("%s", problem) 702 } 703 return true 704 } 705 return false 706 }