github.com/scottwinkler/terraform@v0.11.6-0.20180329211809-05143987aea8/helper/resource/testing_test.go (about)

     1  package resource
     2  
     3  import (
     4  	"errors"
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  	"reflect"
     9  	"regexp"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  	"sync/atomic"
    14  	"testing"
    15  
    16  	"github.com/hashicorp/go-multierror"
    17  	"github.com/hashicorp/terraform/terraform"
    18  )
    19  
    20  func init() {
    21  	testTesting = true
    22  
    23  	// TODO: Remove when we remove the guard on id checks
    24  	if err := os.Setenv("TF_ACC_IDONLY", "1"); err != nil {
    25  		panic(err)
    26  	}
    27  
    28  	if err := os.Setenv(TestEnvVar, "1"); err != nil {
    29  		panic(err)
    30  	}
    31  }
    32  
    33  // wrap the mock provider to implement TestProvider
    34  type resetProvider struct {
    35  	*terraform.MockResourceProvider
    36  	mu              sync.Mutex
    37  	TestResetCalled bool
    38  	TestResetError  error
    39  }
    40  
    41  func (p *resetProvider) TestReset() error {
    42  	p.mu.Lock()
    43  	defer p.mu.Unlock()
    44  	p.TestResetCalled = true
    45  	return p.TestResetError
    46  }
    47  
    48  func TestTest(t *testing.T) {
    49  	mp := &resetProvider{
    50  		MockResourceProvider: testProvider(),
    51  	}
    52  
    53  	mp.DiffReturn = nil
    54  
    55  	mp.ApplyFn = func(
    56  		info *terraform.InstanceInfo,
    57  		state *terraform.InstanceState,
    58  		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
    59  		if !diff.Destroy {
    60  			return &terraform.InstanceState{
    61  				ID: "foo",
    62  			}, nil
    63  		}
    64  
    65  		return nil, nil
    66  	}
    67  
    68  	var refreshCount int32
    69  	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
    70  		atomic.AddInt32(&refreshCount, 1)
    71  		return &terraform.InstanceState{ID: "foo"}, nil
    72  	}
    73  
    74  	checkDestroy := false
    75  	checkStep := false
    76  
    77  	checkDestroyFn := func(*terraform.State) error {
    78  		checkDestroy = true
    79  		return nil
    80  	}
    81  
    82  	checkStepFn := func(s *terraform.State) error {
    83  		checkStep = true
    84  
    85  		rs, ok := s.RootModule().Resources["test_instance.foo"]
    86  		if !ok {
    87  			t.Error("test_instance.foo is not present")
    88  			return nil
    89  		}
    90  		is := rs.Primary
    91  		if is.ID != "foo" {
    92  			t.Errorf("bad check ID: %s", is.ID)
    93  		}
    94  
    95  		return nil
    96  	}
    97  
    98  	mt := new(mockT)
    99  	Test(mt, TestCase{
   100  		Providers: map[string]terraform.ResourceProvider{
   101  			"test": mp,
   102  		},
   103  		CheckDestroy: checkDestroyFn,
   104  		Steps: []TestStep{
   105  			TestStep{
   106  				Config: testConfigStr,
   107  				Check:  checkStepFn,
   108  			},
   109  		},
   110  	})
   111  
   112  	if mt.failed() {
   113  		t.Fatalf("test failed: %s", mt.failMessage())
   114  	}
   115  	if !checkStep {
   116  		t.Fatal("didn't call check for step")
   117  	}
   118  	if !checkDestroy {
   119  		t.Fatal("didn't call check for destroy")
   120  	}
   121  	if !mp.TestResetCalled {
   122  		t.Fatal("didn't call TestReset")
   123  	}
   124  }
   125  
   126  func TestTest_plan_only(t *testing.T) {
   127  	mp := testProvider()
   128  	mp.ApplyReturn = &terraform.InstanceState{
   129  		ID: "foo",
   130  	}
   131  
   132  	checkDestroy := false
   133  
   134  	checkDestroyFn := func(*terraform.State) error {
   135  		checkDestroy = true
   136  		return nil
   137  	}
   138  
   139  	mt := new(mockT)
   140  	Test(mt, TestCase{
   141  		Providers: map[string]terraform.ResourceProvider{
   142  			"test": mp,
   143  		},
   144  		CheckDestroy: checkDestroyFn,
   145  		Steps: []TestStep{
   146  			TestStep{
   147  				Config:             testConfigStr,
   148  				PlanOnly:           true,
   149  				ExpectNonEmptyPlan: false,
   150  			},
   151  		},
   152  	})
   153  
   154  	if !mt.failed() {
   155  		t.Fatal("test should've failed")
   156  	}
   157  
   158  	expected := `Step 0 error: After applying this step, the plan was not empty:
   159  
   160  DIFF:
   161  
   162  CREATE: test_instance.foo
   163    foo: "" => "bar"
   164  
   165  STATE:
   166  
   167  <no state>`
   168  
   169  	if mt.failMessage() != expected {
   170  		t.Fatalf("Expected message: %s\n\ngot:\n\n%s", expected, mt.failMessage())
   171  	}
   172  
   173  	if !checkDestroy {
   174  		t.Fatal("didn't call check for destroy")
   175  	}
   176  }
   177  
   178  func TestTest_idRefresh(t *testing.T) {
   179  	// Refresh count should be 3:
   180  	//   1.) initial Ref/Plan/Apply
   181  	//   2.) post Ref/Plan/Apply for plan-check
   182  	//   3.) id refresh check
   183  	var expectedRefresh int32 = 3
   184  
   185  	mp := testProvider()
   186  	mp.DiffReturn = nil
   187  
   188  	mp.ApplyFn = func(
   189  		info *terraform.InstanceInfo,
   190  		state *terraform.InstanceState,
   191  		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   192  		if !diff.Destroy {
   193  			return &terraform.InstanceState{
   194  				ID: "foo",
   195  			}, nil
   196  		}
   197  
   198  		return nil, nil
   199  	}
   200  
   201  	var refreshCount int32
   202  	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
   203  		atomic.AddInt32(&refreshCount, 1)
   204  		return &terraform.InstanceState{ID: "foo"}, nil
   205  	}
   206  
   207  	mt := new(mockT)
   208  	Test(mt, TestCase{
   209  		IDRefreshName: "test_instance.foo",
   210  		Providers: map[string]terraform.ResourceProvider{
   211  			"test": mp,
   212  		},
   213  		Steps: []TestStep{
   214  			TestStep{
   215  				Config: testConfigStr,
   216  			},
   217  		},
   218  	})
   219  
   220  	if mt.failed() {
   221  		t.Fatalf("test failed: %s", mt.failMessage())
   222  	}
   223  
   224  	// See declaration of expectedRefresh for why that number
   225  	if refreshCount != expectedRefresh {
   226  		t.Fatalf("bad refresh count: %d", refreshCount)
   227  	}
   228  }
   229  
   230  func TestTest_idRefreshCustomName(t *testing.T) {
   231  	// Refresh count should be 3:
   232  	//   1.) initial Ref/Plan/Apply
   233  	//   2.) post Ref/Plan/Apply for plan-check
   234  	//   3.) id refresh check
   235  	var expectedRefresh int32 = 3
   236  
   237  	mp := testProvider()
   238  	mp.DiffReturn = nil
   239  
   240  	mp.ApplyFn = func(
   241  		info *terraform.InstanceInfo,
   242  		state *terraform.InstanceState,
   243  		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   244  		if !diff.Destroy {
   245  			return &terraform.InstanceState{
   246  				ID: "foo",
   247  			}, nil
   248  		}
   249  
   250  		return nil, nil
   251  	}
   252  
   253  	var refreshCount int32
   254  	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
   255  		atomic.AddInt32(&refreshCount, 1)
   256  		return &terraform.InstanceState{ID: "foo"}, nil
   257  	}
   258  
   259  	mt := new(mockT)
   260  	Test(mt, TestCase{
   261  		IDRefreshName: "test_instance.foo",
   262  		Providers: map[string]terraform.ResourceProvider{
   263  			"test": mp,
   264  		},
   265  		Steps: []TestStep{
   266  			TestStep{
   267  				Config: testConfigStr,
   268  			},
   269  		},
   270  	})
   271  
   272  	if mt.failed() {
   273  		t.Fatalf("test failed: %s", mt.failMessage())
   274  	}
   275  
   276  	// See declaration of expectedRefresh for why that number
   277  	if refreshCount != expectedRefresh {
   278  		t.Fatalf("bad refresh count: %d", refreshCount)
   279  	}
   280  }
   281  
   282  func TestTest_idRefreshFail(t *testing.T) {
   283  	// Refresh count should be 3:
   284  	//   1.) initial Ref/Plan/Apply
   285  	//   2.) post Ref/Plan/Apply for plan-check
   286  	//   3.) id refresh check
   287  	var expectedRefresh int32 = 3
   288  
   289  	mp := testProvider()
   290  	mp.DiffReturn = nil
   291  
   292  	mp.ApplyFn = func(
   293  		info *terraform.InstanceInfo,
   294  		state *terraform.InstanceState,
   295  		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   296  		if !diff.Destroy {
   297  			return &terraform.InstanceState{
   298  				ID: "foo",
   299  			}, nil
   300  		}
   301  
   302  		return nil, nil
   303  	}
   304  
   305  	var refreshCount int32
   306  	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
   307  		atomic.AddInt32(&refreshCount, 1)
   308  		if atomic.LoadInt32(&refreshCount) == expectedRefresh-1 {
   309  			return &terraform.InstanceState{
   310  				ID:         "foo",
   311  				Attributes: map[string]string{"foo": "bar"},
   312  			}, nil
   313  		} else if atomic.LoadInt32(&refreshCount) < expectedRefresh {
   314  			return &terraform.InstanceState{ID: "foo"}, nil
   315  		} else {
   316  			return nil, nil
   317  		}
   318  	}
   319  
   320  	mt := new(mockT)
   321  	Test(mt, TestCase{
   322  		IDRefreshName: "test_instance.foo",
   323  		Providers: map[string]terraform.ResourceProvider{
   324  			"test": mp,
   325  		},
   326  		Steps: []TestStep{
   327  			TestStep{
   328  				Config: testConfigStr,
   329  			},
   330  		},
   331  	})
   332  
   333  	if !mt.failed() {
   334  		t.Fatal("test didn't fail")
   335  	}
   336  	t.Logf("failure reason: %s", mt.failMessage())
   337  
   338  	// See declaration of expectedRefresh for why that number
   339  	if refreshCount != expectedRefresh {
   340  		t.Fatalf("bad refresh count: %d", refreshCount)
   341  	}
   342  }
   343  
   344  func TestTest_empty(t *testing.T) {
   345  	destroyCalled := false
   346  	checkDestroyFn := func(*terraform.State) error {
   347  		destroyCalled = true
   348  		return nil
   349  	}
   350  
   351  	mt := new(mockT)
   352  	Test(mt, TestCase{
   353  		CheckDestroy: checkDestroyFn,
   354  	})
   355  
   356  	if mt.failed() {
   357  		t.Fatal("test failed")
   358  	}
   359  	if destroyCalled {
   360  		t.Fatal("should not call check destroy if there is no steps")
   361  	}
   362  }
   363  
   364  func TestTest_noEnv(t *testing.T) {
   365  	// Unset the variable
   366  	if err := os.Setenv(TestEnvVar, ""); err != nil {
   367  		t.Fatalf("err: %s", err)
   368  	}
   369  	defer os.Setenv(TestEnvVar, "1")
   370  
   371  	mt := new(mockT)
   372  	Test(mt, TestCase{})
   373  
   374  	if !mt.SkipCalled {
   375  		t.Fatal("skip not called")
   376  	}
   377  }
   378  
   379  func TestTest_preCheck(t *testing.T) {
   380  	called := false
   381  
   382  	mt := new(mockT)
   383  	Test(mt, TestCase{
   384  		PreCheck: func() { called = true },
   385  	})
   386  
   387  	if !called {
   388  		t.Fatal("precheck should be called")
   389  	}
   390  }
   391  
   392  func TestTest_skipFunc(t *testing.T) {
   393  	preCheckCalled := false
   394  	skipped := false
   395  
   396  	mp := testProvider()
   397  	mp.ApplyReturn = &terraform.InstanceState{
   398  		ID: "foo",
   399  	}
   400  
   401  	checkStepFn := func(*terraform.State) error {
   402  		return fmt.Errorf("error")
   403  	}
   404  
   405  	mt := new(mockT)
   406  	Test(mt, TestCase{
   407  		Providers: map[string]terraform.ResourceProvider{
   408  			"test": mp,
   409  		},
   410  		PreCheck: func() { preCheckCalled = true },
   411  		Steps: []TestStep{
   412  			{
   413  				Config:   testConfigStr,
   414  				Check:    checkStepFn,
   415  				SkipFunc: func() (bool, error) { skipped = true; return true, nil },
   416  			},
   417  		},
   418  	})
   419  
   420  	if mt.failed() {
   421  		t.Fatal("Expected check to be skipped")
   422  	}
   423  
   424  	if !preCheckCalled {
   425  		t.Fatal("precheck should be called")
   426  	}
   427  	if !skipped {
   428  		t.Fatal("SkipFunc should be called")
   429  	}
   430  }
   431  
   432  func TestTest_stepError(t *testing.T) {
   433  	mp := testProvider()
   434  	mp.ApplyReturn = &terraform.InstanceState{
   435  		ID: "foo",
   436  	}
   437  
   438  	checkDestroy := false
   439  
   440  	checkDestroyFn := func(*terraform.State) error {
   441  		checkDestroy = true
   442  		return nil
   443  	}
   444  
   445  	checkStepFn := func(*terraform.State) error {
   446  		return fmt.Errorf("error")
   447  	}
   448  
   449  	mt := new(mockT)
   450  	Test(mt, TestCase{
   451  		Providers: map[string]terraform.ResourceProvider{
   452  			"test": mp,
   453  		},
   454  		CheckDestroy: checkDestroyFn,
   455  		Steps: []TestStep{
   456  			TestStep{
   457  				Config: testConfigStr,
   458  				Check:  checkStepFn,
   459  			},
   460  		},
   461  	})
   462  
   463  	if !mt.failed() {
   464  		t.Fatal("test should've failed")
   465  	}
   466  	expected := "Step 0 error: Check failed: error"
   467  	if mt.failMessage() != expected {
   468  		t.Fatalf("Expected message: %s\n\ngot:\n\n%s", expected, mt.failMessage())
   469  	}
   470  
   471  	if !checkDestroy {
   472  		t.Fatal("didn't call check for destroy")
   473  	}
   474  }
   475  
   476  func TestTest_factoryError(t *testing.T) {
   477  	resourceFactoryError := fmt.Errorf("resource factory error")
   478  
   479  	factory := func() (terraform.ResourceProvider, error) {
   480  		return nil, resourceFactoryError
   481  	}
   482  
   483  	mt := new(mockT)
   484  	Test(mt, TestCase{
   485  		ProviderFactories: map[string]terraform.ResourceProviderFactory{
   486  			"test": factory,
   487  		},
   488  		Steps: []TestStep{
   489  			TestStep{
   490  				ExpectError: regexp.MustCompile("resource factory error"),
   491  			},
   492  		},
   493  	})
   494  
   495  	if !mt.failed() {
   496  		t.Fatal("test should've failed")
   497  	}
   498  }
   499  
   500  func TestTest_resetError(t *testing.T) {
   501  	mp := &resetProvider{
   502  		MockResourceProvider: testProvider(),
   503  		TestResetError:       fmt.Errorf("provider reset error"),
   504  	}
   505  
   506  	mt := new(mockT)
   507  	Test(mt, TestCase{
   508  		Providers: map[string]terraform.ResourceProvider{
   509  			"test": mp,
   510  		},
   511  		Steps: []TestStep{
   512  			TestStep{
   513  				ExpectError: regexp.MustCompile("provider reset error"),
   514  			},
   515  		},
   516  	})
   517  
   518  	if !mt.failed() {
   519  		t.Fatal("test should've failed")
   520  	}
   521  }
   522  
   523  func TestTest_expectError(t *testing.T) {
   524  	cases := []struct {
   525  		name     string
   526  		planErr  bool
   527  		applyErr bool
   528  		badErr   bool
   529  	}{
   530  		{
   531  			name:     "successful apply",
   532  			planErr:  false,
   533  			applyErr: false,
   534  		},
   535  		{
   536  			name:     "bad plan",
   537  			planErr:  true,
   538  			applyErr: false,
   539  		},
   540  		{
   541  			name:     "bad apply",
   542  			planErr:  false,
   543  			applyErr: true,
   544  		},
   545  		{
   546  			name:     "bad plan, bad err",
   547  			planErr:  true,
   548  			applyErr: false,
   549  			badErr:   true,
   550  		},
   551  		{
   552  			name:     "bad apply, bad err",
   553  			planErr:  false,
   554  			applyErr: true,
   555  			badErr:   true,
   556  		},
   557  	}
   558  
   559  	for _, tc := range cases {
   560  		t.Run(tc.name, func(t *testing.T) {
   561  			mp := testProvider()
   562  			expectedText := "test provider error"
   563  			var errText string
   564  			if tc.badErr {
   565  				errText = "wrong provider error"
   566  			} else {
   567  				errText = expectedText
   568  			}
   569  			noErrText := "no error received, but expected a match to"
   570  			if tc.planErr {
   571  				mp.DiffReturnError = errors.New(errText)
   572  			}
   573  			if tc.applyErr {
   574  				mp.ApplyReturnError = errors.New(errText)
   575  			}
   576  			mt := new(mockT)
   577  			Test(mt, TestCase{
   578  				Providers: map[string]terraform.ResourceProvider{
   579  					"test": mp,
   580  				},
   581  				Steps: []TestStep{
   582  					TestStep{
   583  						Config:             testConfigStr,
   584  						ExpectError:        regexp.MustCompile(expectedText),
   585  						Check:              func(*terraform.State) error { return nil },
   586  						ExpectNonEmptyPlan: true,
   587  					},
   588  				},
   589  			},
   590  			)
   591  			if mt.FatalCalled {
   592  				t.Fatalf("fatal: %+v", mt.FatalArgs)
   593  			}
   594  			switch {
   595  			case len(mt.ErrorArgs) < 1 && !tc.planErr && !tc.applyErr:
   596  				t.Fatalf("expected error, got none")
   597  			case !tc.planErr && !tc.applyErr:
   598  				for _, e := range mt.ErrorArgs {
   599  					if regexp.MustCompile(noErrText).MatchString(fmt.Sprintf("%v", e)) {
   600  						return
   601  					}
   602  				}
   603  				t.Fatalf("expected error to match %s, got %+v", noErrText, mt.ErrorArgs)
   604  			case tc.badErr:
   605  				for _, e := range mt.ErrorArgs {
   606  					if regexp.MustCompile(expectedText).MatchString(fmt.Sprintf("%v", e)) {
   607  						return
   608  					}
   609  				}
   610  				t.Fatalf("expected error to match %s, got %+v", expectedText, mt.ErrorArgs)
   611  			}
   612  		})
   613  	}
   614  }
   615  
   616  func TestComposeAggregateTestCheckFunc(t *testing.T) {
   617  	check1 := func(s *terraform.State) error {
   618  		return errors.New("Error 1")
   619  	}
   620  
   621  	check2 := func(s *terraform.State) error {
   622  		return errors.New("Error 2")
   623  	}
   624  
   625  	f := ComposeAggregateTestCheckFunc(check1, check2)
   626  	err := f(nil)
   627  	if err == nil {
   628  		t.Fatalf("Expected errors")
   629  	}
   630  
   631  	multi := err.(*multierror.Error)
   632  	if !strings.Contains(multi.Errors[0].Error(), "Error 1") {
   633  		t.Fatalf("Expected Error 1, Got %s", multi.Errors[0])
   634  	}
   635  	if !strings.Contains(multi.Errors[1].Error(), "Error 2") {
   636  		t.Fatalf("Expected Error 2, Got %s", multi.Errors[1])
   637  	}
   638  }
   639  
   640  func TestComposeTestCheckFunc(t *testing.T) {
   641  	cases := []struct {
   642  		F      []TestCheckFunc
   643  		Result string
   644  	}{
   645  		{
   646  			F: []TestCheckFunc{
   647  				func(*terraform.State) error { return nil },
   648  			},
   649  			Result: "",
   650  		},
   651  
   652  		{
   653  			F: []TestCheckFunc{
   654  				func(*terraform.State) error {
   655  					return fmt.Errorf("error")
   656  				},
   657  				func(*terraform.State) error { return nil },
   658  			},
   659  			Result: "Check 1/2 error: error",
   660  		},
   661  
   662  		{
   663  			F: []TestCheckFunc{
   664  				func(*terraform.State) error { return nil },
   665  				func(*terraform.State) error {
   666  					return fmt.Errorf("error")
   667  				},
   668  			},
   669  			Result: "Check 2/2 error: error",
   670  		},
   671  
   672  		{
   673  			F: []TestCheckFunc{
   674  				func(*terraform.State) error { return nil },
   675  				func(*terraform.State) error { return nil },
   676  			},
   677  			Result: "",
   678  		},
   679  	}
   680  
   681  	for i, tc := range cases {
   682  		f := ComposeTestCheckFunc(tc.F...)
   683  		err := f(nil)
   684  		if err == nil {
   685  			err = fmt.Errorf("")
   686  		}
   687  		if tc.Result != err.Error() {
   688  			t.Fatalf("Case %d bad: %s", i, err)
   689  		}
   690  	}
   691  }
   692  
   693  // mockT implements TestT for testing
   694  type mockT struct {
   695  	ErrorCalled bool
   696  	ErrorArgs   []interface{}
   697  	FatalCalled bool
   698  	FatalArgs   []interface{}
   699  	SkipCalled  bool
   700  	SkipArgs    []interface{}
   701  
   702  	f bool
   703  }
   704  
   705  func (t *mockT) Error(args ...interface{}) {
   706  	t.ErrorCalled = true
   707  	t.ErrorArgs = args
   708  	t.f = true
   709  }
   710  
   711  func (t *mockT) Fatal(args ...interface{}) {
   712  	t.FatalCalled = true
   713  	t.FatalArgs = args
   714  	t.f = true
   715  }
   716  
   717  func (t *mockT) Skip(args ...interface{}) {
   718  	t.SkipCalled = true
   719  	t.SkipArgs = args
   720  	t.f = true
   721  }
   722  
   723  func (t *mockT) Name() string {
   724  	return "MockedName"
   725  }
   726  
   727  func (t *mockT) failed() bool {
   728  	return t.f
   729  }
   730  
   731  func (t *mockT) failMessage() string {
   732  	if t.FatalCalled {
   733  		return t.FatalArgs[0].(string)
   734  	} else if t.ErrorCalled {
   735  		return t.ErrorArgs[0].(string)
   736  	} else if t.SkipCalled {
   737  		return t.SkipArgs[0].(string)
   738  	}
   739  
   740  	return "unknown"
   741  }
   742  
   743  func testProvider() *terraform.MockResourceProvider {
   744  	mp := new(terraform.MockResourceProvider)
   745  	mp.DiffReturn = &terraform.InstanceDiff{
   746  		Attributes: map[string]*terraform.ResourceAttrDiff{
   747  			"foo": &terraform.ResourceAttrDiff{
   748  				New: "bar",
   749  			},
   750  		},
   751  	}
   752  	mp.ResourcesReturn = []terraform.ResourceType{
   753  		terraform.ResourceType{Name: "test_instance"},
   754  	}
   755  
   756  	return mp
   757  }
   758  
   759  func TestTest_Main(t *testing.T) {
   760  	flag.Parse()
   761  	if *flagSweep == "" {
   762  		// Tests for the TestMain method used for Sweepers will panic without the -sweep
   763  		// flag specified. Mock the value for now
   764  		*flagSweep = "us-east-1"
   765  	}
   766  
   767  	cases := []struct {
   768  		Name            string
   769  		Sweepers        map[string]*Sweeper
   770  		ExpectedRunList []string
   771  		SweepRun        string
   772  	}{
   773  		{
   774  			Name: "normal",
   775  			Sweepers: map[string]*Sweeper{
   776  				"aws_dummy": &Sweeper{
   777  					Name: "aws_dummy",
   778  					F:    mockSweeperFunc,
   779  				},
   780  			},
   781  			ExpectedRunList: []string{"aws_dummy"},
   782  		},
   783  		{
   784  			Name: "with dep",
   785  			Sweepers: map[string]*Sweeper{
   786  				"aws_dummy": &Sweeper{
   787  					Name: "aws_dummy",
   788  					F:    mockSweeperFunc,
   789  				},
   790  				"aws_top": &Sweeper{
   791  					Name:         "aws_top",
   792  					Dependencies: []string{"aws_sub"},
   793  					F:            mockSweeperFunc,
   794  				},
   795  				"aws_sub": &Sweeper{
   796  					Name: "aws_sub",
   797  					F:    mockSweeperFunc,
   798  				},
   799  			},
   800  			ExpectedRunList: []string{"aws_dummy", "aws_sub", "aws_top"},
   801  		},
   802  		{
   803  			Name: "with filter",
   804  			Sweepers: map[string]*Sweeper{
   805  				"aws_dummy": &Sweeper{
   806  					Name: "aws_dummy",
   807  					F:    mockSweeperFunc,
   808  				},
   809  				"aws_top": &Sweeper{
   810  					Name:         "aws_top",
   811  					Dependencies: []string{"aws_sub"},
   812  					F:            mockSweeperFunc,
   813  				},
   814  				"aws_sub": &Sweeper{
   815  					Name: "aws_sub",
   816  					F:    mockSweeperFunc,
   817  				},
   818  			},
   819  			ExpectedRunList: []string{"aws_dummy"},
   820  			SweepRun:        "aws_dummy",
   821  		},
   822  		{
   823  			Name: "with two filters",
   824  			Sweepers: map[string]*Sweeper{
   825  				"aws_dummy": &Sweeper{
   826  					Name: "aws_dummy",
   827  					F:    mockSweeperFunc,
   828  				},
   829  				"aws_top": &Sweeper{
   830  					Name:         "aws_top",
   831  					Dependencies: []string{"aws_sub"},
   832  					F:            mockSweeperFunc,
   833  				},
   834  				"aws_sub": &Sweeper{
   835  					Name: "aws_sub",
   836  					F:    mockSweeperFunc,
   837  				},
   838  			},
   839  			ExpectedRunList: []string{"aws_dummy", "aws_sub"},
   840  			SweepRun:        "aws_dummy,aws_sub",
   841  		},
   842  		{
   843  			Name: "with dep and filter",
   844  			Sweepers: map[string]*Sweeper{
   845  				"aws_dummy": &Sweeper{
   846  					Name: "aws_dummy",
   847  					F:    mockSweeperFunc,
   848  				},
   849  				"aws_top": &Sweeper{
   850  					Name:         "aws_top",
   851  					Dependencies: []string{"aws_sub"},
   852  					F:            mockSweeperFunc,
   853  				},
   854  				"aws_sub": &Sweeper{
   855  					Name: "aws_sub",
   856  					F:    mockSweeperFunc,
   857  				},
   858  			},
   859  			ExpectedRunList: []string{"aws_top", "aws_sub"},
   860  			SweepRun:        "aws_top",
   861  		},
   862  		{
   863  			Name: "filter and none",
   864  			Sweepers: map[string]*Sweeper{
   865  				"aws_dummy": &Sweeper{
   866  					Name: "aws_dummy",
   867  					F:    mockSweeperFunc,
   868  				},
   869  				"aws_top": &Sweeper{
   870  					Name:         "aws_top",
   871  					Dependencies: []string{"aws_sub"},
   872  					F:            mockSweeperFunc,
   873  				},
   874  				"aws_sub": &Sweeper{
   875  					Name: "aws_sub",
   876  					F:    mockSweeperFunc,
   877  				},
   878  			},
   879  			SweepRun: "none",
   880  		},
   881  	}
   882  
   883  	for _, tc := range cases {
   884  		// reset sweepers
   885  		sweeperFuncs = map[string]*Sweeper{}
   886  
   887  		t.Run(tc.Name, func(t *testing.T) {
   888  			for n, s := range tc.Sweepers {
   889  				AddTestSweepers(n, s)
   890  			}
   891  			*flagSweepRun = tc.SweepRun
   892  
   893  			TestMain(&testing.M{})
   894  
   895  			// get list of tests ran from sweeperRunList keys
   896  			var keys []string
   897  			for k, _ := range sweeperRunList {
   898  				keys = append(keys, k)
   899  			}
   900  
   901  			sort.Strings(keys)
   902  			sort.Strings(tc.ExpectedRunList)
   903  			if !reflect.DeepEqual(keys, tc.ExpectedRunList) {
   904  				t.Fatalf("Expected keys mismatch, expected:\n%#v\ngot:\n%#v\n", tc.ExpectedRunList, keys)
   905  			}
   906  		})
   907  	}
   908  }
   909  
   910  func mockSweeperFunc(s string) error {
   911  	return nil
   912  }
   913  
   914  const testConfigStr = `
   915  resource "test_instance" "foo" {}
   916  `
   917  
   918  const testConfigStrProvider = `
   919  provider "test" {}
   920  `