github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/dtmanager/twin_test.go (about) 1 /* 2 Copyright 2019 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 dtmanager 18 19 import ( 20 "encoding/json" 21 "errors" 22 "reflect" 23 "sync" 24 "testing" 25 "time" 26 27 "github.com/astaxie/beego/orm" 28 "github.com/golang/mock/gomock" 29 "k8s.io/klog" 30 31 "github.com/kubeedge/beehive/pkg/core/model" 32 "github.com/kubeedge/kubeedge/edge/mocks/beego" 33 "github.com/kubeedge/kubeedge/edge/pkg/common/dbm" 34 "github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtclient" 35 "github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon" 36 "github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcontext" 37 "github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype" 38 ) 39 40 var ( 41 deviceA = "DeviceA" 42 deviceB = "DeviceB" 43 deviceC = "DeviceC" 44 event1 = "Event1" 45 key1 = "key1" 46 47 typeDeleted = "deleted" 48 typeInt = "int" 49 typeString = "string" 50 ) 51 52 // sendMsg sends message to receiverChannel and heartbeatChannel 53 func (tw TwinWorker) sendMsg(msg *dttype.DTMessage, msgHeart string, actionType string, contentType interface{}) { 54 if tw.ReceiverChan != nil { 55 msg.Action = actionType 56 msg.Msg.Content = contentType 57 tw.ReceiverChan <- msg 58 } 59 if tw.HeartBeatChan != nil { 60 tw.HeartBeatChan <- msgHeart 61 } 62 } 63 64 // receiveMsg receives message from the commChannel 65 func receiveMsg(commChannel chan interface{}, message *dttype.DTMessage) { 66 msg, ok := <-commChannel 67 if !ok { 68 klog.Errorf("No message received from communication channel") 69 return 70 } 71 *message = *msg.(*dttype.DTMessage) 72 } 73 74 // twinValueFunc returns a new TwinValue 75 func twinValueFunc() *dttype.TwinValue { 76 var twinValue dttype.TwinValue 77 value := "value" 78 valueMetaData := &dttype.ValueMetadata{Timestamp: time.Now().UnixNano() / 1e6} 79 twinValue.Value = &value 80 twinValue.Metadata = valueMetaData 81 return &twinValue 82 } 83 84 // keyTwinUpdateFunc returns a new DeviceTwinUpdate 85 func keyTwinUpdateFunc() dttype.DeviceTwinUpdate { 86 var keyTwinUpdate dttype.DeviceTwinUpdate 87 twinKey := make(map[string]*dttype.MsgTwin) 88 twinKey[key1] = &dttype.MsgTwin{ 89 Expected: twinValueFunc(), 90 Actual: twinValueFunc(), 91 Metadata: &dttype.TypeMetadata{Type: "nil"}, 92 } 93 keyTwinUpdate.Twin = twinKey 94 keyTwinUpdate.BaseMessage = dttype.BaseMessage{EventID: event1} 95 return keyTwinUpdate 96 } 97 98 // twinWorkerFunc returns a new TwinWorker 99 func twinWorkerFunc(receiverChannel chan interface{}, confirmChannel chan interface{}, heartBeatChannel chan interface{}, context dtcontext.DTContext, group string) TwinWorker { 100 return TwinWorker{ 101 Worker{ 102 receiverChannel, 103 confirmChannel, 104 heartBeatChannel, 105 &context, 106 }, 107 group, 108 } 109 } 110 111 // contextFunc returns a new DTContext 112 func contextFunc(deviceID string) dtcontext.DTContext { 113 context := dtcontext.DTContext{ 114 DeviceList: &sync.Map{}, 115 DeviceMutex: &sync.Map{}, 116 Mutex: &sync.RWMutex{}, 117 } 118 var testMutex sync.Mutex 119 context.DeviceMutex.Store(deviceID, &testMutex) 120 var device dttype.Device 121 context.DeviceList.Store(deviceID, &device) 122 return context 123 } 124 125 // msgTypeFunc returns a new Message 126 func msgTypeFunc(content interface{}) *model.Message { 127 return &model.Message{ 128 Content: content, 129 } 130 } 131 132 // TestStart is function to test Start 133 func TestStart(t *testing.T) { 134 keyTwinUpdate := keyTwinUpdateFunc() 135 contentKeyTwin, _ := json.Marshal(keyTwinUpdate) 136 137 commChan := make(map[string]chan interface{}) 138 commChannel := make(chan interface{}) 139 commChan[dtcommon.CommModule] = commChannel 140 141 context := dtcontext.DTContext{ 142 DeviceList: &sync.Map{}, 143 DeviceMutex: &sync.Map{}, 144 Mutex: &sync.RWMutex{}, 145 CommChan: commChan, 146 ModulesHealth: &sync.Map{}, 147 } 148 var testMutex sync.Mutex 149 context.DeviceMutex.Store(deviceB, &testMutex) 150 msgAttr := make(map[string]*dttype.MsgAttr) 151 device := dttype.Device{ 152 ID: "id1", 153 Name: deviceB, 154 Attributes: msgAttr, 155 Twin: keyTwinUpdate.Twin, 156 } 157 context.DeviceList.Store(deviceB, &device) 158 159 msg := &dttype.DTMessage{ 160 Msg: &model.Message{ 161 Header: model.MessageHeader{ 162 ID: "id1", 163 ParentID: "pid1", 164 Timestamp: 0, 165 Sync: false, 166 }, 167 Router: model.MessageRoute{ 168 Source: "source", 169 Resource: "resource", 170 Group: "group", 171 Operation: "op", 172 }, 173 Content: contentKeyTwin, 174 }, 175 Action: dtcommon.TwinGet, 176 Type: dtcommon.CommModule, 177 } 178 msgHeartPing := "ping" 179 msgHeartStop := "stop" 180 receiverChannel := make(chan interface{}) 181 heartbeatChannel := make(chan interface{}) 182 183 tests := []struct { 184 name string 185 tw TwinWorker 186 actionType string 187 contentType interface{} 188 msgType string 189 }{ 190 { 191 name: "TestStart(): Case 1: ReceiverChan case when error is nil", 192 tw: twinWorkerFunc(receiverChannel, nil, nil, context, ""), 193 actionType: dtcommon.TwinGet, 194 contentType: contentKeyTwin, 195 }, 196 { 197 name: "TestStart(): Case 2: ReceiverChan case error log; TwinModule deal event failed, not found callback", 198 tw: twinWorkerFunc(receiverChannel, nil, nil, context, ""), 199 actionType: dtcommon.SendToEdge, 200 contentType: contentKeyTwin, 201 }, 202 { 203 name: "TestStart(): Case 3: ReceiverChan case error log; TwinModule deal event failed", 204 tw: twinWorkerFunc(receiverChannel, nil, nil, context, ""), 205 actionType: dtcommon.TwinGet, 206 }, 207 { 208 name: "TestStart(): Case 4: HeartBeatChan case when error is nil", 209 tw: twinWorkerFunc(nil, nil, heartbeatChannel, context, "Group1"), 210 msgType: msgHeartPing, 211 }, 212 { 213 name: "TestStart(): Case 5: HeartBeatChan case when error is not nil", 214 tw: twinWorkerFunc(nil, nil, heartbeatChannel, context, "Group1"), 215 msgType: msgHeartStop, 216 }, 217 } 218 for _, test := range tests { 219 t.Run(test.name, func(t *testing.T) { 220 go test.tw.sendMsg(msg, test.msgType, test.actionType, test.contentType) 221 go test.tw.Start() 222 time.Sleep(100 * time.Millisecond) 223 message := &dttype.DTMessage{} 224 go receiveMsg(commChannel, message) 225 time.Sleep(100 * time.Millisecond) 226 if (test.tw.ReceiverChan != nil) && !reflect.DeepEqual(message.Identity, msg.Identity) && !reflect.DeepEqual(message.Type, msg.Type) { 227 t.Errorf("DTManager.TestStart() case failed: got = %v, Want = %v", message, msg) 228 } 229 if _, exist := context.ModulesHealth.Load("Group1"); test.tw.HeartBeatChan != nil && !exist { 230 t.Errorf("DTManager.TestStart() case failed: HeartBeatChan received no string") 231 } 232 }) 233 } 234 } 235 236 // TestDealTwinSync is function to test dealTwinSync 237 func TestDealTwinSync(t *testing.T) { 238 content, _ := json.Marshal(dttype.DeviceTwinUpdate{BaseMessage: dttype.BaseMessage{EventID: event1}}) 239 contentKeyTwin, _ := json.Marshal(keyTwinUpdateFunc()) 240 context := contextFunc(deviceB) 241 242 tests := []struct { 243 name string 244 context *dtcontext.DTContext 245 resource string 246 msg interface{} 247 err error 248 }{ 249 { 250 name: "TestDealTwinSync(): Case 1: msg not Message type", 251 context: &dtcontext.DTContext{}, 252 msg: model.Message{ 253 Content: dttype.BaseMessage{EventID: event1}, 254 }, 255 err: errors.New("msg not Message type"), 256 }, 257 { 258 name: "TestDealTwinSync(): Case 2: invalid message content", 259 context: &dtcontext.DTContext{}, 260 msg: msgTypeFunc(dttype.BaseMessage{EventID: event1}), 261 err: errors.New("invalid message content"), 262 }, 263 { 264 name: "TestDealTwinSync(): Case 3: Unmarshal update request body failed", 265 context: &dtcontext.DTContext{}, 266 msg: msgTypeFunc(content), 267 err: errors.New("Update twin error, the update request body not have key:twin"), 268 }, 269 { 270 name: "TestDealTwinSync(): Case 4: Success case", 271 context: &context, 272 resource: deviceB, 273 msg: msgTypeFunc(contentKeyTwin), 274 err: nil, 275 }, 276 } 277 for _, test := range tests { 278 t.Run(test.name, func(t *testing.T) { 279 if _, err := dealTwinSync(test.context, test.resource, test.msg); !reflect.DeepEqual(err, test.err) { 280 t.Errorf("DTManager.TestDealTwinSync() case failed: got = %v, Want = %v", err, test.err) 281 } 282 }) 283 } 284 } 285 286 // TestDealTwinGet is function to test dealTwinGet 287 func TestDealTwinGet(t *testing.T) { 288 contentKeyTwin, _ := json.Marshal(keyTwinUpdateFunc()) 289 context := contextFunc(deviceB) 290 291 tests := []struct { 292 name string 293 context *dtcontext.DTContext 294 resource string 295 msg interface{} 296 err error 297 }{ 298 { 299 name: "TestDealTwinGet(): Case 1: msg not Message type", 300 context: &dtcontext.DTContext{}, 301 msg: model.Message{ 302 Content: dttype.BaseMessage{EventID: event1}, 303 }, 304 err: errors.New("msg not Message type"), 305 }, 306 { 307 name: "TestDealTwinGet(): Case 2: invalid message content", 308 context: &dtcontext.DTContext{}, 309 msg: msgTypeFunc(dttype.BaseMessage{EventID: event1}), 310 err: errors.New("invalid message content"), 311 }, 312 { 313 name: "TestDealTwinGet(): Case 3: Success; Unmarshal twin info fails in DealGetTwin()", 314 context: &context, 315 resource: deviceB, 316 msg: msgTypeFunc([]byte("")), 317 err: nil, 318 }, 319 { 320 name: "TestDealTwinGet(): Case 4: Success; Device not found while getting twin in DealGetTwin()", 321 context: &context, 322 resource: deviceB, 323 msg: msgTypeFunc(contentKeyTwin), 324 err: nil, 325 }, 326 } 327 for _, test := range tests { 328 t.Run(test.name, func(t *testing.T) { 329 if _, err := dealTwinGet(test.context, test.resource, test.msg); !reflect.DeepEqual(err, test.err) { 330 t.Errorf("DTManager.TestDealTwinGet() case failed: got = %v, Want = %v", err, test.err) 331 } 332 }) 333 } 334 } 335 336 // TestDealTwinUpdate is function to test dealTwinUpdate 337 func TestDealTwinUpdate(t *testing.T) { 338 content, _ := json.Marshal(dttype.DeviceTwinUpdate{BaseMessage: dttype.BaseMessage{EventID: event1}}) 339 contentKeyTwin, _ := json.Marshal(keyTwinUpdateFunc()) 340 context := contextFunc(deviceB) 341 342 tests := []struct { 343 name string 344 context *dtcontext.DTContext 345 resource string 346 msg interface{} 347 err error 348 }{ 349 { 350 name: "TestDealTwinUpdate(): Case 1: msg not Message type", 351 context: &dtcontext.DTContext{}, 352 msg: model.Message{ 353 Content: dttype.BaseMessage{EventID: event1}, 354 }, 355 err: errors.New("msg not Message type"), 356 }, 357 { 358 name: "TestDealTwinUpdate(): Case 2: invalid message content", 359 context: &dtcontext.DTContext{}, 360 msg: msgTypeFunc(dttype.BaseMessage{EventID: event1}), 361 err: errors.New("invalid message content"), 362 }, 363 { 364 name: "TestDealTwinUpdate(): Case 3: Success; Unmarshal update request body fails in Updated()", 365 context: &context, 366 resource: deviceB, 367 msg: msgTypeFunc(content), 368 err: nil, 369 }, 370 { 371 name: "TestDealTwinUpdate(): Case 4: Success; Begin to update twin of the device in Updated()", 372 context: &context, 373 resource: deviceA, 374 msg: msgTypeFunc(contentKeyTwin), 375 err: nil, 376 }, 377 } 378 for _, test := range tests { 379 t.Run(test.name, func(t *testing.T) { 380 if _, err := dealTwinUpdate(test.context, test.resource, test.msg); !reflect.DeepEqual(err, test.err) { 381 t.Errorf("DTManager.TestDealTwinUpdate() case failed: got = %v, Want = %v", err, test.err) 382 } 383 }) 384 } 385 } 386 387 // TestDealDeviceTwin is function to test DealDeviceTwin 388 func TestDealDeviceTwin(t *testing.T) { 389 var mockOrmer *beego.MockOrmer 390 var mockQuerySeter *beego.MockQuerySeter 391 mockCtrl := gomock.NewController(t) 392 defer mockCtrl.Finish() 393 mockOrmer = beego.NewMockOrmer(mockCtrl) 394 mockQuerySeter = beego.NewMockQuerySeter(mockCtrl) 395 dbm.DBAccess = mockOrmer 396 397 str := typeString 398 optionTrue := true 399 msgTwin := make(map[string]*dttype.MsgTwin) 400 msgTwin[key1] = &dttype.MsgTwin{ 401 Expected: twinValueFunc(), 402 Metadata: &dttype.TypeMetadata{ 403 Type: typeDeleted, 404 }, 405 } 406 contextDeviceB := contextFunc(deviceB) 407 twinDeviceB := make(map[string]*dttype.MsgTwin) 408 twinDeviceB[deviceB] = &dttype.MsgTwin{ 409 Expected: &dttype.TwinValue{ 410 Value: &str, 411 }, 412 Optional: &optionTrue, 413 } 414 deviceBTwin := dttype.Device{ 415 Twin: twinDeviceB, 416 } 417 contextDeviceB.DeviceList.Store(deviceB, &deviceBTwin) 418 419 contextDeviceC := dtcontext.DTContext{ 420 DeviceList: &sync.Map{}, 421 DeviceMutex: &sync.Map{}, 422 Mutex: &sync.RWMutex{}, 423 } 424 var testMutex sync.Mutex 425 contextDeviceC.DeviceMutex.Store(deviceC, &testMutex) 426 twinDeviceC := make(map[string]*dttype.MsgTwin) 427 428 twinDeviceC[deviceC] = &dttype.MsgTwin{ 429 Expected: &dttype.TwinValue{ 430 Value: &str, 431 }, 432 Optional: &optionTrue, 433 } 434 deviceCTwin := dttype.Device{Twin: twinDeviceC} 435 contextDeviceC.DeviceList.Store(deviceC, &deviceCTwin) 436 437 tests := []struct { 438 name string 439 context *dtcontext.DTContext 440 deviceID string 441 eventID string 442 msgTwin map[string]*dttype.MsgTwin 443 dealType int 444 err error 445 filterReturn orm.QuerySeter 446 allReturnInt int64 447 allReturnErr error 448 queryTableReturn orm.QuerySeter 449 450 rollbackNums int 451 beginNums int 452 commitNums int 453 filterNums int 454 insertNums int 455 deleteNums int 456 updateNums int 457 queryNums int 458 }{ 459 { 460 name: "TestDealDeviceTwin(): Case 1: msgTwin is nil", 461 context: &contextDeviceB, 462 deviceID: deviceB, 463 dealType: RestDealType, 464 err: errors.New("Update twin error, the update request body not have key:twin"), 465 rollbackNums: 0, 466 beginNums: 1, 467 commitNums: 1, 468 filterNums: 0, 469 insertNums: 1, 470 deleteNums: 0, 471 updateNums: 0, 472 queryNums: 0, 473 }, 474 { 475 name: "TestDealDeviceTwin(): Case 2: Success Case", 476 context: &contextDeviceC, 477 deviceID: deviceC, 478 msgTwin: msgTwin, 479 dealType: RestDealType, 480 err: nil, 481 filterReturn: mockQuerySeter, 482 allReturnInt: int64(1), 483 allReturnErr: nil, 484 queryTableReturn: mockQuerySeter, 485 rollbackNums: 0, 486 beginNums: 1, 487 commitNums: 1, 488 filterNums: 0, 489 insertNums: 1, 490 deleteNums: 0, 491 updateNums: 0, 492 queryNums: 0, 493 }, 494 } 495 496 for _, test := range tests { 497 t.Run(test.name, func(t *testing.T) { 498 mockOrmer.EXPECT().Rollback().Return(nil).Times(test.rollbackNums) 499 mockOrmer.EXPECT().Begin().Return(nil).MaxTimes(test.beginNums) 500 mockOrmer.EXPECT().Commit().Return(nil).MaxTimes(test.commitNums) 501 mockOrmer.EXPECT().Insert(gomock.Any()).Return(test.allReturnInt, test.allReturnErr).MaxTimes(test.insertNums) 502 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(test.filterNums) 503 mockQuerySeter.EXPECT().Delete().Return(test.allReturnInt, test.allReturnErr).Times(test.deleteNums) 504 mockQuerySeter.EXPECT().Update(gomock.Any()).Return(test.allReturnInt, test.allReturnErr).Times(test.updateNums) 505 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(test.queryNums) 506 if err := DealDeviceTwin(test.context, test.deviceID, test.eventID, test.msgTwin, test.dealType); !reflect.DeepEqual(err, test.err) { 507 t.Errorf("DTManager.TestDealDeviceTwin() case failed: got = %v, Want = %v", err, test.err) 508 } 509 }) 510 } 511 } 512 513 // TestDealDeviceTwinResult is function to test DealDeviceTwin when dealTwinResult.Err is not nil 514 func TestDealDeviceTwinResult(t *testing.T) { 515 var mockOrmer *beego.MockOrmer 516 var mockQuerySeter *beego.MockQuerySeter 517 mockCtrl := gomock.NewController(t) 518 defer mockCtrl.Finish() 519 mockOrmer = beego.NewMockOrmer(mockCtrl) 520 mockQuerySeter = beego.NewMockQuerySeter(mockCtrl) 521 dbm.DBAccess = mockOrmer 522 523 str := typeString 524 optionTrue := true 525 value := "value" 526 msgTwinValue := make(map[string]*dttype.MsgTwin) 527 msgTwinValue[deviceB] = &dttype.MsgTwin{ 528 Expected: &dttype.TwinValue{Value: &value}, 529 Metadata: &dttype.TypeMetadata{Type: "nil"}, 530 } 531 contextDeviceA := contextFunc(deviceB) 532 twinDeviceA := make(map[string]*dttype.MsgTwin) 533 twinDeviceA[deviceA] = &dttype.MsgTwin{ 534 Expected: &dttype.TwinValue{Value: &str}, 535 Actual: &dttype.TwinValue{Value: &str}, 536 Optional: &optionTrue, 537 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 538 } 539 deviceATwin := dttype.Device{Twin: twinDeviceA} 540 contextDeviceA.DeviceList.Store(deviceA, &deviceATwin) 541 542 tests := []struct { 543 name string 544 context *dtcontext.DTContext 545 deviceID string 546 eventID string 547 msgTwin map[string]*dttype.MsgTwin 548 dealType int 549 err error 550 filterReturn orm.QuerySeter 551 allReturnInt int64 552 allReturnErr error 553 queryTableReturn orm.QuerySeter 554 }{ 555 { 556 name: "TestDealDeviceTwinResult(): dealTwinResult error", 557 context: &contextDeviceA, 558 deviceID: deviceB, 559 msgTwin: msgTwinValue, 560 dealType: RestDealType, 561 err: errors.New("the value type is not allowed"), 562 filterReturn: mockQuerySeter, 563 allReturnInt: int64(1), 564 allReturnErr: nil, 565 queryTableReturn: mockQuerySeter, 566 }, 567 } 568 569 fakeDevice := new([]dtclient.Device) 570 fakeDeviceArray := make([]dtclient.Device, 1) 571 fakeDeviceArray[0] = dtclient.Device{ID: deviceB} 572 fakeDevice = &fakeDeviceArray 573 574 fakeDeviceAttr := new([]dtclient.DeviceAttr) 575 fakeDeviceAttrArray := make([]dtclient.DeviceAttr, 1) 576 fakeDeviceAttrArray[0] = dtclient.DeviceAttr{DeviceID: deviceB} 577 fakeDeviceAttr = &fakeDeviceAttrArray 578 579 fakeDeviceTwin := new([]dtclient.DeviceTwin) 580 fakeDeviceTwinArray := make([]dtclient.DeviceTwin, 1) 581 fakeDeviceTwinArray[0] = dtclient.DeviceTwin{DeviceID: deviceB} 582 fakeDeviceTwin = &fakeDeviceTwinArray 583 584 for _, test := range tests { 585 t.Run(test.name, func(t *testing.T) { 586 mockQuerySeter.EXPECT().All(gomock.Any()).SetArg(0, *fakeDevice).Return(test.allReturnInt, test.allReturnErr).Times(1) 587 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1) 588 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1) 589 mockQuerySeter.EXPECT().All(gomock.Any()).SetArg(0, *fakeDeviceAttr).Return(test.allReturnInt, test.allReturnErr).Times(1) 590 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1) 591 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1) 592 mockQuerySeter.EXPECT().All(gomock.Any()).SetArg(0, *fakeDeviceTwin).Return(test.allReturnInt, test.allReturnErr).Times(1) 593 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1) 594 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1) 595 if err := DealDeviceTwin(test.context, test.deviceID, test.eventID, test.msgTwin, test.dealType); !reflect.DeepEqual(err, test.err) { 596 t.Errorf("DTManager.TestDealDeviceTwinResult() case failed: got = %v, Want = %v", err, test.err) 597 } 598 }) 599 } 600 } 601 602 // TestDealDeviceTwinTrans is function to test DealDeviceTwin when DeviceTwinTrans() return error 603 func TestDealDeviceTwinTrans(t *testing.T) { 604 var mockOrmer *beego.MockOrmer 605 var mockQuerySeter *beego.MockQuerySeter 606 mockCtrl := gomock.NewController(t) 607 defer mockCtrl.Finish() 608 mockOrmer = beego.NewMockOrmer(mockCtrl) 609 mockQuerySeter = beego.NewMockQuerySeter(mockCtrl) 610 dbm.DBAccess = mockOrmer 611 612 str := typeString 613 optionTrue := true 614 msgTwin := make(map[string]*dttype.MsgTwin) 615 msgTwin[key1] = &dttype.MsgTwin{ 616 Expected: twinValueFunc(), 617 Metadata: &dttype.TypeMetadata{ 618 Type: typeDeleted, 619 }, 620 } 621 622 contextDeviceB := contextFunc(deviceB) 623 twinDeviceB := make(map[string]*dttype.MsgTwin) 624 twinDeviceB[deviceB] = &dttype.MsgTwin{ 625 Expected: &dttype.TwinValue{ 626 Value: &str, 627 }, 628 Optional: &optionTrue, 629 } 630 deviceBTwin := dttype.Device{Twin: twinDeviceB} 631 contextDeviceB.DeviceList.Store(deviceB, &deviceBTwin) 632 633 tests := []struct { 634 name string 635 context *dtcontext.DTContext 636 deviceID string 637 eventID string 638 msgTwin map[string]*dttype.MsgTwin 639 dealType int 640 err error 641 filterReturn orm.QuerySeter 642 insertReturnInt int64 643 insertReturnErr error 644 deleteReturnInt int64 645 deleteReturnErr error 646 updateReturnInt int64 647 updateReturnErr error 648 allReturnInt int64 649 allReturnErr error 650 queryTableReturn orm.QuerySeter 651 }{ 652 { 653 name: "TestDealDeviceTwinTrans(): DeviceTwinTrans error", 654 context: &contextDeviceB, 655 deviceID: deviceB, 656 msgTwin: msgTwin, 657 dealType: RestDealType, 658 err: errors.New("Failed DB Operation"), 659 filterReturn: mockQuerySeter, 660 insertReturnInt: int64(1), 661 insertReturnErr: errors.New("Failed DB Operation"), 662 deleteReturnInt: int64(1), 663 deleteReturnErr: nil, 664 updateReturnInt: int64(1), 665 updateReturnErr: nil, 666 allReturnInt: int64(1), 667 allReturnErr: nil, 668 queryTableReturn: mockQuerySeter, 669 }, 670 } 671 672 fakeDevice := new([]dtclient.Device) 673 fakeDeviceArray := make([]dtclient.Device, 1) 674 fakeDeviceArray[0] = dtclient.Device{ID: deviceB} 675 fakeDevice = &fakeDeviceArray 676 677 fakeDeviceAttr := new([]dtclient.DeviceAttr) 678 fakeDeviceAttrArray := make([]dtclient.DeviceAttr, 1) 679 fakeDeviceAttrArray[0] = dtclient.DeviceAttr{DeviceID: deviceB} 680 fakeDeviceAttr = &fakeDeviceAttrArray 681 682 fakeDeviceTwin := new([]dtclient.DeviceTwin) 683 fakeDeviceTwinArray := make([]dtclient.DeviceTwin, 1) 684 fakeDeviceTwinArray[0] = dtclient.DeviceTwin{DeviceID: deviceB} 685 fakeDeviceTwin = &fakeDeviceTwinArray 686 687 for _, test := range tests { 688 t.Run(test.name, func(t *testing.T) { 689 mockOrmer.EXPECT().Rollback().Return(nil).Times(5) 690 mockOrmer.EXPECT().Commit().Return(nil).Times(0) 691 mockOrmer.EXPECT().Begin().Return(nil).Times(5) 692 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(0) 693 mockOrmer.EXPECT().Insert(gomock.Any()).Return(test.insertReturnInt, test.insertReturnErr).Times(5) 694 mockQuerySeter.EXPECT().Delete().Return(test.deleteReturnInt, test.deleteReturnErr).Times(0) 695 mockQuerySeter.EXPECT().Update(gomock.Any()).Return(test.updateReturnInt, test.updateReturnErr).Times(0) 696 mockQuerySeter.EXPECT().All(gomock.Any()).SetArg(0, *fakeDevice).Return(test.allReturnInt, test.allReturnErr).Times(1) 697 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1) 698 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1) 699 mockQuerySeter.EXPECT().All(gomock.Any()).SetArg(0, *fakeDeviceAttr).Return(test.allReturnInt, test.allReturnErr).Times(1) 700 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1) 701 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1) 702 mockQuerySeter.EXPECT().All(gomock.Any()).SetArg(0, *fakeDeviceTwin).Return(test.allReturnInt, test.allReturnErr).Times(1) 703 mockQuerySeter.EXPECT().Filter(gomock.Any(), gomock.Any()).Return(test.filterReturn).Times(1) 704 mockOrmer.EXPECT().QueryTable(gomock.Any()).Return(test.queryTableReturn).Times(1) 705 if err := DealDeviceTwin(test.context, test.deviceID, test.eventID, test.msgTwin, test.dealType); !reflect.DeepEqual(err, test.err) { 706 t.Errorf("DTManager.TestDealDeviceTwinTrans() case failed: got = %v, Want = %v", err, test.err) 707 } 708 }) 709 } 710 } 711 712 // TestDealVersion is function to test dealVersion 713 func TestDealVersion(t *testing.T) { 714 twinCloudEdgeVersion := dttype.TwinVersion{ 715 CloudVersion: 1, 716 EdgeVersion: 1, 717 } 718 twinCloudVersion := dttype.TwinVersion{ 719 CloudVersion: 1, 720 EdgeVersion: 0, 721 } 722 723 tests := []struct { 724 name string 725 version *dttype.TwinVersion 726 reqVersion *dttype.TwinVersion 727 dealType int 728 errorWant bool 729 err error 730 }{ 731 { 732 name: "TestDealVersion(): Case 1: dealType=3", 733 version: &dttype.TwinVersion{}, 734 dealType: SyncTwinDeleteDealType, 735 errorWant: true, 736 err: nil, 737 }, 738 { 739 name: "TestDealVersion(): Case 2: dealType>=1 && version.EdgeVersion>reqVersion.EdgeVersion", 740 version: &twinCloudEdgeVersion, 741 reqVersion: &twinCloudVersion, 742 dealType: SyncDealType, 743 errorWant: false, 744 err: errors.New("Not allowed to sync due to version conflict"), 745 }, 746 } 747 for _, test := range tests { 748 t.Run(test.name, func(t *testing.T) { 749 got, err := dealVersion(test.version, test.reqVersion, test.dealType) 750 if !reflect.DeepEqual(err, test.err) { 751 t.Errorf("DTManager.TestDealVersion() case failed: got = %v, Want = %v", err, test.err) 752 return 753 } 754 if !reflect.DeepEqual(got, test.errorWant) { 755 t.Errorf("DTManager.TestDealVersion() case failed: got = %v, want %v", got, test.errorWant) 756 } 757 }) 758 } 759 } 760 761 // TestDealTwinDelete is function to test dealTwinDelete 762 func TestDealTwinDelete(t *testing.T) { 763 optionTrue := true 764 optionFalse := false 765 str := typeString 766 doc := make(map[string]*dttype.TwinDoc) 767 doc[key1] = &dttype.TwinDoc{} 768 sync := make(map[string]*dttype.MsgTwin) 769 sync[key1] = &dttype.MsgTwin{ 770 Expected: twinValueFunc(), 771 Actual: twinValueFunc(), 772 Optional: &optionTrue, 773 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 774 ExpectedVersion: &dttype.TwinVersion{}, 775 ActualVersion: &dttype.TwinVersion{}, 776 } 777 result := make(map[string]*dttype.MsgTwin) 778 result[key1] = &dttype.MsgTwin{} 779 780 tests := []struct { 781 name string 782 returnResult *dttype.DealTwinResult 783 deviceID string 784 key string 785 twin *dttype.MsgTwin 786 msgTwin *dttype.MsgTwin 787 dealType int 788 err error 789 }{ 790 { 791 name: "TestDealTwinDelete(): Case 1: msgTwin is not nil; isChange is false", 792 returnResult: &dttype.DealTwinResult{ 793 Document: doc, 794 SyncResult: sync, 795 Result: result, 796 }, 797 deviceID: deviceA, 798 key: key1, 799 twin: &dttype.MsgTwin{ 800 Optional: &optionTrue, 801 Metadata: &dttype.TypeMetadata{ 802 Type: typeDeleted, 803 }, 804 ExpectedVersion: &dttype.TwinVersion{}, 805 }, 806 msgTwin: &dttype.MsgTwin{ 807 Expected: &dttype.TwinValue{ 808 Value: &str, 809 }, 810 Actual: &dttype.TwinValue{ 811 Value: &str, 812 }, 813 Optional: &optionFalse, 814 Metadata: &dttype.TypeMetadata{ 815 Type: typeString, 816 }, 817 ExpectedVersion: &dttype.TwinVersion{}, 818 ActualVersion: &dttype.TwinVersion{}, 819 }, 820 dealType: SyncDealType, 821 err: nil, 822 }, 823 { 824 name: "TestDealTwinDelete(): Case 2: hasTwinExpected is true; dealVersion() returns false", 825 returnResult: &dttype.DealTwinResult{ 826 Document: doc, 827 SyncResult: sync, 828 Result: result, 829 }, 830 deviceID: deviceA, 831 key: key1, 832 twin: &dttype.MsgTwin{ 833 Optional: &optionTrue, 834 Metadata: &dttype.TypeMetadata{ 835 Type: typeString, 836 }, 837 ExpectedVersion: &dttype.TwinVersion{ 838 CloudVersion: 1, 839 }, 840 }, 841 msgTwin: &dttype.MsgTwin{ 842 Expected: &dttype.TwinValue{ 843 Value: &str, 844 }, 845 Actual: &dttype.TwinValue{ 846 Value: &str, 847 }, 848 Optional: &optionFalse, 849 Metadata: &dttype.TypeMetadata{ 850 Type: typeDeleted, 851 }, 852 ExpectedVersion: &dttype.TwinVersion{ 853 CloudVersion: 0, 854 }, 855 ActualVersion: &dttype.TwinVersion{}, 856 }, 857 dealType: SyncDealType, 858 err: nil, 859 }, 860 { 861 name: "TestDealTwinDelete(): Case 3: hasTwinActual is true; dealVersion() returns false", 862 returnResult: &dttype.DealTwinResult{ 863 Document: doc, 864 SyncResult: sync, 865 Result: result, 866 }, 867 deviceID: deviceA, 868 key: key1, 869 twin: &dttype.MsgTwin{ 870 Optional: &optionTrue, 871 Metadata: &dttype.TypeMetadata{ 872 Type: typeString, 873 }, 874 ActualVersion: &dttype.TwinVersion{ 875 CloudVersion: 1, 876 }, 877 }, 878 msgTwin: &dttype.MsgTwin{ 879 Expected: &dttype.TwinValue{ 880 Value: &str, 881 }, 882 Actual: &dttype.TwinValue{ 883 Value: &str, 884 }, 885 Optional: &optionFalse, 886 Metadata: &dttype.TypeMetadata{ 887 Type: typeDeleted, 888 }, 889 ExpectedVersion: &dttype.TwinVersion{}, 890 ActualVersion: &dttype.TwinVersion{ 891 CloudVersion: 0, 892 }, 893 }, 894 dealType: SyncDealType, 895 err: nil, 896 }, 897 { 898 name: "TestDealTwinDelete(): Case 4: hasTwinExpected is true; hasTwinActual is true", 899 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 900 deviceID: deviceA, 901 key: key1, 902 twin: &dttype.MsgTwin{ 903 Optional: &optionTrue, 904 Metadata: &dttype.TypeMetadata{ 905 Type: typeString, 906 }, 907 ExpectedVersion: &dttype.TwinVersion{}, 908 ActualVersion: &dttype.TwinVersion{}, 909 }, 910 dealType: RestDealType, 911 err: nil, 912 }, 913 { 914 name: "TestDealTwinDelete(): Case 5: hasTwinExpected is true; hasTwinActual is false", 915 returnResult: &dttype.DealTwinResult{ 916 Document: doc, 917 SyncResult: sync, 918 Result: result, 919 }, 920 deviceID: deviceA, 921 key: key1, 922 twin: &dttype.MsgTwin{ 923 Optional: &optionTrue, 924 Metadata: &dttype.TypeMetadata{ 925 Type: typeString, 926 }, 927 ExpectedVersion: &dttype.TwinVersion{}, 928 }, 929 msgTwin: &dttype.MsgTwin{ 930 Expected: &dttype.TwinValue{ 931 Value: &str, 932 }, 933 Actual: &dttype.TwinValue{ 934 Value: &str, 935 }, 936 Optional: &optionFalse, 937 Metadata: &dttype.TypeMetadata{ 938 Type: typeDeleted, 939 }, 940 ExpectedVersion: &dttype.TwinVersion{}, 941 ActualVersion: &dttype.TwinVersion{}, 942 }, 943 dealType: SyncDealType, 944 err: nil, 945 }, 946 } 947 for _, test := range tests { 948 t.Run(test.name, func(t *testing.T) { 949 if err := dealTwinDelete(test.returnResult, test.deviceID, test.key, test.twin, test.msgTwin, test.dealType); !reflect.DeepEqual(err, test.err) { 950 t.Errorf("DTManager.TestDealTwinDelete() case failed: got = %+v, Want = %+v", err, test.err) 951 } 952 }) 953 } 954 } 955 956 // TestDealTwinCompare is function to test dealTwinCompare 957 func TestDealTwinCompare(t *testing.T) { 958 optionTrue := true 959 optionFalse := false 960 str := typeString 961 doc := make(map[string]*dttype.TwinDoc) 962 doc[key1] = &dttype.TwinDoc{} 963 sync := make(map[string]*dttype.MsgTwin) 964 sync[key1] = &dttype.MsgTwin{ 965 Expected: twinValueFunc(), 966 Actual: twinValueFunc(), 967 Optional: &optionTrue, 968 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 969 ExpectedVersion: &dttype.TwinVersion{}, 970 ActualVersion: &dttype.TwinVersion{}, 971 } 972 result := make(map[string]*dttype.MsgTwin) 973 result[key1] = &dttype.MsgTwin{} 974 975 tests := []struct { 976 name string 977 returnResult *dttype.DealTwinResult 978 deviceID string 979 key string 980 twin *dttype.MsgTwin 981 msgTwin *dttype.MsgTwin 982 dealType int 983 err error 984 }{ 985 { 986 name: "TestDealTwinCompare(): Case 1: msgTwin nil", 987 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 988 deviceID: deviceA, 989 key: key1, 990 twin: &dttype.MsgTwin{ 991 Optional: &optionTrue, 992 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 993 }, 994 dealType: RestDealType, 995 err: nil, 996 }, 997 { 998 name: "TestDealTwinCompare(): Case 2: actualOk is false; actualErr is not nil", 999 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 1000 deviceID: deviceA, 1001 key: key1, 1002 twin: &dttype.MsgTwin{ 1003 Expected: &dttype.TwinValue{Value: &str}, 1004 Actual: &dttype.TwinValue{Value: &str}, 1005 Optional: &optionTrue, 1006 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 1007 }, 1008 msgTwin: &dttype.MsgTwin{ 1009 Actual: &dttype.TwinValue{Value: &str}, 1010 Optional: &optionFalse, 1011 Metadata: &dttype.TypeMetadata{Type: typeInt}, 1012 }, 1013 dealType: RestDealType, 1014 err: errors.New("the value is not int"), 1015 }, 1016 { 1017 name: "TestDealTwinCompare(): Case 3: expectedOk is true; dealVersion() returns false", 1018 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 1019 deviceID: deviceA, 1020 key: key1, 1021 twin: &dttype.MsgTwin{ 1022 Expected: &dttype.TwinValue{Value: &str}, 1023 Actual: &dttype.TwinValue{Value: &str}, 1024 Optional: &optionTrue, 1025 Metadata: &dttype.TypeMetadata{Type: typeString}, 1026 }, 1027 msgTwin: &dttype.MsgTwin{ 1028 Expected: &dttype.TwinValue{Value: &str}, 1029 Actual: &dttype.TwinValue{Value: &str}, 1030 Optional: &optionFalse, 1031 Metadata: &dttype.TypeMetadata{Type: typeInt}, 1032 ActualVersion: &dttype.TwinVersion{}, 1033 }, 1034 dealType: SyncDealType, 1035 err: nil, 1036 }, 1037 { 1038 name: "TestDealTwinCompare(): Case 4: actualOk is true; dealVersion() returns false", 1039 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 1040 deviceID: deviceA, 1041 key: key1, 1042 twin: &dttype.MsgTwin{ 1043 Expected: &dttype.TwinValue{Value: &str}, 1044 Actual: &dttype.TwinValue{Value: &str}, 1045 Optional: &optionTrue, 1046 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 1047 }, 1048 msgTwin: &dttype.MsgTwin{ 1049 Actual: &dttype.TwinValue{Value: &str}, 1050 Optional: &optionFalse, 1051 Metadata: &dttype.TypeMetadata{Type: typeString}, 1052 }, 1053 dealType: SyncDealType, 1054 err: nil, 1055 }, 1056 { 1057 name: "TestDealTwinCompare(): Case 5: expectedOk is true; actualOk is true", 1058 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 1059 deviceID: deviceA, 1060 key: key1, 1061 twin: &dttype.MsgTwin{ 1062 Optional: &optionTrue, 1063 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 1064 }, 1065 msgTwin: &dttype.MsgTwin{ 1066 Expected: &dttype.TwinValue{Value: &str}, 1067 Actual: &dttype.TwinValue{Value: &str}, 1068 Optional: &optionFalse, 1069 Metadata: &dttype.TypeMetadata{Type: typeString}, 1070 ActualVersion: &dttype.TwinVersion{}, 1071 }, 1072 dealType: RestDealType, 1073 err: nil, 1074 }, 1075 { 1076 name: "TestDealTwinCompare(): Case 6: expectedOk is false; actualOk is false", 1077 returnResult: &dttype.DealTwinResult{Document: doc, SyncResult: sync, Result: result}, 1078 deviceID: deviceA, 1079 key: key1, 1080 twin: &dttype.MsgTwin{ 1081 Optional: &optionTrue, 1082 Metadata: &dttype.TypeMetadata{Type: typeDeleted}, 1083 }, 1084 msgTwin: &dttype.MsgTwin{ 1085 Optional: &optionFalse, 1086 ActualVersion: &dttype.TwinVersion{}, 1087 }, 1088 dealType: SyncDealType, 1089 err: nil, 1090 }, 1091 } 1092 for _, test := range tests { 1093 t.Run(test.name, func(t *testing.T) { 1094 if err := dealTwinCompare(test.returnResult, test.deviceID, test.key, test.twin, test.msgTwin, test.dealType); !reflect.DeepEqual(err, test.err) { 1095 t.Errorf("DTManager.TestDealTwinCompare() case failed: got = %+v, Want = %+v", err, test.err) 1096 } 1097 }) 1098 } 1099 } 1100 1101 // TestDealTwinAdd is function to test dealTwinAdd 1102 func TestDealTwinAdd(t *testing.T) { 1103 optionTrue := true 1104 str := typeString 1105 doc := make(map[string]*dttype.TwinDoc) 1106 doc[key1] = &dttype.TwinDoc{} 1107 sync := make(map[string]*dttype.MsgTwin) 1108 sync[key1] = &dttype.MsgTwin{} 1109 result := make(map[string]*dttype.MsgTwin) 1110 result[key1] = &dttype.MsgTwin{} 1111 1112 twinDelete := make(map[string]*dttype.MsgTwin) 1113 twinDelete[key1] = &dttype.MsgTwin{ 1114 Metadata: &dttype.TypeMetadata{ 1115 Type: typeDeleted, 1116 }, 1117 } 1118 twinInt := make(map[string]*dttype.MsgTwin) 1119 twinInt[key1] = &dttype.MsgTwin{ 1120 Metadata: &dttype.TypeMetadata{ 1121 Type: typeInt, 1122 }, 1123 } 1124 1125 tests := []struct { 1126 name string 1127 returnResult *dttype.DealTwinResult 1128 deviceID string 1129 key string 1130 twins map[string]*dttype.MsgTwin 1131 msgTwin *dttype.MsgTwin 1132 dealType int 1133 err error 1134 }{ 1135 { 1136 name: "TestDealTwinAdd(): Case 1: msgTwin nil", 1137 returnResult: &dttype.DealTwinResult{ 1138 Document: doc, 1139 SyncResult: sync, 1140 Result: result, 1141 }, 1142 deviceID: deviceA, 1143 key: key1, 1144 dealType: RestDealType, 1145 err: errors.New("The request body is wrong"), 1146 }, 1147 { 1148 name: "TestDealTwinAdd(): Case 2: msgTwin.Expected is not nil; dealVersion() returns false", 1149 returnResult: &dttype.DealTwinResult{ 1150 Document: doc, 1151 SyncResult: sync, 1152 Result: result, 1153 }, 1154 deviceID: deviceA, 1155 key: key1, 1156 twins: twinDelete, 1157 msgTwin: &dttype.MsgTwin{ 1158 Expected: &dttype.TwinValue{ 1159 Value: &str, 1160 }, 1161 Actual: &dttype.TwinValue{ 1162 Value: &str, 1163 }, 1164 Optional: &optionTrue, 1165 Metadata: &dttype.TypeMetadata{ 1166 Type: typeDeleted, 1167 }, 1168 ActualVersion: &dttype.TwinVersion{}, 1169 }, 1170 dealType: SyncDealType, 1171 err: nil, 1172 }, 1173 { 1174 name: "TestDealTwinAdd(): Case 3: msgTwin.Expected is not nil; ValidateValue() returns error", 1175 returnResult: &dttype.DealTwinResult{ 1176 Document: doc, 1177 SyncResult: sync, 1178 Result: result, 1179 }, 1180 deviceID: deviceA, 1181 key: key1, 1182 twins: twinDelete, 1183 msgTwin: &dttype.MsgTwin{ 1184 Expected: &dttype.TwinValue{ 1185 Value: &str, 1186 }, 1187 Actual: &dttype.TwinValue{ 1188 Value: &str, 1189 }, 1190 Optional: &optionTrue, 1191 Metadata: &dttype.TypeMetadata{ 1192 Type: typeInt, 1193 }, 1194 ExpectedVersion: &dttype.TwinVersion{}, 1195 }, 1196 dealType: SyncDealType, 1197 err: nil, 1198 }, 1199 { 1200 name: "TestDealTwinAdd(): Case 4: msgTwin.Actual is not nil; dealVersion() returns false", 1201 returnResult: &dttype.DealTwinResult{ 1202 Document: doc, 1203 SyncResult: sync, 1204 Result: result, 1205 }, 1206 deviceID: deviceA, 1207 key: key1, 1208 twins: twinDelete, 1209 msgTwin: &dttype.MsgTwin{ 1210 Expected: &dttype.TwinValue{ 1211 Value: &str, 1212 }, 1213 Actual: &dttype.TwinValue{ 1214 Value: &str, 1215 }, 1216 Optional: &optionTrue, 1217 Metadata: &dttype.TypeMetadata{ 1218 Type: typeDeleted, 1219 }, 1220 ExpectedVersion: &dttype.TwinVersion{}, 1221 }, 1222 dealType: SyncDealType, 1223 err: nil, 1224 }, 1225 { 1226 name: "TestDealTwinAdd(): Case 5: msgTwin.Actual is not nil; ValidateValue() returns error; dealType=0", 1227 returnResult: &dttype.DealTwinResult{ 1228 Document: doc, 1229 SyncResult: sync, 1230 Result: result, 1231 }, 1232 deviceID: deviceA, 1233 key: key1, 1234 twins: twinDelete, 1235 msgTwin: &dttype.MsgTwin{ 1236 Actual: &dttype.TwinValue{ 1237 Value: &str, 1238 }, 1239 Optional: &optionTrue, 1240 Metadata: &dttype.TypeMetadata{ 1241 Type: typeInt, 1242 }, 1243 ExpectedVersion: &dttype.TwinVersion{}, 1244 ActualVersion: &dttype.TwinVersion{}, 1245 }, 1246 dealType: RestDealType, 1247 err: errors.New("the value is not int"), 1248 }, 1249 { 1250 name: "TestDealTwinAdd(): Case 6: msgTwin.Actual is not nil; ValidateValue() returns error; dealType=1", 1251 returnResult: &dttype.DealTwinResult{ 1252 Document: doc, 1253 SyncResult: sync, 1254 Result: result, 1255 }, 1256 deviceID: deviceA, 1257 key: key1, 1258 twins: twinDelete, 1259 msgTwin: &dttype.MsgTwin{ 1260 Actual: &dttype.TwinValue{ 1261 Value: &str, 1262 }, 1263 Optional: &optionTrue, 1264 Metadata: &dttype.TypeMetadata{ 1265 Type: typeInt, 1266 }, 1267 ExpectedVersion: &dttype.TwinVersion{}, 1268 ActualVersion: &dttype.TwinVersion{}, 1269 }, 1270 dealType: SyncDealType, 1271 err: nil, 1272 }, 1273 { 1274 name: "TestDealTwinAdd(): Case 7: msgTwin.Expected is nil; msgTwin.Actual is nil", 1275 returnResult: &dttype.DealTwinResult{ 1276 Document: doc, 1277 SyncResult: sync, 1278 Result: result, 1279 }, 1280 deviceID: deviceA, 1281 key: key1, 1282 twins: twinInt, 1283 msgTwin: &dttype.MsgTwin{ 1284 ExpectedVersion: &dttype.TwinVersion{}, 1285 ActualVersion: &dttype.TwinVersion{}, 1286 }, 1287 dealType: RestDealType, 1288 err: nil, 1289 }, 1290 { 1291 name: "TestDealTwinAdd(): Case 8: msgTwin.Expected is not nil; msgTwin.Actual is not nil", 1292 returnResult: &dttype.DealTwinResult{ 1293 Document: doc, 1294 SyncResult: sync, 1295 Result: result, 1296 }, 1297 deviceID: deviceA, 1298 key: key1, 1299 twins: twinDelete, 1300 msgTwin: &dttype.MsgTwin{ 1301 Expected: &dttype.TwinValue{ 1302 Value: &str, 1303 }, 1304 Actual: &dttype.TwinValue{ 1305 Value: &str, 1306 }, 1307 Optional: &optionTrue, 1308 Metadata: &dttype.TypeMetadata{ 1309 Type: typeDeleted, 1310 }, 1311 ExpectedVersion: &dttype.TwinVersion{}, 1312 ActualVersion: &dttype.TwinVersion{}, 1313 }, 1314 dealType: SyncDealType, 1315 err: nil, 1316 }, 1317 } 1318 for _, test := range tests { 1319 t.Run(test.name, func(t *testing.T) { 1320 if err := dealTwinAdd(test.returnResult, test.deviceID, test.key, test.twins, test.msgTwin, test.dealType); !reflect.DeepEqual(err, test.err) { 1321 t.Errorf("DTManager.TestDealTwinAdd() case failed: got = %+v, Want = %+v", err, test.err) 1322 } 1323 }) 1324 } 1325 } 1326 1327 // TestDealMsgTwin is function to test DealMsgTwin 1328 func TestDealMsgTwin(t *testing.T) { 1329 value := "value" 1330 str := typeString 1331 optionTrue := true 1332 optionFalse := false 1333 add := make([]dtclient.DeviceTwin, 0) 1334 deletes := make([]dtclient.DeviceDelete, 0) 1335 update := make([]dtclient.DeviceTwinUpdate, 0) 1336 result := make(map[string]*dttype.MsgTwin) 1337 syncResult := make(map[string]*dttype.MsgTwin) 1338 syncResultDevice := make(map[string]*dttype.MsgTwin) 1339 syncResultDevice[deviceA] = &dttype.MsgTwin{} 1340 document := make(map[string]*dttype.TwinDoc) 1341 documentDevice := make(map[string]*dttype.TwinDoc) 1342 documentDevice[deviceA] = &dttype.TwinDoc{LastState: nil} 1343 documentDeviceTwin := make(map[string]*dttype.TwinDoc) 1344 documentDeviceTwin[deviceA] = &dttype.TwinDoc{ 1345 LastState: &dttype.MsgTwin{ 1346 Expected: &dttype.TwinValue{ 1347 Value: &str, 1348 }, 1349 Actual: &dttype.TwinValue{ 1350 Value: &str, 1351 }, 1352 Optional: &optionTrue, 1353 Metadata: &dttype.TypeMetadata{ 1354 Type: typeDeleted, 1355 }, 1356 }, 1357 } 1358 1359 msgTwin := make(map[string]*dttype.MsgTwin) 1360 msgTwin[deviceB] = &dttype.MsgTwin{ 1361 Expected: &dttype.TwinValue{ 1362 Value: &value, 1363 }, 1364 Metadata: &dttype.TypeMetadata{ 1365 Type: "nil", 1366 }, 1367 } 1368 msgTwinDevice := make(map[string]*dttype.MsgTwin) 1369 msgTwinDevice[deviceA] = nil 1370 msgTwinDeviceTwin := make(map[string]*dttype.MsgTwin) 1371 msgTwinDeviceTwin[deviceA] = &dttype.MsgTwin{ 1372 Expected: &dttype.TwinValue{ 1373 Value: &str, 1374 }, 1375 Actual: &dttype.TwinValue{ 1376 Value: &str, 1377 }, 1378 Optional: &optionFalse, 1379 Metadata: &dttype.TypeMetadata{ 1380 Type: typeInt, 1381 }, 1382 ActualVersion: &dttype.TwinVersion{}, 1383 } 1384 1385 context := contextFunc(deviceB) 1386 twin := make(map[string]*dttype.MsgTwin) 1387 twin[deviceA] = &dttype.MsgTwin{ 1388 Expected: &dttype.TwinValue{ 1389 Value: &str, 1390 }, 1391 Actual: &dttype.TwinValue{ 1392 Value: &str, 1393 }, 1394 Optional: &optionTrue, 1395 Metadata: &dttype.TypeMetadata{ 1396 Type: typeDeleted, 1397 }, 1398 } 1399 device := dttype.Device{Twin: twin} 1400 context.DeviceList.Store(deviceA, &device) 1401 1402 tests := []struct { 1403 name string 1404 context *dtcontext.DTContext 1405 deviceID string 1406 msgTwins map[string]*dttype.MsgTwin 1407 dealType int 1408 want dttype.DealTwinResult 1409 }{ 1410 { 1411 name: "TestDealMsgTwin(): Case1: invalid device id", 1412 context: &context, 1413 deviceID: deviceC, 1414 msgTwins: msgTwin, 1415 dealType: RestDealType, 1416 want: dttype.DealTwinResult{ 1417 Add: add, 1418 Delete: deletes, 1419 Update: update, 1420 Result: result, 1421 SyncResult: syncResult, 1422 Document: document, 1423 Err: errors.New("invalid device id"), 1424 }, 1425 }, 1426 { 1427 name: "TestDealMsgTwin(): Case 2: dealTwinCompare error", 1428 context: &context, 1429 deviceID: deviceA, 1430 msgTwins: msgTwinDeviceTwin, 1431 dealType: RestDealType, 1432 want: dttype.DealTwinResult{ 1433 Add: add, 1434 Delete: deletes, 1435 Update: update, 1436 Result: result, 1437 SyncResult: syncResultDevice, 1438 Document: documentDevice, 1439 Err: errors.New("the value is not int"), 1440 }, 1441 }, 1442 { 1443 name: "TestDealMsgTwin(): Case 3: Success case", 1444 context: &context, 1445 deviceID: deviceA, 1446 msgTwins: msgTwinDevice, 1447 dealType: RestDealType, 1448 want: dttype.DealTwinResult{ 1449 Add: add, 1450 Delete: deletes, 1451 Update: update, 1452 Result: result, 1453 SyncResult: syncResultDevice, 1454 Document: documentDeviceTwin, 1455 }, 1456 }, 1457 } 1458 for _, tt := range tests { 1459 t.Run(tt.name, func(t *testing.T) { 1460 if got := DealMsgTwin(tt.context, tt.deviceID, tt.msgTwins, tt.dealType); !reflect.DeepEqual(got, tt.want) { 1461 t.Errorf("DTManager.DealMsgTwin() case failed: got = %+v, want = %+v", got, tt.want) 1462 } 1463 }) 1464 } 1465 }