github.com/xsb/terraform@v0.6.13-0.20160314145438-fe415c2f09d7/helper/schema/resource_test.go (about)

     1  package schema
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strconv"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/terraform/terraform"
    10  )
    11  
    12  func TestResourceApply_create(t *testing.T) {
    13  	r := &Resource{
    14  		SchemaVersion: 2,
    15  		Schema: map[string]*Schema{
    16  			"foo": &Schema{
    17  				Type:     TypeInt,
    18  				Optional: true,
    19  			},
    20  		},
    21  	}
    22  
    23  	called := false
    24  	r.Create = func(d *ResourceData, m interface{}) error {
    25  		called = true
    26  		d.SetId("foo")
    27  		return nil
    28  	}
    29  
    30  	var s *terraform.InstanceState = nil
    31  
    32  	d := &terraform.InstanceDiff{
    33  		Attributes: map[string]*terraform.ResourceAttrDiff{
    34  			"foo": &terraform.ResourceAttrDiff{
    35  				New: "42",
    36  			},
    37  		},
    38  	}
    39  
    40  	actual, err := r.Apply(s, d, nil)
    41  	if err != nil {
    42  		t.Fatalf("err: %s", err)
    43  	}
    44  
    45  	if !called {
    46  		t.Fatal("not called")
    47  	}
    48  
    49  	expected := &terraform.InstanceState{
    50  		ID: "foo",
    51  		Attributes: map[string]string{
    52  			"id":  "foo",
    53  			"foo": "42",
    54  		},
    55  		Meta: map[string]string{
    56  			"schema_version": "2",
    57  		},
    58  	}
    59  
    60  	if !reflect.DeepEqual(actual, expected) {
    61  		t.Fatalf("bad: %#v", actual)
    62  	}
    63  }
    64  
    65  func TestResourceApply_destroy(t *testing.T) {
    66  	r := &Resource{
    67  		Schema: map[string]*Schema{
    68  			"foo": &Schema{
    69  				Type:     TypeInt,
    70  				Optional: true,
    71  			},
    72  		},
    73  	}
    74  
    75  	called := false
    76  	r.Delete = func(d *ResourceData, m interface{}) error {
    77  		called = true
    78  		return nil
    79  	}
    80  
    81  	s := &terraform.InstanceState{
    82  		ID: "bar",
    83  	}
    84  
    85  	d := &terraform.InstanceDiff{
    86  		Destroy: true,
    87  	}
    88  
    89  	actual, err := r.Apply(s, d, nil)
    90  	if err != nil {
    91  		t.Fatalf("err: %s", err)
    92  	}
    93  
    94  	if !called {
    95  		t.Fatal("delete not called")
    96  	}
    97  
    98  	if actual != nil {
    99  		t.Fatalf("bad: %#v", actual)
   100  	}
   101  }
   102  
   103  func TestResourceApply_destroyCreate(t *testing.T) {
   104  	r := &Resource{
   105  		Schema: map[string]*Schema{
   106  			"foo": &Schema{
   107  				Type:     TypeInt,
   108  				Optional: true,
   109  			},
   110  
   111  			"tags": &Schema{
   112  				Type:     TypeMap,
   113  				Optional: true,
   114  				Computed: true,
   115  			},
   116  		},
   117  	}
   118  
   119  	change := false
   120  	r.Create = func(d *ResourceData, m interface{}) error {
   121  		change = d.HasChange("tags")
   122  		d.SetId("foo")
   123  		return nil
   124  	}
   125  	r.Delete = func(d *ResourceData, m interface{}) error {
   126  		return nil
   127  	}
   128  
   129  	var s *terraform.InstanceState = &terraform.InstanceState{
   130  		ID: "bar",
   131  		Attributes: map[string]string{
   132  			"foo":       "bar",
   133  			"tags.Name": "foo",
   134  		},
   135  	}
   136  
   137  	d := &terraform.InstanceDiff{
   138  		Attributes: map[string]*terraform.ResourceAttrDiff{
   139  			"foo": &terraform.ResourceAttrDiff{
   140  				New:         "42",
   141  				RequiresNew: true,
   142  			},
   143  			"tags.Name": &terraform.ResourceAttrDiff{
   144  				Old:         "foo",
   145  				New:         "foo",
   146  				RequiresNew: true,
   147  			},
   148  		},
   149  	}
   150  
   151  	actual, err := r.Apply(s, d, nil)
   152  	if err != nil {
   153  		t.Fatalf("err: %s", err)
   154  	}
   155  
   156  	if !change {
   157  		t.Fatal("should have change")
   158  	}
   159  
   160  	expected := &terraform.InstanceState{
   161  		ID: "foo",
   162  		Attributes: map[string]string{
   163  			"id":        "foo",
   164  			"foo":       "42",
   165  			"tags.#":    "1",
   166  			"tags.Name": "foo",
   167  		},
   168  	}
   169  
   170  	if !reflect.DeepEqual(actual, expected) {
   171  		t.Fatalf("bad: %#v", actual)
   172  	}
   173  }
   174  
   175  func TestResourceApply_destroyPartial(t *testing.T) {
   176  	r := &Resource{
   177  		Schema: map[string]*Schema{
   178  			"foo": &Schema{
   179  				Type:     TypeInt,
   180  				Optional: true,
   181  			},
   182  		},
   183  		SchemaVersion: 3,
   184  	}
   185  
   186  	r.Delete = func(d *ResourceData, m interface{}) error {
   187  		d.Set("foo", 42)
   188  		return fmt.Errorf("some error")
   189  	}
   190  
   191  	s := &terraform.InstanceState{
   192  		ID: "bar",
   193  		Attributes: map[string]string{
   194  			"foo": "12",
   195  		},
   196  	}
   197  
   198  	d := &terraform.InstanceDiff{
   199  		Destroy: true,
   200  	}
   201  
   202  	actual, err := r.Apply(s, d, nil)
   203  	if err == nil {
   204  		t.Fatal("should error")
   205  	}
   206  
   207  	expected := &terraform.InstanceState{
   208  		ID: "bar",
   209  		Attributes: map[string]string{
   210  			"id":  "bar",
   211  			"foo": "42",
   212  		},
   213  		Meta: map[string]string{
   214  			"schema_version": "3",
   215  		},
   216  	}
   217  
   218  	if !reflect.DeepEqual(actual, expected) {
   219  		t.Fatalf("expected:\n%#v\n\ngot:\n%#v", expected, actual)
   220  	}
   221  }
   222  
   223  func TestResourceApply_update(t *testing.T) {
   224  	r := &Resource{
   225  		Schema: map[string]*Schema{
   226  			"foo": &Schema{
   227  				Type:     TypeInt,
   228  				Optional: true,
   229  			},
   230  		},
   231  	}
   232  
   233  	r.Update = func(d *ResourceData, m interface{}) error {
   234  		d.Set("foo", 42)
   235  		return nil
   236  	}
   237  
   238  	s := &terraform.InstanceState{
   239  		ID: "foo",
   240  		Attributes: map[string]string{
   241  			"foo": "12",
   242  		},
   243  	}
   244  
   245  	d := &terraform.InstanceDiff{
   246  		Attributes: map[string]*terraform.ResourceAttrDiff{
   247  			"foo": &terraform.ResourceAttrDiff{
   248  				New: "13",
   249  			},
   250  		},
   251  	}
   252  
   253  	actual, err := r.Apply(s, d, nil)
   254  	if err != nil {
   255  		t.Fatalf("err: %s", err)
   256  	}
   257  
   258  	expected := &terraform.InstanceState{
   259  		ID: "foo",
   260  		Attributes: map[string]string{
   261  			"id":  "foo",
   262  			"foo": "42",
   263  		},
   264  	}
   265  
   266  	if !reflect.DeepEqual(actual, expected) {
   267  		t.Fatalf("bad: %#v", actual)
   268  	}
   269  }
   270  
   271  func TestResourceApply_updateNoCallback(t *testing.T) {
   272  	r := &Resource{
   273  		Schema: map[string]*Schema{
   274  			"foo": &Schema{
   275  				Type:     TypeInt,
   276  				Optional: true,
   277  			},
   278  		},
   279  	}
   280  
   281  	r.Update = nil
   282  
   283  	s := &terraform.InstanceState{
   284  		ID: "foo",
   285  		Attributes: map[string]string{
   286  			"foo": "12",
   287  		},
   288  	}
   289  
   290  	d := &terraform.InstanceDiff{
   291  		Attributes: map[string]*terraform.ResourceAttrDiff{
   292  			"foo": &terraform.ResourceAttrDiff{
   293  				New: "13",
   294  			},
   295  		},
   296  	}
   297  
   298  	actual, err := r.Apply(s, d, nil)
   299  	if err == nil {
   300  		t.Fatal("should error")
   301  	}
   302  
   303  	expected := &terraform.InstanceState{
   304  		ID: "foo",
   305  		Attributes: map[string]string{
   306  			"foo": "12",
   307  		},
   308  	}
   309  
   310  	if !reflect.DeepEqual(actual, expected) {
   311  		t.Fatalf("bad: %#v", actual)
   312  	}
   313  }
   314  
   315  func TestResourceApply_isNewResource(t *testing.T) {
   316  	r := &Resource{
   317  		Schema: map[string]*Schema{
   318  			"foo": &Schema{
   319  				Type:     TypeString,
   320  				Optional: true,
   321  			},
   322  		},
   323  	}
   324  
   325  	updateFunc := func(d *ResourceData, m interface{}) error {
   326  		d.Set("foo", "updated")
   327  		if d.IsNewResource() {
   328  			d.Set("foo", "new-resource")
   329  		}
   330  		return nil
   331  	}
   332  	r.Create = func(d *ResourceData, m interface{}) error {
   333  		d.SetId("foo")
   334  		d.Set("foo", "created")
   335  		return updateFunc(d, m)
   336  	}
   337  	r.Update = updateFunc
   338  
   339  	d := &terraform.InstanceDiff{
   340  		Attributes: map[string]*terraform.ResourceAttrDiff{
   341  			"foo": &terraform.ResourceAttrDiff{
   342  				New: "bla-blah",
   343  			},
   344  		},
   345  	}
   346  
   347  	// positive test
   348  	var s *terraform.InstanceState = nil
   349  
   350  	actual, err := r.Apply(s, d, nil)
   351  	if err != nil {
   352  		t.Fatalf("err: %s", err)
   353  	}
   354  
   355  	expected := &terraform.InstanceState{
   356  		ID: "foo",
   357  		Attributes: map[string]string{
   358  			"id":  "foo",
   359  			"foo": "new-resource",
   360  		},
   361  	}
   362  
   363  	if !reflect.DeepEqual(actual, expected) {
   364  		t.Fatalf("actual: %#v\nexpected: %#v",
   365  			actual, expected)
   366  	}
   367  
   368  	// negative test
   369  	s = &terraform.InstanceState{
   370  		ID: "foo",
   371  		Attributes: map[string]string{
   372  			"id":  "foo",
   373  			"foo": "new-resource",
   374  		},
   375  	}
   376  
   377  	actual, err = r.Apply(s, d, nil)
   378  	if err != nil {
   379  		t.Fatalf("err: %s", err)
   380  	}
   381  
   382  	expected = &terraform.InstanceState{
   383  		ID: "foo",
   384  		Attributes: map[string]string{
   385  			"id":  "foo",
   386  			"foo": "updated",
   387  		},
   388  	}
   389  
   390  	if !reflect.DeepEqual(actual, expected) {
   391  		t.Fatalf("actual: %#v\nexpected: %#v",
   392  			actual, expected)
   393  	}
   394  }
   395  
   396  func TestResourceInternalValidate(t *testing.T) {
   397  	cases := []struct {
   398  		In  *Resource
   399  		Err bool
   400  	}{
   401  		{
   402  			nil,
   403  			true,
   404  		},
   405  
   406  		// No optional and no required
   407  		{
   408  			&Resource{
   409  				Schema: map[string]*Schema{
   410  					"foo": &Schema{
   411  						Type:     TypeInt,
   412  						Optional: true,
   413  						Required: true,
   414  					},
   415  				},
   416  			},
   417  			true,
   418  		},
   419  
   420  		// Update undefined for non-ForceNew field
   421  		{
   422  			&Resource{
   423  				Create: func(d *ResourceData, meta interface{}) error { return nil },
   424  				Schema: map[string]*Schema{
   425  					"boo": &Schema{
   426  						Type:     TypeInt,
   427  						Optional: true,
   428  					},
   429  				},
   430  			},
   431  			true,
   432  		},
   433  
   434  		// Update defined for ForceNew field
   435  		{
   436  			&Resource{
   437  				Create: func(d *ResourceData, meta interface{}) error { return nil },
   438  				Update: func(d *ResourceData, meta interface{}) error { return nil },
   439  				Schema: map[string]*Schema{
   440  					"goo": &Schema{
   441  						Type:     TypeInt,
   442  						Optional: true,
   443  						ForceNew: true,
   444  					},
   445  				},
   446  			},
   447  			true,
   448  		},
   449  	}
   450  
   451  	for i, tc := range cases {
   452  		err := tc.In.InternalValidate(schemaMap{})
   453  		if err != nil != tc.Err {
   454  			t.Fatalf("%d: bad: %s", i, err)
   455  		}
   456  	}
   457  }
   458  
   459  func TestResourceRefresh(t *testing.T) {
   460  	r := &Resource{
   461  		SchemaVersion: 2,
   462  		Schema: map[string]*Schema{
   463  			"foo": &Schema{
   464  				Type:     TypeInt,
   465  				Optional: true,
   466  			},
   467  		},
   468  	}
   469  
   470  	r.Read = func(d *ResourceData, m interface{}) error {
   471  		if m != 42 {
   472  			return fmt.Errorf("meta not passed")
   473  		}
   474  
   475  		return d.Set("foo", d.Get("foo").(int)+1)
   476  	}
   477  
   478  	s := &terraform.InstanceState{
   479  		ID: "bar",
   480  		Attributes: map[string]string{
   481  			"foo": "12",
   482  		},
   483  	}
   484  
   485  	expected := &terraform.InstanceState{
   486  		ID: "bar",
   487  		Attributes: map[string]string{
   488  			"id":  "bar",
   489  			"foo": "13",
   490  		},
   491  		Meta: map[string]string{
   492  			"schema_version": "2",
   493  		},
   494  	}
   495  
   496  	actual, err := r.Refresh(s, 42)
   497  	if err != nil {
   498  		t.Fatalf("err: %s", err)
   499  	}
   500  
   501  	if !reflect.DeepEqual(actual, expected) {
   502  		t.Fatalf("bad: %#v", actual)
   503  	}
   504  }
   505  
   506  func TestResourceRefresh_blankId(t *testing.T) {
   507  	r := &Resource{
   508  		Schema: map[string]*Schema{
   509  			"foo": &Schema{
   510  				Type:     TypeInt,
   511  				Optional: true,
   512  			},
   513  		},
   514  	}
   515  
   516  	r.Read = func(d *ResourceData, m interface{}) error {
   517  		d.SetId("foo")
   518  		return nil
   519  	}
   520  
   521  	s := &terraform.InstanceState{
   522  		ID:         "",
   523  		Attributes: map[string]string{},
   524  	}
   525  
   526  	actual, err := r.Refresh(s, 42)
   527  	if err != nil {
   528  		t.Fatalf("err: %s", err)
   529  	}
   530  	if actual != nil {
   531  		t.Fatalf("bad: %#v", actual)
   532  	}
   533  }
   534  
   535  func TestResourceRefresh_delete(t *testing.T) {
   536  	r := &Resource{
   537  		Schema: map[string]*Schema{
   538  			"foo": &Schema{
   539  				Type:     TypeInt,
   540  				Optional: true,
   541  			},
   542  		},
   543  	}
   544  
   545  	r.Read = func(d *ResourceData, m interface{}) error {
   546  		d.SetId("")
   547  		return nil
   548  	}
   549  
   550  	s := &terraform.InstanceState{
   551  		ID: "bar",
   552  		Attributes: map[string]string{
   553  			"foo": "12",
   554  		},
   555  	}
   556  
   557  	actual, err := r.Refresh(s, 42)
   558  	if err != nil {
   559  		t.Fatalf("err: %s", err)
   560  	}
   561  
   562  	if actual != nil {
   563  		t.Fatalf("bad: %#v", actual)
   564  	}
   565  }
   566  
   567  func TestResourceRefresh_existsError(t *testing.T) {
   568  	r := &Resource{
   569  		Schema: map[string]*Schema{
   570  			"foo": &Schema{
   571  				Type:     TypeInt,
   572  				Optional: true,
   573  			},
   574  		},
   575  	}
   576  
   577  	r.Exists = func(*ResourceData, interface{}) (bool, error) {
   578  		return false, fmt.Errorf("error")
   579  	}
   580  
   581  	r.Read = func(d *ResourceData, m interface{}) error {
   582  		panic("shouldn't be called")
   583  	}
   584  
   585  	s := &terraform.InstanceState{
   586  		ID: "bar",
   587  		Attributes: map[string]string{
   588  			"foo": "12",
   589  		},
   590  	}
   591  
   592  	actual, err := r.Refresh(s, 42)
   593  	if err == nil {
   594  		t.Fatalf("should error")
   595  	}
   596  	if !reflect.DeepEqual(actual, s) {
   597  		t.Fatalf("bad: %#v", actual)
   598  	}
   599  }
   600  
   601  func TestResourceRefresh_noExists(t *testing.T) {
   602  	r := &Resource{
   603  		Schema: map[string]*Schema{
   604  			"foo": &Schema{
   605  				Type:     TypeInt,
   606  				Optional: true,
   607  			},
   608  		},
   609  	}
   610  
   611  	r.Exists = func(*ResourceData, interface{}) (bool, error) {
   612  		return false, nil
   613  	}
   614  
   615  	r.Read = func(d *ResourceData, m interface{}) error {
   616  		panic("shouldn't be called")
   617  	}
   618  
   619  	s := &terraform.InstanceState{
   620  		ID: "bar",
   621  		Attributes: map[string]string{
   622  			"foo": "12",
   623  		},
   624  	}
   625  
   626  	actual, err := r.Refresh(s, 42)
   627  	if err != nil {
   628  		t.Fatalf("err: %s", err)
   629  	}
   630  	if actual != nil {
   631  		t.Fatalf("should have no state")
   632  	}
   633  }
   634  
   635  func TestResourceRefresh_needsMigration(t *testing.T) {
   636  	// Schema v2 it deals only in newfoo, which tracks foo as an int
   637  	r := &Resource{
   638  		SchemaVersion: 2,
   639  		Schema: map[string]*Schema{
   640  			"newfoo": &Schema{
   641  				Type:     TypeInt,
   642  				Optional: true,
   643  			},
   644  		},
   645  	}
   646  
   647  	r.Read = func(d *ResourceData, m interface{}) error {
   648  		return d.Set("newfoo", d.Get("newfoo").(int)+1)
   649  	}
   650  
   651  	r.MigrateState = func(
   652  		v int,
   653  		s *terraform.InstanceState,
   654  		meta interface{}) (*terraform.InstanceState, error) {
   655  		// Real state migration functions will probably switch on this value,
   656  		// but we'll just assert on it for now.
   657  		if v != 1 {
   658  			t.Fatalf("Expected StateSchemaVersion to be 1, got %d", v)
   659  		}
   660  
   661  		if meta != 42 {
   662  			t.Fatal("Expected meta to be passed through to the migration function")
   663  		}
   664  
   665  		oldfoo, err := strconv.ParseFloat(s.Attributes["oldfoo"], 64)
   666  		if err != nil {
   667  			t.Fatalf("err: %#v", err)
   668  		}
   669  		s.Attributes["newfoo"] = strconv.Itoa(int(oldfoo * 10))
   670  		delete(s.Attributes, "oldfoo")
   671  
   672  		return s, nil
   673  	}
   674  
   675  	// State is v1 and deals in oldfoo, which tracked foo as a float at 1/10th
   676  	// the scale of newfoo
   677  	s := &terraform.InstanceState{
   678  		ID: "bar",
   679  		Attributes: map[string]string{
   680  			"oldfoo": "1.2",
   681  		},
   682  		Meta: map[string]string{
   683  			"schema_version": "1",
   684  		},
   685  	}
   686  
   687  	actual, err := r.Refresh(s, 42)
   688  	if err != nil {
   689  		t.Fatalf("err: %s", err)
   690  	}
   691  
   692  	expected := &terraform.InstanceState{
   693  		ID: "bar",
   694  		Attributes: map[string]string{
   695  			"id":     "bar",
   696  			"newfoo": "13",
   697  		},
   698  		Meta: map[string]string{
   699  			"schema_version": "2",
   700  		},
   701  	}
   702  
   703  	if !reflect.DeepEqual(actual, expected) {
   704  		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
   705  	}
   706  }
   707  
   708  func TestResourceRefresh_noMigrationNeeded(t *testing.T) {
   709  	r := &Resource{
   710  		SchemaVersion: 2,
   711  		Schema: map[string]*Schema{
   712  			"newfoo": &Schema{
   713  				Type:     TypeInt,
   714  				Optional: true,
   715  			},
   716  		},
   717  	}
   718  
   719  	r.Read = func(d *ResourceData, m interface{}) error {
   720  		return d.Set("newfoo", d.Get("newfoo").(int)+1)
   721  	}
   722  
   723  	r.MigrateState = func(
   724  		v int,
   725  		s *terraform.InstanceState,
   726  		meta interface{}) (*terraform.InstanceState, error) {
   727  		t.Fatal("Migrate function shouldn't be called!")
   728  		return nil, nil
   729  	}
   730  
   731  	s := &terraform.InstanceState{
   732  		ID: "bar",
   733  		Attributes: map[string]string{
   734  			"newfoo": "12",
   735  		},
   736  		Meta: map[string]string{
   737  			"schema_version": "2",
   738  		},
   739  	}
   740  
   741  	actual, err := r.Refresh(s, nil)
   742  	if err != nil {
   743  		t.Fatalf("err: %s", err)
   744  	}
   745  
   746  	expected := &terraform.InstanceState{
   747  		ID: "bar",
   748  		Attributes: map[string]string{
   749  			"id":     "bar",
   750  			"newfoo": "13",
   751  		},
   752  		Meta: map[string]string{
   753  			"schema_version": "2",
   754  		},
   755  	}
   756  
   757  	if !reflect.DeepEqual(actual, expected) {
   758  		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
   759  	}
   760  }
   761  
   762  func TestResourceRefresh_stateSchemaVersionUnset(t *testing.T) {
   763  	r := &Resource{
   764  		// Version 1 > Version 0
   765  		SchemaVersion: 1,
   766  		Schema: map[string]*Schema{
   767  			"newfoo": &Schema{
   768  				Type:     TypeInt,
   769  				Optional: true,
   770  			},
   771  		},
   772  	}
   773  
   774  	r.Read = func(d *ResourceData, m interface{}) error {
   775  		return d.Set("newfoo", d.Get("newfoo").(int)+1)
   776  	}
   777  
   778  	r.MigrateState = func(
   779  		v int,
   780  		s *terraform.InstanceState,
   781  		meta interface{}) (*terraform.InstanceState, error) {
   782  		s.Attributes["newfoo"] = s.Attributes["oldfoo"]
   783  		return s, nil
   784  	}
   785  
   786  	s := &terraform.InstanceState{
   787  		ID: "bar",
   788  		Attributes: map[string]string{
   789  			"oldfoo": "12",
   790  		},
   791  	}
   792  
   793  	actual, err := r.Refresh(s, nil)
   794  	if err != nil {
   795  		t.Fatalf("err: %s", err)
   796  	}
   797  
   798  	expected := &terraform.InstanceState{
   799  		ID: "bar",
   800  		Attributes: map[string]string{
   801  			"id":     "bar",
   802  			"newfoo": "13",
   803  		},
   804  		Meta: map[string]string{
   805  			"schema_version": "1",
   806  		},
   807  	}
   808  
   809  	if !reflect.DeepEqual(actual, expected) {
   810  		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
   811  	}
   812  }
   813  
   814  func TestResourceRefresh_migrateStateErr(t *testing.T) {
   815  	r := &Resource{
   816  		SchemaVersion: 2,
   817  		Schema: map[string]*Schema{
   818  			"newfoo": &Schema{
   819  				Type:     TypeInt,
   820  				Optional: true,
   821  			},
   822  		},
   823  	}
   824  
   825  	r.Read = func(d *ResourceData, m interface{}) error {
   826  		t.Fatal("Read should never be called!")
   827  		return nil
   828  	}
   829  
   830  	r.MigrateState = func(
   831  		v int,
   832  		s *terraform.InstanceState,
   833  		meta interface{}) (*terraform.InstanceState, error) {
   834  		return s, fmt.Errorf("triggering an error")
   835  	}
   836  
   837  	s := &terraform.InstanceState{
   838  		ID: "bar",
   839  		Attributes: map[string]string{
   840  			"oldfoo": "12",
   841  		},
   842  	}
   843  
   844  	_, err := r.Refresh(s, nil)
   845  	if err == nil {
   846  		t.Fatal("expected error, but got none!")
   847  	}
   848  }