github.com/pmcatominey/terraform@v0.7.0-rc2.0.20160708105029-1401a52a5cc5/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  		Writable bool
   400  		Err      bool
   401  	}{
   402  		{
   403  			nil,
   404  			true,
   405  			true,
   406  		},
   407  
   408  		// No optional and no required
   409  		{
   410  			&Resource{
   411  				Schema: map[string]*Schema{
   412  					"foo": &Schema{
   413  						Type:     TypeInt,
   414  						Optional: true,
   415  						Required: true,
   416  					},
   417  				},
   418  			},
   419  			true,
   420  			true,
   421  		},
   422  
   423  		// Update undefined for non-ForceNew field
   424  		{
   425  			&Resource{
   426  				Create: func(d *ResourceData, meta interface{}) error { return nil },
   427  				Schema: map[string]*Schema{
   428  					"boo": &Schema{
   429  						Type:     TypeInt,
   430  						Optional: true,
   431  					},
   432  				},
   433  			},
   434  			true,
   435  			true,
   436  		},
   437  
   438  		// Update defined for ForceNew field
   439  		{
   440  			&Resource{
   441  				Create: func(d *ResourceData, meta interface{}) error { return nil },
   442  				Update: func(d *ResourceData, meta interface{}) error { return nil },
   443  				Schema: map[string]*Schema{
   444  					"goo": &Schema{
   445  						Type:     TypeInt,
   446  						Optional: true,
   447  						ForceNew: true,
   448  					},
   449  				},
   450  			},
   451  			true,
   452  			true,
   453  		},
   454  
   455  		// non-writable doesn't need Update, Create or Delete
   456  		{
   457  			&Resource{
   458  				Schema: map[string]*Schema{
   459  					"goo": &Schema{
   460  						Type:     TypeInt,
   461  						Optional: true,
   462  					},
   463  				},
   464  			},
   465  			false,
   466  			false,
   467  		},
   468  
   469  		// non-writable *must not* have Create
   470  		{
   471  			&Resource{
   472  				Create: func(d *ResourceData, meta interface{}) error { return nil },
   473  				Schema: map[string]*Schema{
   474  					"goo": &Schema{
   475  						Type:     TypeInt,
   476  						Optional: true,
   477  					},
   478  				},
   479  			},
   480  			false,
   481  			true,
   482  		},
   483  	}
   484  
   485  	for i, tc := range cases {
   486  		err := tc.In.InternalValidate(schemaMap{}, tc.Writable)
   487  		if err != nil != tc.Err {
   488  			t.Fatalf("%d: bad: %s", i, err)
   489  		}
   490  	}
   491  }
   492  
   493  func TestResourceRefresh(t *testing.T) {
   494  	r := &Resource{
   495  		SchemaVersion: 2,
   496  		Schema: map[string]*Schema{
   497  			"foo": &Schema{
   498  				Type:     TypeInt,
   499  				Optional: true,
   500  			},
   501  		},
   502  	}
   503  
   504  	r.Read = func(d *ResourceData, m interface{}) error {
   505  		if m != 42 {
   506  			return fmt.Errorf("meta not passed")
   507  		}
   508  
   509  		return d.Set("foo", d.Get("foo").(int)+1)
   510  	}
   511  
   512  	s := &terraform.InstanceState{
   513  		ID: "bar",
   514  		Attributes: map[string]string{
   515  			"foo": "12",
   516  		},
   517  	}
   518  
   519  	expected := &terraform.InstanceState{
   520  		ID: "bar",
   521  		Attributes: map[string]string{
   522  			"id":  "bar",
   523  			"foo": "13",
   524  		},
   525  		Meta: map[string]string{
   526  			"schema_version": "2",
   527  		},
   528  	}
   529  
   530  	actual, err := r.Refresh(s, 42)
   531  	if err != nil {
   532  		t.Fatalf("err: %s", err)
   533  	}
   534  
   535  	if !reflect.DeepEqual(actual, expected) {
   536  		t.Fatalf("bad: %#v", actual)
   537  	}
   538  }
   539  
   540  func TestResourceRefresh_blankId(t *testing.T) {
   541  	r := &Resource{
   542  		Schema: map[string]*Schema{
   543  			"foo": &Schema{
   544  				Type:     TypeInt,
   545  				Optional: true,
   546  			},
   547  		},
   548  	}
   549  
   550  	r.Read = func(d *ResourceData, m interface{}) error {
   551  		d.SetId("foo")
   552  		return nil
   553  	}
   554  
   555  	s := &terraform.InstanceState{
   556  		ID:         "",
   557  		Attributes: map[string]string{},
   558  	}
   559  
   560  	actual, err := r.Refresh(s, 42)
   561  	if err != nil {
   562  		t.Fatalf("err: %s", err)
   563  	}
   564  	if actual != nil {
   565  		t.Fatalf("bad: %#v", actual)
   566  	}
   567  }
   568  
   569  func TestResourceRefresh_delete(t *testing.T) {
   570  	r := &Resource{
   571  		Schema: map[string]*Schema{
   572  			"foo": &Schema{
   573  				Type:     TypeInt,
   574  				Optional: true,
   575  			},
   576  		},
   577  	}
   578  
   579  	r.Read = func(d *ResourceData, m interface{}) error {
   580  		d.SetId("")
   581  		return nil
   582  	}
   583  
   584  	s := &terraform.InstanceState{
   585  		ID: "bar",
   586  		Attributes: map[string]string{
   587  			"foo": "12",
   588  		},
   589  	}
   590  
   591  	actual, err := r.Refresh(s, 42)
   592  	if err != nil {
   593  		t.Fatalf("err: %s", err)
   594  	}
   595  
   596  	if actual != nil {
   597  		t.Fatalf("bad: %#v", actual)
   598  	}
   599  }
   600  
   601  func TestResourceRefresh_existsError(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, fmt.Errorf("error")
   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("should error")
   629  	}
   630  	if !reflect.DeepEqual(actual, s) {
   631  		t.Fatalf("bad: %#v", actual)
   632  	}
   633  }
   634  
   635  func TestResourceRefresh_noExists(t *testing.T) {
   636  	r := &Resource{
   637  		Schema: map[string]*Schema{
   638  			"foo": &Schema{
   639  				Type:     TypeInt,
   640  				Optional: true,
   641  			},
   642  		},
   643  	}
   644  
   645  	r.Exists = func(*ResourceData, interface{}) (bool, error) {
   646  		return false, nil
   647  	}
   648  
   649  	r.Read = func(d *ResourceData, m interface{}) error {
   650  		panic("shouldn't be called")
   651  	}
   652  
   653  	s := &terraform.InstanceState{
   654  		ID: "bar",
   655  		Attributes: map[string]string{
   656  			"foo": "12",
   657  		},
   658  	}
   659  
   660  	actual, err := r.Refresh(s, 42)
   661  	if err != nil {
   662  		t.Fatalf("err: %s", err)
   663  	}
   664  	if actual != nil {
   665  		t.Fatalf("should have no state")
   666  	}
   667  }
   668  
   669  func TestResourceRefresh_needsMigration(t *testing.T) {
   670  	// Schema v2 it deals only in newfoo, which tracks foo as an int
   671  	r := &Resource{
   672  		SchemaVersion: 2,
   673  		Schema: map[string]*Schema{
   674  			"newfoo": &Schema{
   675  				Type:     TypeInt,
   676  				Optional: true,
   677  			},
   678  		},
   679  	}
   680  
   681  	r.Read = func(d *ResourceData, m interface{}) error {
   682  		return d.Set("newfoo", d.Get("newfoo").(int)+1)
   683  	}
   684  
   685  	r.MigrateState = func(
   686  		v int,
   687  		s *terraform.InstanceState,
   688  		meta interface{}) (*terraform.InstanceState, error) {
   689  		// Real state migration functions will probably switch on this value,
   690  		// but we'll just assert on it for now.
   691  		if v != 1 {
   692  			t.Fatalf("Expected StateSchemaVersion to be 1, got %d", v)
   693  		}
   694  
   695  		if meta != 42 {
   696  			t.Fatal("Expected meta to be passed through to the migration function")
   697  		}
   698  
   699  		oldfoo, err := strconv.ParseFloat(s.Attributes["oldfoo"], 64)
   700  		if err != nil {
   701  			t.Fatalf("err: %#v", err)
   702  		}
   703  		s.Attributes["newfoo"] = strconv.Itoa(int(oldfoo * 10))
   704  		delete(s.Attributes, "oldfoo")
   705  
   706  		return s, nil
   707  	}
   708  
   709  	// State is v1 and deals in oldfoo, which tracked foo as a float at 1/10th
   710  	// the scale of newfoo
   711  	s := &terraform.InstanceState{
   712  		ID: "bar",
   713  		Attributes: map[string]string{
   714  			"oldfoo": "1.2",
   715  		},
   716  		Meta: map[string]string{
   717  			"schema_version": "1",
   718  		},
   719  	}
   720  
   721  	actual, err := r.Refresh(s, 42)
   722  	if err != nil {
   723  		t.Fatalf("err: %s", err)
   724  	}
   725  
   726  	expected := &terraform.InstanceState{
   727  		ID: "bar",
   728  		Attributes: map[string]string{
   729  			"id":     "bar",
   730  			"newfoo": "13",
   731  		},
   732  		Meta: map[string]string{
   733  			"schema_version": "2",
   734  		},
   735  	}
   736  
   737  	if !reflect.DeepEqual(actual, expected) {
   738  		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
   739  	}
   740  }
   741  
   742  func TestResourceRefresh_noMigrationNeeded(t *testing.T) {
   743  	r := &Resource{
   744  		SchemaVersion: 2,
   745  		Schema: map[string]*Schema{
   746  			"newfoo": &Schema{
   747  				Type:     TypeInt,
   748  				Optional: true,
   749  			},
   750  		},
   751  	}
   752  
   753  	r.Read = func(d *ResourceData, m interface{}) error {
   754  		return d.Set("newfoo", d.Get("newfoo").(int)+1)
   755  	}
   756  
   757  	r.MigrateState = func(
   758  		v int,
   759  		s *terraform.InstanceState,
   760  		meta interface{}) (*terraform.InstanceState, error) {
   761  		t.Fatal("Migrate function shouldn't be called!")
   762  		return nil, nil
   763  	}
   764  
   765  	s := &terraform.InstanceState{
   766  		ID: "bar",
   767  		Attributes: map[string]string{
   768  			"newfoo": "12",
   769  		},
   770  		Meta: map[string]string{
   771  			"schema_version": "2",
   772  		},
   773  	}
   774  
   775  	actual, err := r.Refresh(s, nil)
   776  	if err != nil {
   777  		t.Fatalf("err: %s", err)
   778  	}
   779  
   780  	expected := &terraform.InstanceState{
   781  		ID: "bar",
   782  		Attributes: map[string]string{
   783  			"id":     "bar",
   784  			"newfoo": "13",
   785  		},
   786  		Meta: map[string]string{
   787  			"schema_version": "2",
   788  		},
   789  	}
   790  
   791  	if !reflect.DeepEqual(actual, expected) {
   792  		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
   793  	}
   794  }
   795  
   796  func TestResourceRefresh_stateSchemaVersionUnset(t *testing.T) {
   797  	r := &Resource{
   798  		// Version 1 > Version 0
   799  		SchemaVersion: 1,
   800  		Schema: map[string]*Schema{
   801  			"newfoo": &Schema{
   802  				Type:     TypeInt,
   803  				Optional: true,
   804  			},
   805  		},
   806  	}
   807  
   808  	r.Read = func(d *ResourceData, m interface{}) error {
   809  		return d.Set("newfoo", d.Get("newfoo").(int)+1)
   810  	}
   811  
   812  	r.MigrateState = func(
   813  		v int,
   814  		s *terraform.InstanceState,
   815  		meta interface{}) (*terraform.InstanceState, error) {
   816  		s.Attributes["newfoo"] = s.Attributes["oldfoo"]
   817  		return s, nil
   818  	}
   819  
   820  	s := &terraform.InstanceState{
   821  		ID: "bar",
   822  		Attributes: map[string]string{
   823  			"oldfoo": "12",
   824  		},
   825  	}
   826  
   827  	actual, err := r.Refresh(s, nil)
   828  	if err != nil {
   829  		t.Fatalf("err: %s", err)
   830  	}
   831  
   832  	expected := &terraform.InstanceState{
   833  		ID: "bar",
   834  		Attributes: map[string]string{
   835  			"id":     "bar",
   836  			"newfoo": "13",
   837  		},
   838  		Meta: map[string]string{
   839  			"schema_version": "1",
   840  		},
   841  	}
   842  
   843  	if !reflect.DeepEqual(actual, expected) {
   844  		t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
   845  	}
   846  }
   847  
   848  func TestResourceRefresh_migrateStateErr(t *testing.T) {
   849  	r := &Resource{
   850  		SchemaVersion: 2,
   851  		Schema: map[string]*Schema{
   852  			"newfoo": &Schema{
   853  				Type:     TypeInt,
   854  				Optional: true,
   855  			},
   856  		},
   857  	}
   858  
   859  	r.Read = func(d *ResourceData, m interface{}) error {
   860  		t.Fatal("Read should never be called!")
   861  		return nil
   862  	}
   863  
   864  	r.MigrateState = func(
   865  		v int,
   866  		s *terraform.InstanceState,
   867  		meta interface{}) (*terraform.InstanceState, error) {
   868  		return s, fmt.Errorf("triggering an error")
   869  	}
   870  
   871  	s := &terraform.InstanceState{
   872  		ID: "bar",
   873  		Attributes: map[string]string{
   874  			"oldfoo": "12",
   875  		},
   876  	}
   877  
   878  	_, err := r.Refresh(s, nil)
   879  	if err == nil {
   880  		t.Fatal("expected error, but got none!")
   881  	}
   882  }
   883  
   884  func TestResourceData(t *testing.T) {
   885  	r := &Resource{
   886  		SchemaVersion: 2,
   887  		Schema: map[string]*Schema{
   888  			"foo": &Schema{
   889  				Type:     TypeInt,
   890  				Optional: true,
   891  			},
   892  		},
   893  	}
   894  
   895  	state := &terraform.InstanceState{
   896  		ID: "foo",
   897  		Attributes: map[string]string{
   898  			"id":  "foo",
   899  			"foo": "42",
   900  		},
   901  	}
   902  
   903  	data := r.Data(state)
   904  	if data.Id() != "foo" {
   905  		t.Fatalf("err: %s", data.Id())
   906  	}
   907  	if v := data.Get("foo"); v != 42 {
   908  		t.Fatalf("bad: %#v", v)
   909  	}
   910  
   911  	// Set expectations
   912  	state.Meta = map[string]string{
   913  		"schema_version": "2",
   914  	}
   915  
   916  	result := data.State()
   917  	if !reflect.DeepEqual(result, state) {
   918  		t.Fatalf("bad: %#v", result)
   919  	}
   920  }
   921  
   922  func TestResourceData_blank(t *testing.T) {
   923  	r := &Resource{
   924  		SchemaVersion: 2,
   925  		Schema: map[string]*Schema{
   926  			"foo": &Schema{
   927  				Type:     TypeInt,
   928  				Optional: true,
   929  			},
   930  		},
   931  	}
   932  
   933  	data := r.Data(nil)
   934  	if data.Id() != "" {
   935  		t.Fatalf("err: %s", data.Id())
   936  	}
   937  	if v := data.Get("foo"); v != 0 {
   938  		t.Fatalf("bad: %#v", v)
   939  	}
   940  }