github.com/acm1/terraform@v0.6.2-0.20150729164239-1f314444f45c/helper/resource/testing_test.go (about)

     1  package resource
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"sync/atomic"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/terraform/terraform"
    10  )
    11  
    12  func init() {
    13  	testTesting = true
    14  
    15  	if err := os.Setenv(TestEnvVar, "1"); err != nil {
    16  		panic(err)
    17  	}
    18  }
    19  
    20  func TestTest(t *testing.T) {
    21  	mp := testProvider()
    22  	mp.DiffReturn = nil
    23  
    24  	mp.ApplyReturn = &terraform.InstanceState{
    25  		ID: "foo",
    26  	}
    27  	var refreshCount int32
    28  	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
    29  		atomic.AddInt32(&refreshCount, 1)
    30  		if atomic.LoadInt32(&refreshCount) == 1 {
    31  			return &terraform.InstanceState{ID: "foo"}, nil
    32  		} else {
    33  			return nil, nil
    34  		}
    35  	}
    36  
    37  	checkDestroy := false
    38  	checkStep := false
    39  
    40  	checkDestroyFn := func(*terraform.State) error {
    41  		checkDestroy = true
    42  		return nil
    43  	}
    44  
    45  	checkStepFn := func(s *terraform.State) error {
    46  		checkStep = true
    47  
    48  		rs, ok := s.RootModule().Resources["test_instance.foo"]
    49  		if !ok {
    50  			t.Error("test_instance.foo is not present")
    51  			return nil
    52  		}
    53  		is := rs.Primary
    54  		if is.ID != "foo" {
    55  			t.Errorf("bad check ID: %s", is.ID)
    56  		}
    57  
    58  		return nil
    59  	}
    60  
    61  	mt := new(mockT)
    62  	Test(mt, TestCase{
    63  		Providers: map[string]terraform.ResourceProvider{
    64  			"test": mp,
    65  		},
    66  		CheckDestroy: checkDestroyFn,
    67  		Steps: []TestStep{
    68  			TestStep{
    69  				Config: testConfigStr,
    70  				Check:  checkStepFn,
    71  			},
    72  		},
    73  	})
    74  
    75  	if mt.failed() {
    76  		t.Fatalf("test failed: %s", mt.failMessage())
    77  	}
    78  	if !checkStep {
    79  		t.Fatal("didn't call check for step")
    80  	}
    81  	if !checkDestroy {
    82  		t.Fatal("didn't call check for destroy")
    83  	}
    84  }
    85  
    86  func TestTest_empty(t *testing.T) {
    87  	destroyCalled := false
    88  	checkDestroyFn := func(*terraform.State) error {
    89  		destroyCalled = true
    90  		return nil
    91  	}
    92  
    93  	mt := new(mockT)
    94  	Test(mt, TestCase{
    95  		CheckDestroy: checkDestroyFn,
    96  	})
    97  
    98  	if mt.failed() {
    99  		t.Fatal("test failed")
   100  	}
   101  	if destroyCalled {
   102  		t.Fatal("should not call check destroy if there is no steps")
   103  	}
   104  }
   105  
   106  func TestTest_noEnv(t *testing.T) {
   107  	// Unset the variable
   108  	if err := os.Setenv(TestEnvVar, ""); err != nil {
   109  		t.Fatalf("err: %s", err)
   110  	}
   111  	defer os.Setenv(TestEnvVar, "1")
   112  
   113  	mt := new(mockT)
   114  	Test(mt, TestCase{})
   115  
   116  	if !mt.SkipCalled {
   117  		t.Fatal("skip not called")
   118  	}
   119  }
   120  
   121  func TestTest_preCheck(t *testing.T) {
   122  	called := false
   123  
   124  	mt := new(mockT)
   125  	Test(mt, TestCase{
   126  		PreCheck: func() { called = true },
   127  	})
   128  
   129  	if !called {
   130  		t.Fatal("precheck should be called")
   131  	}
   132  }
   133  
   134  func TestTest_stepError(t *testing.T) {
   135  	mp := testProvider()
   136  	mp.ApplyReturn = &terraform.InstanceState{
   137  		ID: "foo",
   138  	}
   139  
   140  	checkDestroy := false
   141  
   142  	checkDestroyFn := func(*terraform.State) error {
   143  		checkDestroy = true
   144  		return nil
   145  	}
   146  
   147  	checkStepFn := func(*terraform.State) error {
   148  		return fmt.Errorf("error")
   149  	}
   150  
   151  	mt := new(mockT)
   152  	Test(mt, TestCase{
   153  		Providers: map[string]terraform.ResourceProvider{
   154  			"test": mp,
   155  		},
   156  		CheckDestroy: checkDestroyFn,
   157  		Steps: []TestStep{
   158  			TestStep{
   159  				Config: testConfigStr,
   160  				Check:  checkStepFn,
   161  			},
   162  		},
   163  	})
   164  
   165  	if !mt.failed() {
   166  		t.Fatal("test should've failed")
   167  	}
   168  	expected := "Step 0 error: Check failed: error"
   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 TestComposeTestCheckFunc(t *testing.T) {
   179  	cases := []struct {
   180  		F      []TestCheckFunc
   181  		Result string
   182  	}{
   183  		{
   184  			F: []TestCheckFunc{
   185  				func(*terraform.State) error { return nil },
   186  			},
   187  			Result: "",
   188  		},
   189  
   190  		{
   191  			F: []TestCheckFunc{
   192  				func(*terraform.State) error {
   193  					return fmt.Errorf("error")
   194  				},
   195  				func(*terraform.State) error { return nil },
   196  			},
   197  			Result: "error",
   198  		},
   199  
   200  		{
   201  			F: []TestCheckFunc{
   202  				func(*terraform.State) error { return nil },
   203  				func(*terraform.State) error {
   204  					return fmt.Errorf("error")
   205  				},
   206  			},
   207  			Result: "error",
   208  		},
   209  
   210  		{
   211  			F: []TestCheckFunc{
   212  				func(*terraform.State) error { return nil },
   213  				func(*terraform.State) error { return nil },
   214  			},
   215  			Result: "",
   216  		},
   217  	}
   218  
   219  	for i, tc := range cases {
   220  		f := ComposeTestCheckFunc(tc.F...)
   221  		err := f(nil)
   222  		if err == nil {
   223  			err = fmt.Errorf("")
   224  		}
   225  		if tc.Result != err.Error() {
   226  			t.Fatalf("Case %d bad: %s", i, err)
   227  		}
   228  	}
   229  }
   230  
   231  // mockT implements TestT for testing
   232  type mockT struct {
   233  	ErrorCalled bool
   234  	ErrorArgs   []interface{}
   235  	FatalCalled bool
   236  	FatalArgs   []interface{}
   237  	SkipCalled  bool
   238  	SkipArgs    []interface{}
   239  
   240  	f bool
   241  }
   242  
   243  func (t *mockT) Error(args ...interface{}) {
   244  	t.ErrorCalled = true
   245  	t.ErrorArgs = args
   246  	t.f = true
   247  }
   248  
   249  func (t *mockT) Fatal(args ...interface{}) {
   250  	t.FatalCalled = true
   251  	t.FatalArgs = args
   252  	t.f = true
   253  }
   254  
   255  func (t *mockT) Skip(args ...interface{}) {
   256  	t.SkipCalled = true
   257  	t.SkipArgs = args
   258  	t.f = true
   259  }
   260  
   261  func (t *mockT) failed() bool {
   262  	return t.f
   263  }
   264  
   265  func (t *mockT) failMessage() string {
   266  	if t.FatalCalled {
   267  		return t.FatalArgs[0].(string)
   268  	} else if t.ErrorCalled {
   269  		return t.ErrorArgs[0].(string)
   270  	} else if t.SkipCalled {
   271  		return t.SkipArgs[0].(string)
   272  	}
   273  
   274  	return "unknown"
   275  }
   276  
   277  func testProvider() *terraform.MockResourceProvider {
   278  	mp := new(terraform.MockResourceProvider)
   279  	mp.DiffReturn = &terraform.InstanceDiff{
   280  		Attributes: map[string]*terraform.ResourceAttrDiff{
   281  			"foo": &terraform.ResourceAttrDiff{
   282  				New: "bar",
   283  			},
   284  		},
   285  	}
   286  	mp.ResourcesReturn = []terraform.ResourceType{
   287  		terraform.ResourceType{Name: "test_instance"},
   288  	}
   289  
   290  	return mp
   291  }
   292  
   293  const testConfigStr = `
   294  resource "test_instance" "foo" {}
   295  `