github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/dtclient/device_db_test.go (about)

     1  /*
     2  Copyright 2018 The KubeEdge 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 dtclient
    18  
    19  import (
    20  	"errors"
    21  	"testing"
    22  
    23  	"github.com/astaxie/beego/orm"
    24  	"github.com/golang/mock/gomock"
    25  
    26  	"github.com/kubeedge/kubeedge/edge/mocks/beego"
    27  	"github.com/kubeedge/kubeedge/edge/pkg/common/dbm"
    28  )
    29  
    30  // errFailedDBOperation is common DB operation fail error
    31  var errFailedDBOperation = errors.New("Failed DB Operation")
    32  
    33  // TestSaveDevice is used to test SaveDevice
    34  func TestSaveDevice(t *testing.T) {
    35  	// ormerMock is mocked Ormer implementation
    36  	var ormerMock *beego.MockOrmer
    37  
    38  	mockCtrl := gomock.NewController(t)
    39  	defer mockCtrl.Finish()
    40  	ormerMock = beego.NewMockOrmer(mockCtrl)
    41  	dbm.DBAccess = ormerMock
    42  
    43  	cases := []struct {
    44  		// name is name of the testcase
    45  		name string
    46  		// returnInt is first return of mock interface ormerMock
    47  		returnInt int64
    48  		// returnErr is second return of mock interface ormerMock which is also expected error
    49  		returnErr error
    50  	}{{
    51  		// Success Case
    52  		name:      "SuccessCase",
    53  		returnInt: int64(1),
    54  		returnErr: nil,
    55  	}, {
    56  		// Failure Case
    57  		name:      "FailureCase",
    58  		returnInt: int64(1),
    59  		returnErr: errFailedDBOperation,
    60  	},
    61  	}
    62  
    63  	// run the test cases
    64  	for _, test := range cases {
    65  		t.Run(test.name, func(t *testing.T) {
    66  			ormerMock.EXPECT().Insert(gomock.Any()).Return(test.returnInt, test.returnErr).Times(1)
    67  			err := SaveDevice(&Device{})
    68  			if test.returnErr != err {
    69  				t.Errorf("SaveDevice case failed: wanted error %v and got error %v", test.returnErr, err)
    70  			}
    71  		})
    72  	}
    73  }
    74  
    75  // TestDeleteDeviceByID is function to test DeleteDeviceByID
    76  func TestDeleteDeviceByID(t *testing.T) {
    77  	// ormerMock is mocked Ormer implementation
    78  	var ormerMock *beego.MockOrmer
    79  	// querySeterMock is mocked QuerySeter implementation
    80  	var querySeterMock *beego.MockQuerySeter
    81  
    82  	mockCtrl := gomock.NewController(t)
    83  	defer mockCtrl.Finish()
    84  	ormerMock = beego.NewMockOrmer(mockCtrl)
    85  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
    86  	dbm.DBAccess = ormerMock
    87  
    88  	cases := []struct {
    89  		// name is name of the testcase
    90  		name string
    91  		// filterReturn is the return of mock interface querySeterMock's filter function
    92  		filterReturn orm.QuerySeter
    93  		// deleteReturnInt is the first return of mock interface querySeterMock's delete function
    94  		deleteReturnInt int64
    95  		// deleteReturnErr is the second return of mock interface querySeterMocks's delete function also expected error
    96  		deleteReturnErr error
    97  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
    98  		queryTableReturn orm.QuerySeter
    99  	}{{
   100  		// Success Case
   101  		name:             "SuccessCase",
   102  		filterReturn:     querySeterMock,
   103  		deleteReturnInt:  int64(1),
   104  		deleteReturnErr:  nil,
   105  		queryTableReturn: querySeterMock,
   106  	}, {
   107  		// Failure Case
   108  		name:             "FailureCase",
   109  		filterReturn:     querySeterMock,
   110  		deleteReturnInt:  int64(0),
   111  		deleteReturnErr:  errFailedDBOperation,
   112  		queryTableReturn: querySeterMock,
   113  	},
   114  	}
   115  
   116  	// run the test cases
   117  	for _, test := range cases {
   118  		t.Run(test.name, func(t *testing.T) {
   119  			querySeterMock.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1)
   120  			querySeterMock.EXPECT().Delete().Return(test.deleteReturnInt, test.deleteReturnErr).Times(1)
   121  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1)
   122  			err := DeleteDeviceByID("test")
   123  			if test.deleteReturnErr != err {
   124  				t.Errorf("DeleteDeviceByID case failed: wanted %v and got %v", test.deleteReturnErr, err)
   125  			}
   126  		})
   127  	}
   128  }
   129  
   130  // TestUpdateDeviceField is function to test UpdateDeviceField
   131  func TestUpdateDeviceField(t *testing.T) {
   132  	// ormerMock is mocked Ormer implementation
   133  	var ormerMock *beego.MockOrmer
   134  	// querySeterMock is mocked QuerySeter implementation
   135  	var querySeterMock *beego.MockQuerySeter
   136  
   137  	mockCtrl := gomock.NewController(t)
   138  	defer mockCtrl.Finish()
   139  	ormerMock = beego.NewMockOrmer(mockCtrl)
   140  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
   141  	dbm.DBAccess = ormerMock
   142  
   143  	cases := []struct {
   144  		// name is name of the testcase
   145  		name string
   146  		// filterReturn is the return of mock interface querySeterMock's filter function
   147  		filterReturn orm.QuerySeter
   148  		// updateReturnInt is the first return of mock interface querySeterMock's update function
   149  		updateReturnInt int64
   150  		// updateReturnErr is the second return of mock interface querySeterMocks's update function also expected error
   151  		updateReturnErr error
   152  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
   153  		queryTableReturn orm.QuerySeter
   154  	}{{
   155  		// Success Case
   156  		name:             "SuccessCase",
   157  		filterReturn:     querySeterMock,
   158  		updateReturnInt:  int64(1),
   159  		updateReturnErr:  nil,
   160  		queryTableReturn: querySeterMock,
   161  	}, {
   162  		// Failure Case
   163  		name:             "FailureCase",
   164  		filterReturn:     querySeterMock,
   165  		updateReturnInt:  int64(0),
   166  		updateReturnErr:  errFailedDBOperation,
   167  		queryTableReturn: querySeterMock,
   168  	},
   169  	}
   170  
   171  	// run the test cases
   172  	for _, test := range cases {
   173  		t.Run(test.name, func(t *testing.T) {
   174  			querySeterMock.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1)
   175  			querySeterMock.EXPECT().Update(gomock.Any()).Return(test.updateReturnInt, test.updateReturnErr).Times(1)
   176  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1)
   177  			err := UpdateDeviceField("test", "test", "test")
   178  			if test.updateReturnErr != err {
   179  				t.Errorf("UpdateDeviceField case failed: wanted %v and got %v", test.updateReturnErr, err)
   180  			}
   181  		})
   182  	}
   183  }
   184  
   185  // TestUpdateDeviceFields is function to test UpdateDeviceFields
   186  func TestUpdateDeviceFields(t *testing.T) {
   187  	// ormerMock is mocked Ormer implementation
   188  	var ormerMock *beego.MockOrmer
   189  	// querySeterMock is mocked QuerySeter implementation
   190  	var querySeterMock *beego.MockQuerySeter
   191  
   192  	mockCtrl := gomock.NewController(t)
   193  	defer mockCtrl.Finish()
   194  	ormerMock = beego.NewMockOrmer(mockCtrl)
   195  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
   196  	dbm.DBAccess = ormerMock
   197  
   198  	cases := []struct {
   199  		// name is name of the testcase
   200  		name string
   201  		// filterReturn is the return of mock interface querySeterMock's filter function
   202  		filterReturn orm.QuerySeter
   203  		// updateReturnInt is the first return of mock interface querySeterMock's update function
   204  		updateReturnInt int64
   205  		// updateReturnErr is the second return of mock interface querySeterMocks's update function also expected error
   206  		updateReturnErr error
   207  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
   208  		queryTableReturn orm.QuerySeter
   209  	}{{
   210  		// Success Case
   211  		name:             "SuccessCase",
   212  		filterReturn:     querySeterMock,
   213  		updateReturnInt:  int64(1),
   214  		updateReturnErr:  nil,
   215  		queryTableReturn: querySeterMock,
   216  	}, {
   217  		// Failure Case
   218  		name:             "FailureCase",
   219  		filterReturn:     querySeterMock,
   220  		updateReturnInt:  int64(0),
   221  		updateReturnErr:  errFailedDBOperation,
   222  		queryTableReturn: querySeterMock,
   223  	},
   224  	}
   225  
   226  	// run the test cases
   227  	for _, test := range cases {
   228  		t.Run(test.name, func(t *testing.T) {
   229  			querySeterMock.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1)
   230  			querySeterMock.EXPECT().Update(gomock.Any()).Return(test.updateReturnInt, test.updateReturnErr).Times(1)
   231  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1)
   232  			err := UpdateDeviceFields("test", make(map[string]interface{}))
   233  			if test.updateReturnErr != err {
   234  				t.Errorf("UpdateDeviceFields case failed: wanted %v and got %v", test.updateReturnErr, err)
   235  			}
   236  		})
   237  	}
   238  }
   239  
   240  // TestQueryDevice is function to test QueryDevice
   241  func TestQueryDevice(t *testing.T) {
   242  	// ormerMock is mocked Ormer implementation
   243  	var ormerMock *beego.MockOrmer
   244  	// querySeterMock is mocked QuerySeter implementation
   245  	var querySeterMock *beego.MockQuerySeter
   246  
   247  	mockCtrl := gomock.NewController(t)
   248  	defer mockCtrl.Finish()
   249  	ormerMock = beego.NewMockOrmer(mockCtrl)
   250  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
   251  	dbm.DBAccess = ormerMock
   252  
   253  	cases := []struct {
   254  		// name is name of the testcase
   255  		name string
   256  		// filterReturn is the return of mock interface querySeterMock's filter function
   257  		filterReturn orm.QuerySeter
   258  		// allReturnInt is the first return of mock interface querySeterMock's all function
   259  		allReturnInt int64
   260  		// allReturnErr is the second return of mock interface querySeterMocks's all function also expected error
   261  		allReturnErr error
   262  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
   263  		queryTableReturn orm.QuerySeter
   264  	}{{
   265  		// Success Case
   266  		name:             "SuccessCase",
   267  		filterReturn:     querySeterMock,
   268  		allReturnInt:     int64(1),
   269  		allReturnErr:     nil,
   270  		queryTableReturn: querySeterMock,
   271  	}, {
   272  		// Failure Case
   273  		name:             "FailureCase",
   274  		filterReturn:     querySeterMock,
   275  		allReturnInt:     int64(0),
   276  		allReturnErr:     errFailedDBOperation,
   277  		queryTableReturn: querySeterMock,
   278  	},
   279  	}
   280  
   281  	// fakeDevice is used to set the argument of All function
   282  	fakeDevice := new([]Device)
   283  	fakeDeviceArray := make([]Device, 1)
   284  	fakeDeviceArray[0] = Device{ID: "Test"}
   285  	fakeDevice = &fakeDeviceArray
   286  
   287  	// run the test cases
   288  	for _, test := range cases {
   289  		t.Run(test.name, func(t *testing.T) {
   290  			querySeterMock.EXPECT().All(gomock.Any()).SetArg(0, *fakeDevice).Return(test.allReturnInt, test.allReturnErr).Times(1)
   291  			querySeterMock.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1)
   292  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1)
   293  			device, err := QueryDevice("test", "test")
   294  			if test.allReturnErr != err {
   295  				t.Errorf("QueryDevice case failed: wanted error %v and got error %v", test.allReturnErr, err)
   296  				return
   297  			}
   298  
   299  			if err == nil {
   300  				if len(*device) != 1 {
   301  					t.Errorf("QueryDevice case failed: wanted length 1 and got length %v", len(*device))
   302  				}
   303  			}
   304  		})
   305  	}
   306  }
   307  
   308  // TestQueryDeviceAll is function to test QueryDeviceAll
   309  func TestQueryDeviceAll(t *testing.T) {
   310  	// ormerMock is mocked Ormer implementation
   311  	var ormerMock *beego.MockOrmer
   312  	// querySeterMock is mocked QuerySeter implementation
   313  	var querySeterMock *beego.MockQuerySeter
   314  
   315  	mockCtrl := gomock.NewController(t)
   316  	defer mockCtrl.Finish()
   317  	ormerMock = beego.NewMockOrmer(mockCtrl)
   318  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
   319  	dbm.DBAccess = ormerMock
   320  
   321  	cases := []struct {
   322  		// name is name of the testcase
   323  		name string
   324  		// filterReturn is the return of mock interface querySeterMock's filter function
   325  		filterReturn orm.QuerySeter
   326  		// allReturnInt is the first return of mock interface querySeterMock's all function
   327  		allReturnInt int64
   328  		// allReturnErr is the second return of mock interface querySeterMocks's all function also expected error
   329  		allReturnErr error
   330  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
   331  		queryTableReturn orm.QuerySeter
   332  	}{{
   333  		// Success Case
   334  		name:             "SuccessCase",
   335  		filterReturn:     querySeterMock,
   336  		allReturnInt:     int64(1),
   337  		allReturnErr:     nil,
   338  		queryTableReturn: querySeterMock,
   339  	}, {
   340  		// Failure Case
   341  		name:             "FailureCase",
   342  		filterReturn:     querySeterMock,
   343  		allReturnInt:     int64(0),
   344  		allReturnErr:     errFailedDBOperation,
   345  		queryTableReturn: querySeterMock,
   346  	},
   347  	}
   348  
   349  	// fakeDevice is used to set the argument of All function
   350  	fakeDevice := new([]Device)
   351  	fakeDeviceArray := make([]Device, 1)
   352  	fakeDeviceArray[0] = Device{ID: "Test"}
   353  	fakeDevice = &fakeDeviceArray
   354  
   355  	// run the test cases
   356  	for _, test := range cases {
   357  		t.Run(test.name, func(t *testing.T) {
   358  			querySeterMock.EXPECT().All(gomock.Any()).SetArg(0, *fakeDevice).Return(test.allReturnInt, test.allReturnErr).Times(1)
   359  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1)
   360  			device, err := QueryDeviceAll()
   361  			if test.allReturnErr != err {
   362  				t.Errorf("QueryDeviceAll case failed: wanted error %v and got error %v", test.allReturnErr, err)
   363  				return
   364  			}
   365  
   366  			if err == nil {
   367  				if len(*device) != 1 {
   368  					t.Errorf("QueryDeviceAll case failed: wanted length 1 and got length %v", len(*device))
   369  				}
   370  			}
   371  		})
   372  	}
   373  }
   374  
   375  // TestUpdateDeviceMulti is function to test UpdateDeviceMulti
   376  func TestUpdateDeviceMulti(t *testing.T) {
   377  	// ormerMock is mocked Ormer implementation
   378  	var ormerMock *beego.MockOrmer
   379  	// querySeterMock is mocked QuerySeter implementation
   380  	var querySeterMock *beego.MockQuerySeter
   381  
   382  	mockCtrl := gomock.NewController(t)
   383  	defer mockCtrl.Finish()
   384  	ormerMock = beego.NewMockOrmer(mockCtrl)
   385  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
   386  	dbm.DBAccess = ormerMock
   387  
   388  	cases := []struct {
   389  		// name is name of the testcase
   390  		name string
   391  		// filterReturn is the return of mock interface querySeterMock's filter function
   392  		filterReturn orm.QuerySeter
   393  		// updateReturnInt is the first return of mock interface querySeterMock's update function
   394  		updateReturnInt int64
   395  		// updateReturnErr is the second return of mock interface querySeterMocks's update function also expected error
   396  		updateReturnErr error
   397  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
   398  		queryTableReturn orm.QuerySeter
   399  	}{{
   400  		// Success Case
   401  		name:             "SuccessCase",
   402  		filterReturn:     querySeterMock,
   403  		updateReturnInt:  int64(1),
   404  		updateReturnErr:  nil,
   405  		queryTableReturn: querySeterMock,
   406  	}, {
   407  		// Failure Case
   408  		name:             "FailureCase",
   409  		filterReturn:     querySeterMock,
   410  		updateReturnInt:  int64(0),
   411  		updateReturnErr:  errFailedDBOperation,
   412  		queryTableReturn: querySeterMock,
   413  	},
   414  	}
   415  
   416  	// updateDevice is argument to UpdateDeviceMulti function
   417  	updateDevice := make([]DeviceUpdate, 0)
   418  	updateDevice = append(updateDevice, DeviceUpdate{DeviceID: "test"})
   419  
   420  	// run the test cases
   421  	for _, test := range cases {
   422  		t.Run(test.name, func(t *testing.T) {
   423  			querySeterMock.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1)
   424  			querySeterMock.EXPECT().Update(gomock.Any()).Return(test.updateReturnInt, test.updateReturnErr).Times(1)
   425  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1)
   426  			err := UpdateDeviceMulti(updateDevice)
   427  			if test.updateReturnErr != err {
   428  				t.Errorf("UpdateDeviceMulti case failed: wanted %v and got %v", test.updateReturnErr, err)
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  // TestAddDeviceTrans is function to test AddDeviceTrans
   435  func TestAddDeviceTrans(t *testing.T) {
   436  	// ormerMock is mocked Ormer implementation
   437  	var ormerMock *beego.MockOrmer
   438  
   439  	mockCtrl := gomock.NewController(t)
   440  	defer mockCtrl.Finish()
   441  	ormerMock = beego.NewMockOrmer(mockCtrl)
   442  	dbm.DBAccess = ormerMock
   443  
   444  	cases := []struct {
   445  		// name is name of the testcase
   446  		name string
   447  		// rollBackTimes is number of times rollback is expected
   448  		rollBackTimes int
   449  		// commitTimes is number of times commit is expected
   450  		commitTimes int
   451  		// beginTimes is number of times begin is expected
   452  		beginTimes int
   453  		// successInsertReturnInt is the first return of mock interface ormerMock's Insert function success case
   454  		successInsertReturnInt int64
   455  		// successInsertReturnErr is the second return of mock interface ormerMock's Insert function success case
   456  		successInsertReturnErr error
   457  		// successInsertTimes is number of times successful insert is expected
   458  		successInsertTimes int
   459  		// failInsertReturnInt is the first return of mock interface ormerMock's Insert function error case
   460  		failInsertReturnInt int64
   461  		// failInsertReturnErr is the second return of mock interface ormerMock's Insert function error case
   462  		failInsertReturnErr error
   463  		// failInsertTimes is number of times fail insert is expected
   464  		failInsertTimes int
   465  		// wantErr is expected error
   466  		wantErr error
   467  	}{{
   468  		// Failure Case SaveDevice
   469  		name:                   "FailureCaseSaveDevice",
   470  		rollBackTimes:          1,
   471  		commitTimes:            0,
   472  		beginTimes:             1,
   473  		successInsertReturnInt: int64(1),
   474  		successInsertReturnErr: nil,
   475  		successInsertTimes:     0,
   476  		failInsertReturnInt:    int64(1),
   477  		failInsertReturnErr:    errFailedDBOperation,
   478  		failInsertTimes:        1,
   479  		wantErr:                errFailedDBOperation,
   480  	}, {
   481  		// Failure Case SaveDeviceAttr
   482  		name:                   "FailureCaseSaveDeviceAttr",
   483  		rollBackTimes:          1,
   484  		commitTimes:            0,
   485  		beginTimes:             1,
   486  		successInsertReturnInt: int64(1),
   487  		successInsertReturnErr: nil,
   488  		successInsertTimes:     1,
   489  		failInsertReturnInt:    int64(1),
   490  		failInsertReturnErr:    errFailedDBOperation,
   491  		failInsertTimes:        1,
   492  		wantErr:                errFailedDBOperation,
   493  	}, {
   494  		// Failure Case SaveDeviceTwin
   495  		name:                   "FailureCaseSaveDeviceAttr",
   496  		rollBackTimes:          1,
   497  		commitTimes:            0,
   498  		beginTimes:             1,
   499  		successInsertReturnInt: int64(1),
   500  		successInsertReturnErr: nil,
   501  		successInsertTimes:     2,
   502  		failInsertReturnInt:    int64(1),
   503  		failInsertReturnErr:    errFailedDBOperation,
   504  		failInsertTimes:        1,
   505  		wantErr:                errFailedDBOperation,
   506  	}, {
   507  		// Success Case SaveDeviceTwin
   508  		name:                   "SuccessCaseSaveDeviceAttr",
   509  		rollBackTimes:          0,
   510  		commitTimes:            1,
   511  		beginTimes:             1,
   512  		successInsertReturnInt: int64(1),
   513  		successInsertReturnErr: nil,
   514  		successInsertTimes:     3,
   515  		failInsertReturnInt:    int64(1),
   516  		failInsertReturnErr:    errFailedDBOperation,
   517  		failInsertTimes:        0,
   518  		wantErr:                nil,
   519  	},
   520  	}
   521  
   522  	// adds is fake Device used as argument
   523  	adds := make([]Device, 0)
   524  	adds = append(adds, Device{ID: "test"})
   525  	// addAttrs is fake DeviceAttr used as argument
   526  	addAttrs := make([]DeviceAttr, 0)
   527  	addAttrs = append(addAttrs, DeviceAttr{DeviceID: "test"})
   528  	// addTwins is fake DeviceTwin used as argument
   529  	addTwins := make([]DeviceTwin, 0)
   530  	addTwins = append(addTwins, DeviceTwin{DeviceID: "test"})
   531  
   532  	// run the test cases
   533  	for _, test := range cases {
   534  		t.Run(test.name, func(t *testing.T) {
   535  			ormerMock.EXPECT().Begin().Return(nil).Times(test.beginTimes)
   536  			// success insert
   537  			ormerMock.EXPECT().Insert(gomock.Any()).Return(test.successInsertReturnInt, test.successInsertReturnErr).Times(test.successInsertTimes)
   538  			// fail insert
   539  			ormerMock.EXPECT().Insert(gomock.Any()).Return(test.failInsertReturnInt, test.failInsertReturnErr).Times(test.failInsertTimes)
   540  			ormerMock.EXPECT().Commit().Return(nil).Times(test.commitTimes)
   541  			ormerMock.EXPECT().Rollback().Return(nil).Times(test.rollBackTimes)
   542  			err := AddDeviceTrans(adds, addAttrs, addTwins)
   543  			if test.wantErr != err {
   544  				t.Errorf("AddDeviceTrans case failed: wanted error %v and got error %v", test.wantErr, err)
   545  			}
   546  		})
   547  	}
   548  }
   549  
   550  // TestDeleteDeviceTrans is function to test DeleteDeviceTrans
   551  func TestDeleteDeviceTrans(t *testing.T) {
   552  	// ormerMock is mocked Ormer implementation
   553  	var ormerMock *beego.MockOrmer
   554  	// querySeterMock is mocked QuerySeter implementation
   555  	var querySeterMock *beego.MockQuerySeter
   556  
   557  	mockCtrl := gomock.NewController(t)
   558  	defer mockCtrl.Finish()
   559  	ormerMock = beego.NewMockOrmer(mockCtrl)
   560  	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
   561  	dbm.DBAccess = ormerMock
   562  
   563  	cases := []struct {
   564  		// name is name of the testcase
   565  		name string
   566  		// rollBackTimes is number of times rollback is expected
   567  		rollBackTimes int
   568  		// commitTimes is number of times commit is expected
   569  		commitTimes int
   570  		// beginTimes is number of times begin is expected
   571  		beginTimes int
   572  		// successDeleteReturnInt is the first return of mock interface ormerMock's delete function success case
   573  		successDeleteReturnInt int64
   574  		// successDeleteReturnErr is the second return of mock interface ormerMock's delete function success case
   575  		successDeleteReturnErr error
   576  		// successDeleteTimes is number of times successful delete is expected
   577  		successDeleteTimes int
   578  		// failDeleteReturnInt is the first return of mock interface ormerMock's delete function error case
   579  		failDeleteReturnInt int64
   580  		// failDeleteReturnErr is the second return of mock interface ormerMock's delete function error case
   581  		failDeleteReturnErr error
   582  		// failDeleteTimes is number of times fail Delete is expected
   583  		failDeleteTimes int
   584  		// queryTableReturn is the return of mock interface ormerMock's QueryTable function
   585  		queryTableReturn orm.QuerySeter
   586  		// queryTableTimes is the number of times queryTable is called
   587  		queryTableTimes int
   588  		// filterReturn is the return of mock interface querySeterMock's filter function
   589  		filterReturn orm.QuerySeter
   590  		// filterTimes is the number of times filter is called
   591  		filterTimes int
   592  		// wantErr is expected error
   593  		wantErr error
   594  	}{{
   595  		// Failure Case DeleteDeviceByID
   596  		name:                   "FailureCaseDeleteDeviceByID",
   597  		rollBackTimes:          1,
   598  		commitTimes:            0,
   599  		beginTimes:             1,
   600  		successDeleteReturnInt: int64(1),
   601  		successDeleteReturnErr: nil,
   602  		successDeleteTimes:     0,
   603  		failDeleteReturnInt:    int64(1),
   604  		failDeleteReturnErr:    errFailedDBOperation,
   605  		failDeleteTimes:        1,
   606  		queryTableReturn:       querySeterMock,
   607  		queryTableTimes:        1,
   608  		filterReturn:           querySeterMock,
   609  		filterTimes:            1,
   610  		wantErr:                errFailedDBOperation,
   611  	}, {
   612  		// Failure Case DeleteDeviceAttrByDeviceID
   613  		name:                   "FailureCaseDeleteDeviceAttrByDeviceID",
   614  		rollBackTimes:          1,
   615  		commitTimes:            0,
   616  		beginTimes:             1,
   617  		successDeleteReturnInt: int64(1),
   618  		successDeleteReturnErr: nil,
   619  		successDeleteTimes:     1,
   620  		failDeleteReturnInt:    int64(1),
   621  		failDeleteReturnErr:    errFailedDBOperation,
   622  		failDeleteTimes:        1,
   623  		queryTableReturn:       querySeterMock,
   624  		queryTableTimes:        2,
   625  		filterReturn:           querySeterMock,
   626  		filterTimes:            2,
   627  		wantErr:                errFailedDBOperation,
   628  	}, {
   629  		// Failure Case DeleteDeviceTwinByDeviceID
   630  		name:                   "FailureCaseDeleteDeviceTwinByDeviceID",
   631  		rollBackTimes:          1,
   632  		commitTimes:            0,
   633  		beginTimes:             1,
   634  		successDeleteReturnInt: int64(1),
   635  		successDeleteReturnErr: nil,
   636  		successDeleteTimes:     2,
   637  		failDeleteReturnInt:    int64(1),
   638  		failDeleteReturnErr:    errFailedDBOperation,
   639  		failDeleteTimes:        1,
   640  		queryTableReturn:       querySeterMock,
   641  		queryTableTimes:        3,
   642  		filterReturn:           querySeterMock,
   643  		filterTimes:            3,
   644  		wantErr:                errFailedDBOperation,
   645  	}, {
   646  		// Success Case
   647  		name:                   "SuccessCase",
   648  		rollBackTimes:          0,
   649  		commitTimes:            1,
   650  		beginTimes:             1,
   651  		successDeleteReturnInt: int64(1),
   652  		successDeleteReturnErr: nil,
   653  		successDeleteTimes:     3,
   654  		failDeleteReturnInt:    int64(1),
   655  		failDeleteReturnErr:    errFailedDBOperation,
   656  		failDeleteTimes:        0,
   657  		queryTableReturn:       querySeterMock,
   658  		queryTableTimes:        3,
   659  		filterReturn:           querySeterMock,
   660  		filterTimes:            3,
   661  		wantErr:                nil,
   662  	},
   663  	}
   664  
   665  	// deletes is argument to DeleteDeviceTrans function
   666  	deletes := []string{"test"}
   667  
   668  	// run the test cases
   669  	for _, test := range cases {
   670  		t.Run(test.name, func(t *testing.T) {
   671  			ormerMock.EXPECT().Begin().Return(nil).Times(test.beginTimes)
   672  			ormerMock.EXPECT().Rollback().Return(nil).Times(test.rollBackTimes)
   673  			ormerMock.EXPECT().Commit().Return(nil).Times(test.commitTimes)
   674  			querySeterMock.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(test.filterTimes)
   675  			ormerMock.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(test.queryTableTimes)
   676  			// success delete
   677  			querySeterMock.EXPECT().Delete().Return(test.successDeleteReturnInt, test.successDeleteReturnErr).Times(test.successDeleteTimes)
   678  			// fail delete
   679  			querySeterMock.EXPECT().Delete().Return(test.failDeleteReturnInt, test.failDeleteReturnErr).Times(test.failDeleteTimes)
   680  			err := DeleteDeviceTrans(deletes)
   681  			if test.wantErr != err {
   682  				t.Errorf("DeleteDeviceTrans Case failed : wanted %v and got %v", test.wantErr, err)
   683  			}
   684  		})
   685  	}
   686  }