github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/boskos/ranch/ranch_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package ranch
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	"k8s.io/test-infra/boskos/common"
    25  )
    26  
    27  func MakeTestRanch(resources []common.Resource) *Ranch {
    28  	newRanch := &Ranch{
    29  		Resources: resources,
    30  	}
    31  
    32  	return newRanch
    33  }
    34  
    35  func AreErrorsEqual(got error, expect error) bool {
    36  	if got == nil && expect == nil {
    37  		return true
    38  	}
    39  
    40  	if got == nil || expect == nil {
    41  		return false
    42  	}
    43  
    44  	switch got.(type) {
    45  	default:
    46  		return false
    47  	case *OwnerNotMatch:
    48  		if o, ok := expect.(*OwnerNotMatch); ok {
    49  			if o.request == got.(*OwnerNotMatch).request && o.owner == got.(*OwnerNotMatch).owner {
    50  				return true
    51  			}
    52  		}
    53  		return false
    54  	case *ResourceNotFound:
    55  		if o, ok := expect.(*ResourceNotFound); ok {
    56  			if o.name == got.(*ResourceNotFound).name {
    57  				return true
    58  			}
    59  		}
    60  		return false
    61  	case *StateNotMatch:
    62  		if o, ok := expect.(*StateNotMatch); ok {
    63  			if o.expect == got.(*StateNotMatch).expect && o.current == got.(*StateNotMatch).current {
    64  				return true
    65  			}
    66  		}
    67  		return false
    68  	}
    69  }
    70  
    71  func TestAcquire(t *testing.T) {
    72  	FakeNow := time.Now()
    73  	var testcases = []struct {
    74  		name      string
    75  		resources []common.Resource
    76  		owner     string
    77  		rtype     string
    78  		state     string
    79  		dest      string
    80  		expectErr error
    81  	}{
    82  		{
    83  			name:      "ranch has no resource",
    84  			resources: []common.Resource{},
    85  			owner:     "user",
    86  			rtype:     "t",
    87  			state:     "s",
    88  			dest:      "d",
    89  			expectErr: &ResourceNotFound{"t"},
    90  		},
    91  		{
    92  			name: "no match type",
    93  			resources: []common.Resource{
    94  				{
    95  					Name:       "res",
    96  					Type:       "wrong",
    97  					State:      "s",
    98  					Owner:      "",
    99  					LastUpdate: FakeNow,
   100  				},
   101  			},
   102  			owner:     "user",
   103  			rtype:     "t",
   104  			state:     "s",
   105  			dest:      "d",
   106  			expectErr: &ResourceNotFound{"t"},
   107  		},
   108  		{
   109  			name: "no match state",
   110  			resources: []common.Resource{
   111  				{
   112  					Name:       "res",
   113  					Type:       "t",
   114  					State:      "wrong",
   115  					Owner:      "",
   116  					LastUpdate: FakeNow,
   117  				},
   118  			},
   119  			owner:     "user",
   120  			rtype:     "t",
   121  			state:     "s",
   122  			dest:      "d",
   123  			expectErr: &ResourceNotFound{"t"},
   124  		},
   125  		{
   126  			name: "busy",
   127  			resources: []common.Resource{
   128  				{
   129  					Name:       "res",
   130  					Type:       "t",
   131  					State:      "s",
   132  					Owner:      "foo",
   133  					LastUpdate: FakeNow,
   134  				},
   135  			},
   136  			owner:     "user",
   137  			rtype:     "t",
   138  			state:     "s",
   139  			dest:      "d",
   140  			expectErr: &ResourceNotFound{"t"},
   141  		},
   142  		{
   143  			name: "ok",
   144  			resources: []common.Resource{
   145  				{
   146  					Name:       "res",
   147  					Type:       "t",
   148  					State:      "s",
   149  					Owner:      "",
   150  					LastUpdate: FakeNow,
   151  				},
   152  			},
   153  			owner:     "user",
   154  			rtype:     "t",
   155  			state:     "s",
   156  			dest:      "d",
   157  			expectErr: nil,
   158  		},
   159  	}
   160  
   161  	for _, tc := range testcases {
   162  		c := MakeTestRanch(tc.resources)
   163  		res, err := c.Acquire(tc.rtype, tc.state, tc.dest, tc.owner)
   164  		if !AreErrorsEqual(err, tc.expectErr) {
   165  			t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr)
   166  			continue
   167  		}
   168  
   169  		if err == nil {
   170  			if res.State != tc.dest {
   171  				t.Errorf("%s - Wrong final state. Got %v, expect %v", tc.name, res.State, tc.dest)
   172  			}
   173  			if *res != c.Resources[0] {
   174  				t.Errorf("%s - Wrong resource. Got %v, expect %v", tc.name, res, c.Resources[0])
   175  			} else if !res.LastUpdate.After(FakeNow) {
   176  				t.Errorf("%s - LastUpdate did not update.", tc.name)
   177  			}
   178  		} else {
   179  			for _, res := range c.Resources {
   180  				if res.LastUpdate != FakeNow {
   181  					t.Errorf("%s - LastUpdate should not update. Got %v, expect %v", tc.name, c.Resources[0].LastUpdate, FakeNow)
   182  				}
   183  			}
   184  		}
   185  	}
   186  }
   187  
   188  func TestAcquireRoundRobin(t *testing.T) {
   189  	FakeNow := time.Now()
   190  	resources := []common.Resource{
   191  		{
   192  			Name:       "res-1",
   193  			Type:       "t",
   194  			State:      "s",
   195  			Owner:      "",
   196  			LastUpdate: FakeNow,
   197  		},
   198  		{
   199  			Name:       "res-2",
   200  			Type:       "t",
   201  			State:      "s",
   202  			Owner:      "",
   203  			LastUpdate: FakeNow,
   204  		},
   205  		{
   206  			Name:       "res-3",
   207  			Type:       "t",
   208  			State:      "s",
   209  			Owner:      "",
   210  			LastUpdate: FakeNow,
   211  		},
   212  		{
   213  			Name:       "res-4",
   214  			Type:       "t",
   215  			State:      "s",
   216  			Owner:      "",
   217  			LastUpdate: FakeNow,
   218  		},
   219  	}
   220  
   221  	expected := []string{"res-3", "res-4", "res-1", "res-2"}
   222  
   223  	c := MakeTestRanch(resources)
   224  	for i := 0; i < 2; i++ {
   225  		_, err := c.Acquire("t", "s", "d", "foo")
   226  		if err != nil {
   227  			t.Fatalf("Unexpected error: %v", err)
   228  		}
   229  	}
   230  
   231  	for idx := range c.Resources {
   232  		if c.Resources[idx].Name != expected[idx] {
   233  			t.Errorf("Resource %d, expected %v, got %v", idx, expected[idx], c.Resources[idx].Name)
   234  		}
   235  	}
   236  
   237  }
   238  
   239  func TestRelease(t *testing.T) {
   240  	FakeNow := time.Now()
   241  	var testcases = []struct {
   242  		name      string
   243  		resources []common.Resource
   244  		resName   string
   245  		owner     string
   246  		dest      string
   247  		expectErr error
   248  	}{
   249  		{
   250  			name:      "ranch has no resource",
   251  			resources: []common.Resource{},
   252  			resName:   "res",
   253  			owner:     "user",
   254  			dest:      "d",
   255  			expectErr: &ResourceNotFound{"res"},
   256  		},
   257  		{
   258  			name: "wrong owner",
   259  			resources: []common.Resource{
   260  				{
   261  					Name:       "res",
   262  					Type:       "t",
   263  					State:      "s",
   264  					Owner:      "merlin",
   265  					LastUpdate: FakeNow,
   266  				},
   267  			},
   268  			resName:   "res",
   269  			owner:     "user",
   270  			dest:      "d",
   271  			expectErr: &OwnerNotMatch{"merlin", "user"},
   272  		},
   273  		{
   274  			name: "no match name",
   275  			resources: []common.Resource{
   276  				{
   277  					Name:       "foo",
   278  					Type:       "t",
   279  					State:      "s",
   280  					Owner:      "merlin",
   281  					LastUpdate: FakeNow,
   282  				},
   283  			},
   284  			resName:   "res",
   285  			owner:     "user",
   286  			dest:      "d",
   287  			expectErr: &ResourceNotFound{"res"},
   288  		},
   289  		{
   290  			name: "ok",
   291  			resources: []common.Resource{
   292  				{
   293  					Name:       "res",
   294  					Type:       "t",
   295  					State:      "s",
   296  					Owner:      "merlin",
   297  					LastUpdate: FakeNow,
   298  				},
   299  			},
   300  			resName:   "res",
   301  			owner:     "merlin",
   302  			dest:      "d",
   303  			expectErr: nil,
   304  		},
   305  	}
   306  
   307  	for _, tc := range testcases {
   308  		c := MakeTestRanch(tc.resources)
   309  		err := c.Release(tc.resName, tc.dest, tc.owner)
   310  		if !AreErrorsEqual(err, tc.expectErr) {
   311  			t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr)
   312  			continue
   313  		}
   314  
   315  		if err == nil {
   316  			if c.Resources[0].Owner != "" {
   317  				t.Errorf("%s - Wrong owner after release. Got %v, expect empty", tc.name, c.Resources[0].Owner)
   318  			} else if c.Resources[0].State != tc.dest {
   319  				t.Errorf("%s - Wrong state after release. Got %v, expect %v", tc.name, c.Resources[0].State, tc.dest)
   320  			} else if !c.Resources[0].LastUpdate.After(FakeNow) {
   321  				t.Errorf("%s - LastUpdate did not update.", tc.name)
   322  			}
   323  		} else {
   324  			for _, res := range c.Resources {
   325  				if res.LastUpdate != FakeNow {
   326  					t.Errorf("%s - LastUpdate should not update. Got %v, expect %v", tc.name, c.Resources[0].LastUpdate, FakeNow)
   327  				}
   328  			}
   329  		}
   330  	}
   331  }
   332  
   333  func TestReset(t *testing.T) {
   334  	FakeNow := time.Now()
   335  
   336  	var testcases = []struct {
   337  		name       string
   338  		resources  []common.Resource
   339  		rtype      string
   340  		state      string
   341  		dest       string
   342  		expire     time.Duration
   343  		hasContent bool
   344  	}{
   345  
   346  		{
   347  			name: "empty - has no owner",
   348  			resources: []common.Resource{
   349  				{
   350  					Name:       "res",
   351  					Type:       "t",
   352  					State:      "s",
   353  					Owner:      "",
   354  					LastUpdate: FakeNow.Add(-time.Minute * 20),
   355  				},
   356  			},
   357  			rtype:  "t",
   358  			state:  "s",
   359  			expire: time.Minute * 10,
   360  			dest:   "d",
   361  		},
   362  		{
   363  			name: "empty - not expire",
   364  			resources: []common.Resource{
   365  				{
   366  					Name:       "res",
   367  					Type:       "t",
   368  					State:      "s",
   369  					Owner:      "",
   370  					LastUpdate: FakeNow,
   371  				},
   372  			},
   373  			rtype:  "t",
   374  			state:  "s",
   375  			expire: time.Minute * 10,
   376  			dest:   "d",
   377  		},
   378  		{
   379  			name: "empty - no match type",
   380  			resources: []common.Resource{
   381  				{
   382  					Name:       "res",
   383  					Type:       "wrong",
   384  					State:      "s",
   385  					Owner:      "",
   386  					LastUpdate: FakeNow.Add(-time.Minute * 20),
   387  				},
   388  			},
   389  			rtype:  "t",
   390  			state:  "s",
   391  			expire: time.Minute * 10,
   392  			dest:   "d",
   393  		},
   394  		{
   395  			name: "empty - no match state",
   396  			resources: []common.Resource{
   397  				{
   398  					Name:       "res",
   399  					Type:       "t",
   400  					State:      "wrong",
   401  					Owner:      "",
   402  					LastUpdate: FakeNow.Add(-time.Minute * 20),
   403  				},
   404  			},
   405  			rtype:  "t",
   406  			state:  "s",
   407  			expire: time.Minute * 10,
   408  			dest:   "d",
   409  		},
   410  		{
   411  			name: "ok",
   412  			resources: []common.Resource{
   413  				{
   414  					Name:       "res",
   415  					Type:       "t",
   416  					State:      "s",
   417  					Owner:      "user",
   418  					LastUpdate: FakeNow.Add(-time.Minute * 20),
   419  				},
   420  			},
   421  			rtype:      "t",
   422  			state:      "s",
   423  			expire:     time.Minute * 10,
   424  			dest:       "d",
   425  			hasContent: true,
   426  		},
   427  	}
   428  
   429  	for _, tc := range testcases {
   430  		c := MakeTestRanch(tc.resources)
   431  		rmap := c.Reset(tc.rtype, tc.state, tc.expire, tc.dest)
   432  
   433  		if !tc.hasContent {
   434  			if len(rmap) != 0 {
   435  				t.Errorf("%s - Expect empty map. Got %v", tc.name, rmap)
   436  			}
   437  		} else {
   438  			if owner, ok := rmap["res"]; !ok || owner != "user" {
   439  				t.Errorf("%s - Expect res - user. Got %v", tc.name, rmap)
   440  			}
   441  			if !c.Resources[0].LastUpdate.After(FakeNow) {
   442  				t.Errorf("%s - LastUpdate did not update.", tc.name)
   443  			}
   444  		}
   445  	}
   446  }
   447  
   448  func TestUpdate(t *testing.T) {
   449  	FakeNow := time.Now()
   450  
   451  	var testcases = []struct {
   452  		name      string
   453  		resources []common.Resource
   454  		resName   string
   455  		owner     string
   456  		state     string
   457  		expectErr error
   458  	}{
   459  		{
   460  			name:      "ranch has no resource",
   461  			resources: []common.Resource{},
   462  			resName:   "res",
   463  			owner:     "user",
   464  			state:     "s",
   465  			expectErr: &ResourceNotFound{"res"},
   466  		},
   467  		{
   468  			name: "wrong owner",
   469  			resources: []common.Resource{
   470  				{
   471  					Name:       "res",
   472  					Type:       "t",
   473  					State:      "s",
   474  					Owner:      "merlin",
   475  					LastUpdate: FakeNow,
   476  				},
   477  			},
   478  			resName:   "res",
   479  			owner:     "user",
   480  			state:     "s",
   481  			expectErr: &OwnerNotMatch{"merlin", "user"},
   482  		},
   483  		{
   484  			name: "wrong state",
   485  			resources: []common.Resource{
   486  				{
   487  					Name:       "res",
   488  					Type:       "t",
   489  					State:      "s",
   490  					Owner:      "merlin",
   491  					LastUpdate: FakeNow,
   492  				},
   493  			},
   494  			resName:   "res",
   495  			owner:     "merlin",
   496  			state:     "foo",
   497  			expectErr: &StateNotMatch{"s", "foo"},
   498  		},
   499  		{
   500  			name: "no matched resource",
   501  			resources: []common.Resource{
   502  				{
   503  					Name:       "foo",
   504  					Type:       "t",
   505  					State:      "s",
   506  					Owner:      "merlin",
   507  					LastUpdate: FakeNow,
   508  				},
   509  			},
   510  			resName:   "res",
   511  			owner:     "merlin",
   512  			state:     "s",
   513  			expectErr: &ResourceNotFound{"res"},
   514  		},
   515  		{
   516  			name: "ok",
   517  			resources: []common.Resource{
   518  				{
   519  					Name:       "res",
   520  					Type:       "t",
   521  					State:      "s",
   522  					Owner:      "merlin",
   523  					LastUpdate: FakeNow,
   524  				},
   525  			},
   526  			resName: "res",
   527  			owner:   "merlin",
   528  			state:   "s",
   529  		},
   530  	}
   531  
   532  	for _, tc := range testcases {
   533  		c := MakeTestRanch(tc.resources)
   534  		err := c.Update(tc.resName, tc.owner, tc.state)
   535  		if !AreErrorsEqual(err, tc.expectErr) {
   536  			t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr)
   537  			continue
   538  		}
   539  
   540  		if err == nil {
   541  			if c.Resources[0].Owner != tc.owner {
   542  				t.Errorf("%s - Wrong owner after release. Got %v, expect %v", tc.name, c.Resources[0].Owner, tc.owner)
   543  			} else if c.Resources[0].State != tc.state {
   544  				t.Errorf("%s - Wrong state after release. Got %v, expect %v", tc.name, c.Resources[0].State, tc.state)
   545  			} else if !c.Resources[0].LastUpdate.After(FakeNow) {
   546  				t.Errorf("%s - LastUpdate did not update.", tc.name)
   547  			}
   548  		} else {
   549  			for _, res := range c.Resources {
   550  				if res.LastUpdate != FakeNow {
   551  					t.Errorf("%s - LastUpdate should not update. Got %v, expect %v", tc.name, c.Resources[0].LastUpdate, FakeNow)
   552  				}
   553  			}
   554  		}
   555  	}
   556  }
   557  
   558  func TestMetric(t *testing.T) {
   559  	var testcases = []struct {
   560  		name         string
   561  		resources    []common.Resource
   562  		metricType   string
   563  		expectErr    error
   564  		expectMetric common.Metric
   565  	}{
   566  		{
   567  			name:       "ranch has no resource",
   568  			resources:  []common.Resource{},
   569  			metricType: "t",
   570  			expectErr:  &ResourceNotFound{"t"},
   571  		},
   572  		{
   573  			name: "no matching resource",
   574  			resources: []common.Resource{
   575  				{
   576  					Name:  "res",
   577  					Type:  "t",
   578  					State: "s",
   579  					Owner: "merlin",
   580  				},
   581  			},
   582  			metricType: "foo",
   583  			expectErr:  &ResourceNotFound{"foo"},
   584  		},
   585  		{
   586  			name: "one resource",
   587  			resources: []common.Resource{
   588  				{
   589  					Name:  "res",
   590  					Type:  "t",
   591  					State: "s",
   592  					Owner: "merlin",
   593  				},
   594  			},
   595  			metricType: "t",
   596  			expectMetric: common.Metric{
   597  				Type: "t",
   598  				Current: map[string]int{
   599  					"s": 1,
   600  				},
   601  				Owners: map[string]int{
   602  					"merlin": 1,
   603  				},
   604  			},
   605  		},
   606  		{
   607  			name: "multiple resources",
   608  			resources: []common.Resource{
   609  				{
   610  					Name:  "res-1",
   611  					Type:  "t",
   612  					State: "s",
   613  					Owner: "merlin",
   614  				},
   615  				{
   616  					Name:  "res-2",
   617  					Type:  "t",
   618  					State: "p",
   619  					Owner: "pony",
   620  				},
   621  				{
   622  					Name:  "res-2",
   623  					Type:  "t",
   624  					State: "s",
   625  					Owner: "pony",
   626  				},
   627  				{
   628  					Name:  "res-3",
   629  					Type:  "foo",
   630  					State: "s",
   631  					Owner: "pony",
   632  				},
   633  				{
   634  					Name:  "res-4",
   635  					Type:  "t",
   636  					State: "d",
   637  					Owner: "merlin",
   638  				},
   639  			},
   640  			metricType: "t",
   641  			expectMetric: common.Metric{
   642  				Type: "t",
   643  				Current: map[string]int{
   644  					"s": 2,
   645  					"d": 1,
   646  					"p": 1,
   647  				},
   648  				Owners: map[string]int{
   649  					"merlin": 2,
   650  					"pony":   2,
   651  				},
   652  			},
   653  		},
   654  	}
   655  
   656  	for _, tc := range testcases {
   657  		c := MakeTestRanch(tc.resources)
   658  		metric, err := c.Metric(tc.metricType)
   659  		if !AreErrorsEqual(err, tc.expectErr) {
   660  			t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr)
   661  			continue
   662  		}
   663  
   664  		if err == nil {
   665  			if !reflect.DeepEqual(metric, tc.expectMetric) {
   666  				t.Errorf("%s - wrong metric, got %v, want %v", tc.name, metric, tc.expectMetric)
   667  			}
   668  		}
   669  	}
   670  }
   671  
   672  func TestSyncConfig(t *testing.T) {
   673  	var testcases = []struct {
   674  		name   string
   675  		oldRes []common.Resource
   676  		newRes []common.Resource
   677  		expect []common.Resource
   678  	}{
   679  		{
   680  			name:   "empty",
   681  			oldRes: []common.Resource{},
   682  			newRes: []common.Resource{},
   683  			expect: []common.Resource{},
   684  		},
   685  		{
   686  			name:   "append",
   687  			oldRes: []common.Resource{},
   688  			newRes: []common.Resource{
   689  				{
   690  					Name: "res",
   691  					Type: "t",
   692  				},
   693  			},
   694  			expect: []common.Resource{
   695  				{
   696  					Name:  "res",
   697  					Type:  "t",
   698  					State: "free",
   699  				},
   700  			},
   701  		},
   702  		{
   703  			name: "should not have a type change",
   704  			oldRes: []common.Resource{
   705  				{
   706  					Name: "res",
   707  					Type: "t",
   708  				},
   709  			},
   710  			newRes: []common.Resource{
   711  				{
   712  					Name: "res",
   713  					Type: "d",
   714  				},
   715  			},
   716  			expect: []common.Resource{
   717  				{
   718  					Name: "res",
   719  					Type: "t",
   720  				},
   721  			},
   722  		},
   723  		{
   724  			name: "delete",
   725  			oldRes: []common.Resource{
   726  				{
   727  					Name: "res",
   728  					Type: "t",
   729  				},
   730  			},
   731  			newRes: []common.Resource{},
   732  			expect: []common.Resource{},
   733  		},
   734  		{
   735  			name: "delete busy",
   736  			oldRes: []common.Resource{
   737  				{
   738  					Name:  "res",
   739  					Type:  "t",
   740  					State: "busy",
   741  					Owner: "o",
   742  				},
   743  			},
   744  			newRes: []common.Resource{},
   745  			expect: []common.Resource{
   746  				{
   747  					Name:  "res",
   748  					Type:  "t",
   749  					State: "busy",
   750  					Owner: "o",
   751  				},
   752  			},
   753  		},
   754  		{
   755  			name: "append and delete",
   756  			oldRes: []common.Resource{
   757  				{
   758  					Name: "res-1",
   759  					Type: "t",
   760  				},
   761  			},
   762  			newRes: []common.Resource{
   763  				{
   764  					Name: "res-2",
   765  					Type: "t",
   766  				},
   767  			},
   768  			expect: []common.Resource{
   769  				{
   770  					Name:  "res-2",
   771  					Type:  "t",
   772  					State: "free",
   773  				},
   774  			},
   775  		},
   776  		{
   777  			name: "append and delete busy",
   778  			oldRes: []common.Resource{
   779  				{
   780  					Name:  "res-1",
   781  					Type:  "t",
   782  					State: "busy",
   783  					Owner: "o",
   784  				},
   785  			},
   786  			newRes: []common.Resource{
   787  				{
   788  					Name: "res-2",
   789  					Type: "t",
   790  				},
   791  			},
   792  			expect: []common.Resource{
   793  				{
   794  					Name:  "res-1",
   795  					Type:  "t",
   796  					State: "busy",
   797  					Owner: "o",
   798  				},
   799  				{
   800  					Name:  "res-2",
   801  					Type:  "t",
   802  					State: "free",
   803  				},
   804  			},
   805  		},
   806  		{
   807  			name: "append/delete mixed type",
   808  			oldRes: []common.Resource{
   809  				{
   810  					Name: "res-1",
   811  					Type: "t",
   812  				},
   813  			},
   814  			newRes: []common.Resource{
   815  				{
   816  					Name: "res-2",
   817  					Type: "t",
   818  				},
   819  				{
   820  					Name: "res-3",
   821  					Type: "t2",
   822  				},
   823  			},
   824  			expect: []common.Resource{
   825  				{
   826  					Name:  "res-2",
   827  					Type:  "t",
   828  					State: "free",
   829  				},
   830  				{
   831  					Name:  "res-3",
   832  					Type:  "t2",
   833  					State: "free",
   834  				},
   835  			},
   836  		},
   837  	}
   838  
   839  	for _, tc := range testcases {
   840  		c := MakeTestRanch(tc.oldRes)
   841  		c.syncConfigHelper(tc.newRes)
   842  		if !reflect.DeepEqual(c.Resources, tc.expect) {
   843  			t.Errorf("Test %v: got %v, expect %v", tc.name, c.Resources, tc.expect)
   844  		}
   845  	}
   846  }