github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/dtcontext/dtcontext_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 dtcontext
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"reflect"
    23  	"sync"
    24  	"testing"
    25  
    26  	"github.com/kubeedge/beehive/pkg/core/model"
    27  	"github.com/kubeedge/kubeedge/edge/pkg/common/modules"
    28  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon"
    29  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype"
    30  )
    31  
    32  //TestCommTo is function to test CommTo().
    33  func TestCommTo(t *testing.T) {
    34  	commChan := make(map[string]chan interface{})
    35  	testInterface := make(chan interface{}, 1)
    36  	commChan["ModuleB"] = testInterface
    37  	dtContext := &DTContext{
    38  		CommChan: commChan,
    39  	}
    40  	var returnValue interface{}
    41  	tests := []struct {
    42  		name       string
    43  		modulename string
    44  		content    interface{}
    45  		wantErr    error
    46  	}{
    47  		{
    48  			//Failure Case
    49  			name:       "ModuleNotPresent",
    50  			modulename: "ModuleA",
    51  			content:    nil,
    52  			wantErr:    errors.New("Not found chan to communicate"),
    53  		},
    54  		{
    55  			//Success Case
    56  			name:       "ModulePresent",
    57  			modulename: "ModuleB",
    58  			content:    dttype.MembershipUpdate{AddDevices: []dttype.Device{{ID: "DeviceA", Name: "Router", State: "unknown"}}},
    59  			wantErr:    nil,
    60  		},
    61  	}
    62  	for _, test := range tests {
    63  		t.Run(test.name, func(t *testing.T) {
    64  			err := dtContext.CommTo(test.modulename, test.content)
    65  			if err == nil {
    66  				returnValue = <-testInterface
    67  			} else {
    68  				returnValue = nil
    69  			}
    70  			if !reflect.DeepEqual(err, test.wantErr) {
    71  				t.Errorf("Error in CommTo %v, Want %v", err, test.wantErr)
    72  				return
    73  			}
    74  			if !reflect.DeepEqual(returnValue, test.content) {
    75  				t.Errorf("Got %v on channel, Want % v on Channel", returnValue, test.content)
    76  				return
    77  			}
    78  		})
    79  	}
    80  }
    81  
    82  //TestHeartBeat is function to test HeartBeat().
    83  func TestHeartBeat(t *testing.T) {
    84  	tests := []struct {
    85  		name       string
    86  		dtc        *DTContext
    87  		moduleName string
    88  		content    interface{}
    89  		wantError  error
    90  	}{
    91  		{
    92  			//Success Case
    93  			name: "PingTest",
    94  			dtc: &DTContext{
    95  				ModulesHealth: &sync.Map{},
    96  			},
    97  			moduleName: "ModuleA",
    98  			content:    "ping",
    99  			wantError:  nil,
   100  		},
   101  		{
   102  			//Failure Case
   103  			name: "StopTest",
   104  			dtc: &DTContext{
   105  				ModulesHealth: &sync.Map{},
   106  			},
   107  			moduleName: "ModuleB",
   108  			content:    "stop",
   109  			wantError:  errors.New("stop"),
   110  		},
   111  	}
   112  	for _, test := range tests {
   113  		t.Run(test.name, func(t *testing.T) {
   114  			dtc := &DTContext{
   115  				ModulesHealth: test.dtc.ModulesHealth,
   116  			}
   117  			if err := dtc.HeartBeat(test.moduleName, test.content); !reflect.DeepEqual(err, test.wantError) {
   118  				t.Errorf("DTContext.HeartBeat() error = %v, Want = %v", err, test.wantError)
   119  			}
   120  		})
   121  	}
   122  }
   123  
   124  //TestGetMutex is function to test GetMutex().
   125  func TestGetMutex(t *testing.T) {
   126  	dtc := &DTContext{
   127  		DeviceMutex: &sync.Map{},
   128  	}
   129  	var testMutex *sync.Mutex
   130  	dtc.DeviceMutex.Store("DeviceB", "")
   131  	dtc.DeviceMutex.Store("DeviceC", testMutex)
   132  	tests := []struct {
   133  		name     string
   134  		want     *sync.Mutex
   135  		wantBool bool
   136  		deviceID string
   137  	}{
   138  		{
   139  			//Failure Case-No device present
   140  			name:     "UnknownDevice",
   141  			wantBool: false,
   142  			deviceID: "DeviceA",
   143  		},
   144  		{
   145  			//Failure Case-Device present but unable to get mutex
   146  			name:     "UnableToGetMutex",
   147  			wantBool: false,
   148  			deviceID: "DeviceB",
   149  		},
   150  		{
   151  			//Success Case
   152  			name:     "KnownDevice",
   153  			wantBool: true,
   154  			deviceID: "DeviceC",
   155  		},
   156  	}
   157  	for _, test := range tests {
   158  		t.Run(test.name, func(t *testing.T) {
   159  			got, gotBool := dtc.GetMutex(test.deviceID)
   160  			if !reflect.DeepEqual(got, test.want) {
   161  				t.Errorf("DTContext.GetMutex() got = %v, want = %v", got, test.want)
   162  				return
   163  			}
   164  			if gotBool != test.wantBool {
   165  				t.Errorf("DTContext.GetMutex() gotBool = %v, wantError = %v", gotBool, test.wantBool)
   166  				return
   167  			}
   168  		})
   169  	}
   170  }
   171  
   172  //TestLock is function to test Lock().
   173  func TestLock(t *testing.T) {
   174  	dtc := &DTContext{
   175  		Mutex:       &sync.RWMutex{},
   176  		DeviceMutex: &sync.Map{},
   177  	}
   178  	var testMutex sync.Mutex
   179  	dtc.DeviceMutex.Store("DeviceB", &testMutex)
   180  	tests := []struct {
   181  		name     string
   182  		deviceID string
   183  		wantBool bool
   184  	}{
   185  		{
   186  			//Failure Case
   187  			name:     "UnknownDevice",
   188  			deviceID: "DeviceA",
   189  			wantBool: false,
   190  		},
   191  		{
   192  			//Success Case
   193  			name:     "KnownDevice",
   194  			deviceID: "DeviceB",
   195  			wantBool: true,
   196  		},
   197  	}
   198  	for _, test := range tests {
   199  		t.Run(test.name, func(t *testing.T) {
   200  			if got := dtc.Lock(test.deviceID); got != test.wantBool {
   201  				t.Errorf("DTContext.Lock() = %v, want = %v", got, test.wantBool)
   202  			}
   203  		})
   204  	}
   205  }
   206  
   207  //TestUnlock is function to test Unlock().
   208  func TestUnlock(t *testing.T) {
   209  	dtc := &DTContext{
   210  		Mutex:       &sync.RWMutex{},
   211  		DeviceMutex: &sync.Map{},
   212  	}
   213  	// Creating a mutex variable and getting a lock over it.
   214  	var testMutex sync.Mutex
   215  	dtc.DeviceMutex.Store("DeviceB", &testMutex)
   216  	dtc.Lock("DeviceB")
   217  	tests := []struct {
   218  		name     string
   219  		deviceID string
   220  		wantBool bool
   221  	}{
   222  		{
   223  			//Failure Case
   224  			name:     "UnknownDevice",
   225  			deviceID: "DeviceA",
   226  			wantBool: false,
   227  		},
   228  		{
   229  			//Success Case
   230  			name:     "KnownDevice",
   231  			deviceID: "DeviceB",
   232  			wantBool: true,
   233  		},
   234  	}
   235  	for _, tt := range tests {
   236  		t.Run(tt.name, func(t *testing.T) {
   237  			if got := dtc.Unlock(tt.deviceID); got != tt.wantBool {
   238  				t.Errorf("DTContext.Unlock() = %v, Want = %v", got, tt.wantBool)
   239  			}
   240  		})
   241  	}
   242  }
   243  
   244  //TestIsDeviceExist is to test IsDeviceExist().
   245  func TestIsDeviceExist(t *testing.T) {
   246  	dtc := &DTContext{
   247  		DeviceList: &sync.Map{},
   248  	}
   249  	dtc.DeviceList.Store("DeviceB", "")
   250  	tests := []struct {
   251  		name     string
   252  		deviceID string
   253  		wantBool bool
   254  	}{
   255  		{
   256  			//Failure Case
   257  			name:     "UnknownDevice",
   258  			deviceID: "DeviceA",
   259  			wantBool: false,
   260  		},
   261  		{
   262  			//Success Case
   263  			name:     "KnownDevice",
   264  			deviceID: "DeviceB",
   265  			wantBool: true,
   266  		},
   267  	}
   268  	for _, test := range tests {
   269  		t.Run(test.name, func(t *testing.T) {
   270  			if got := dtc.IsDeviceExist(test.deviceID); got != test.wantBool {
   271  				t.Errorf("DTContext.IsDeviceExist() = %v, Want = %v", got, test.wantBool)
   272  			}
   273  		})
   274  	}
   275  }
   276  
   277  //Function TestGetDevice is to test GetDevice().
   278  func TestGetDevice(t *testing.T) {
   279  	dtc := &DTContext{
   280  		DeviceList: &sync.Map{},
   281  	}
   282  	var device dttype.Device
   283  	dtc.DeviceList.Store("DeviceA", "")
   284  	dtc.DeviceList.Store("DeviceB", &device)
   285  	tests := []struct {
   286  		name     string
   287  		deviceID string
   288  		want     *dttype.Device
   289  		wantBool bool
   290  	}{
   291  		{
   292  			//Failure Case-DeviceID not present
   293  			name:     "UnknownDevice",
   294  			deviceID: "",
   295  			want:     nil,
   296  			wantBool: false,
   297  		},
   298  		{
   299  			//Failure Case-DeviceID present but unable to get device
   300  			name:     "DeviceError",
   301  			deviceID: "DeviceA",
   302  			want:     nil,
   303  			wantBool: false,
   304  		},
   305  		{
   306  			//Success Case
   307  			name:     "KnownDevice",
   308  			deviceID: "DeviceB",
   309  			want:     &dttype.Device{},
   310  			wantBool: true,
   311  		},
   312  	}
   313  	for _, test := range tests {
   314  		t.Run(test.name, func(t *testing.T) {
   315  			got, gotBool := dtc.GetDevice(test.deviceID)
   316  			if !reflect.DeepEqual(got, test.want) {
   317  				t.Errorf("DTContext.GetDevice() got = %v, Want = %v", got, test.want)
   318  				return
   319  			}
   320  			if gotBool != test.wantBool {
   321  				t.Errorf("DTContext.GetDevice() gotBool = %v, wantError %v", gotBool, test.wantBool)
   322  				return
   323  			}
   324  		})
   325  	}
   326  }
   327  
   328  //Function TestSend is function to test Send().
   329  func TestSend(t *testing.T) {
   330  	payload := dttype.MembershipUpdate{
   331  		AddDevices: []dttype.Device{
   332  			{
   333  				ID:    "DeviceA",
   334  				Name:  "Router",
   335  				State: "unknown",
   336  			},
   337  		},
   338  	}
   339  	content, err := json.Marshal(payload)
   340  	if err != nil {
   341  		t.Errorf("Got error on marshalling: %v", err)
   342  	}
   343  	commChan := make(map[string]chan interface{})
   344  	receiveCh := make(chan interface{}, 1)
   345  	commChan[dtcommon.TwinModule] = receiveCh
   346  	var msg = &model.Message{
   347  		Content: content,
   348  	}
   349  	dtc := &DTContext{
   350  		CommChan: commChan,
   351  	}
   352  	tests := []struct {
   353  		name      string
   354  		identity  string
   355  		action    string
   356  		module    string
   357  		msg       *model.Message
   358  		wantError error
   359  	}{
   360  		{
   361  			//Failure Case
   362  			name:      "UnknownModule",
   363  			action:    dtcommon.SendToCloud,
   364  			module:    dtcommon.CommModule,
   365  			msg:       msg,
   366  			wantError: errors.New("Not found chan to communicate"),
   367  		},
   368  		{
   369  			//Success Case
   370  			name:      "KnownModule",
   371  			action:    dtcommon.SendToCloud,
   372  			module:    dtcommon.TwinModule,
   373  			msg:       msg,
   374  			wantError: nil,
   375  		},
   376  	}
   377  	for _, test := range tests {
   378  		t.Run(test.name, func(t *testing.T) {
   379  			if err := dtc.Send(test.identity, test.action, test.module, test.msg); !reflect.DeepEqual(err, test.wantError) {
   380  				t.Errorf("DTContext.Send() error = %v, Want =  %v", err, test.wantError)
   381  			}
   382  		})
   383  	}
   384  }
   385  
   386  //TestBuildModelMessage is to test BuildModelMessage().
   387  func TestBuildModelMessage(t *testing.T) {
   388  	dtc := &DTContext{}
   389  	payload := dttype.MembershipUpdate{
   390  		AddDevices: []dttype.Device{
   391  			{
   392  				ID:    "DeviceA",
   393  				Name:  "Router",
   394  				State: "unknown",
   395  			},
   396  		},
   397  	}
   398  	content, err := json.Marshal(payload)
   399  	if err != nil {
   400  		t.Errorf("Error on Marshalling: %v", err)
   401  	}
   402  	tests := []struct {
   403  		name      string
   404  		group     string
   405  		parentID  string
   406  		resource  string
   407  		operation string
   408  		content   interface{}
   409  		want      *model.Message
   410  	}{
   411  		{
   412  			name:      "BuildModelMessageTest",
   413  			group:     "resource",
   414  			resource:  "membership/detail",
   415  			operation: "get",
   416  			content:   content,
   417  			want:      &model.Message{},
   418  		},
   419  	}
   420  	for _, test := range tests {
   421  		t.Run(test.name, func(t *testing.T) {
   422  			got := dtc.BuildModelMessage(test.group, test.parentID, test.resource, test.operation, test.content)
   423  			if got.Header.ParentID != test.parentID {
   424  				t.Errorf("DTContext.BuildModelMessage failed due to wrong parentID, Got = %v Want = %v", got.Header.ParentID, test.parentID)
   425  				return
   426  			}
   427  			if got.Router.Source != modules.TwinGroup {
   428  				t.Errorf("DtContext.BuildModelMessage failed due to wrong source, Got= %v Want = %v", got.Router.Source, modules.TwinGroup)
   429  				return
   430  			}
   431  			if got.Router.Group != test.group {
   432  				t.Errorf("DTContext.BuildModelMessage due to wrong group, Got = %v Want = %v", got.Router.Group, test.group)
   433  				return
   434  			}
   435  			if got.Router.Resource != test.resource {
   436  				t.Errorf("DTContext.BuildModelMessage failed due to wrong resource, Got = %v Want =%v ", got.Router.Resource, test.resource)
   437  				return
   438  			}
   439  			if got.Router.Operation != test.operation {
   440  				t.Errorf("DTContext.BuildModelMessage failed due to wrong operation, Got = %v Want = %v ", got.Router.Operation, test.operation)
   441  				return
   442  			}
   443  			if !reflect.DeepEqual(got.Content, test.content) {
   444  				t.Errorf("DTContext.buildModelMessage failed due to wrong content, Got= %v Want = %v", got.Content, test.content)
   445  				return
   446  			}
   447  		})
   448  	}
   449  }