github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/dtmanager/communicate_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  	"errors"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	beehiveContext "github.com/kubeedge/beehive/pkg/core/context"
    26  	"github.com/kubeedge/beehive/pkg/core/model"
    27  	cloudconn "github.com/kubeedge/kubeedge/edge/pkg/common/cloudconnection"
    28  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon"
    29  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcontext"
    30  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype"
    31  )
    32  
    33  // TestStartAction is function to test Start() when value is passed in ReceiverChan.
    34  func TestStartAction(t *testing.T) {
    35  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
    36  
    37  	dtContextStateConnected, _ := dtcontext.InitDTContext()
    38  	dtContextStateConnected.State = dtcommon.Connected
    39  	receiveChanActionPresent := make(chan interface{}, 1)
    40  
    41  	const delay = 10 * time.Millisecond
    42  	const maxRetries = 5
    43  
    44  	receiveChanActionPresent <- &dttype.DTMessage{
    45  		Action:   dtcommon.SendToCloud,
    46  		Identity: "identity",
    47  		Msg: &model.Message{
    48  			Header: model.MessageHeader{
    49  				ID: "message",
    50  			},
    51  			Content: "msg",
    52  		},
    53  	}
    54  
    55  	receiveChanActionNotPresent := make(chan interface{}, 1)
    56  	receiveChanActionNotPresent <- &dttype.DTMessage{
    57  		Action:   "action",
    58  		Identity: "identity",
    59  		Msg: &model.Message{
    60  			Content: "msg",
    61  		},
    62  	}
    63  	tests := []struct {
    64  		name   string
    65  		Worker Worker
    66  	}{
    67  		{
    68  			name: "StartTest-ActionPresentInActionCallback",
    69  			Worker: Worker{
    70  				ReceiverChan: receiveChanActionPresent,
    71  				DTContexts:   dtContextStateConnected,
    72  			},
    73  		},
    74  		{
    75  			name: "StartTest-ActionNotPresentInActionCallback",
    76  			Worker: Worker{
    77  				ReceiverChan: receiveChanActionNotPresent,
    78  				DTContexts:   dtContextStateConnected,
    79  			},
    80  		},
    81  	}
    82  	for _, test := range tests {
    83  		retry := 0
    84  		t.Run(test.name, func(t *testing.T) {
    85  			cw := CommWorker{
    86  				Worker: test.Worker,
    87  			}
    88  			go cw.Start()
    89  			if test.Worker.ReceiverChan == receiveChanActionPresent {
    90  				for retry < maxRetries {
    91  					time.Sleep(delay)
    92  					retry++
    93  					_, exist := test.Worker.DTContexts.ConfirmMap.Load("message")
    94  					if exist {
    95  						break
    96  					}
    97  				}
    98  				if retry >= maxRetries {
    99  					t.Errorf("Start Failed to store message in ConfirmMap")
   100  				}
   101  			}
   102  		})
   103  	}
   104  }
   105  
   106  // TestStartHeartBeat is function to test Start() when value is passed in HeartBeatChan.
   107  func TestStartHeartBeat(t *testing.T) {
   108  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   109  
   110  	dtContexts, _ := dtcontext.InitDTContext()
   111  	heartChanStop := make(chan interface{}, 1)
   112  	heartChanPing := make(chan interface{}, 1)
   113  	heartChanStop <- "stop"
   114  	heartChanPing <- "ping"
   115  
   116  	const delay = 10 * time.Millisecond
   117  	const maxRetries = 5
   118  
   119  	tests := []struct {
   120  		name   string
   121  		Worker Worker
   122  		Group  string
   123  	}{
   124  		{
   125  			name: "StartTest-PingInHeartBeatChannel",
   126  			Worker: Worker{
   127  				HeartBeatChan: heartChanPing,
   128  				DTContexts:    dtContexts,
   129  			},
   130  			Group: "group",
   131  		},
   132  		{
   133  			name: "StartTest-StopInHeartBeatChannel",
   134  			Worker: Worker{
   135  				HeartBeatChan: heartChanStop,
   136  				DTContexts:    dtContexts,
   137  			},
   138  			Group: "group",
   139  		},
   140  	}
   141  	for _, test := range tests {
   142  		retry := 0
   143  		t.Run(test.name, func(t *testing.T) {
   144  			cw := CommWorker{
   145  				Worker: test.Worker,
   146  				Group:  test.Group,
   147  			}
   148  			go cw.Start()
   149  			if test.Worker.HeartBeatChan == heartChanPing {
   150  				for retry < maxRetries {
   151  					time.Sleep(delay)
   152  					retry++
   153  					_, exist := test.Worker.DTContexts.ModulesHealth.Load("group")
   154  					if exist {
   155  						break
   156  					}
   157  				}
   158  				if retry >= maxRetries {
   159  					t.Errorf("Start Failed to add module in beehiveContext")
   160  				}
   161  
   162  			}
   163  		})
   164  	}
   165  }
   166  
   167  // TestDealSendToCloud is function to test dealSendToCloud().
   168  func TestDealSendToCloud(t *testing.T) {
   169  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   170  
   171  	dtContextStateDisconnected, _ := dtcontext.InitDTContext()
   172  	dtContextStateConnected, _ := dtcontext.InitDTContext()
   173  	dtContextStateConnected.State = dtcommon.Connected
   174  	msg := &model.Message{
   175  		Header: model.MessageHeader{
   176  			ID: "message",
   177  		},
   178  	}
   179  
   180  	expectedMessage := &dttype.DTMessage{
   181  		Msg:    msg,
   182  		Action: dtcommon.SendToCloud,
   183  		Type:   dtcommon.CommModule,
   184  	}
   185  	tests := []struct {
   186  		name     string
   187  		context  *dtcontext.DTContext
   188  		resource string
   189  		msg      interface{}
   190  		wantErr  error
   191  	}{
   192  		{
   193  			name:    "dealSendToCloudTest-StateDisconnected",
   194  			context: dtContextStateDisconnected,
   195  			msg:     "",
   196  			wantErr: nil,
   197  		},
   198  		{
   199  			name:    "dealSendToCloudTest-StateConnected",
   200  			context: dtContextStateConnected,
   201  			msg:     "",
   202  			wantErr: errors.New("msg not Message type"),
   203  		},
   204  		{
   205  			name:    "dealSendToCloudTest-ActualMsg",
   206  			context: dtContextStateConnected,
   207  			msg:     msg,
   208  			wantErr: nil,
   209  		},
   210  	}
   211  	for _, test := range tests {
   212  		t.Run(test.name, func(t *testing.T) {
   213  			_, err := dealSendToCloud(test.context, test.resource, test.msg)
   214  			if !reflect.DeepEqual(err, test.wantErr) {
   215  				t.Errorf("dealSendToCloud() error = %v, wantErr %v", err, test.wantErr)
   216  				return
   217  			}
   218  			// Testing whether the message is properly stored in ConfirmMap of beehiveContext when correct message is passed
   219  			if err == nil && test.context.State == dtcommon.Connected {
   220  				gotMsg, exist := test.context.ConfirmMap.Load("message")
   221  				if !exist {
   222  					t.Errorf("dealSendToCloud() failed to store message in ConfirmMap")
   223  					return
   224  				}
   225  				if !reflect.DeepEqual(expectedMessage, gotMsg) {
   226  					t.Errorf("dealSendToCloud() failed due to wrong gotMsg in ConfirmMap Got =%v Want=%v", test.msg, gotMsg)
   227  				}
   228  			}
   229  		})
   230  	}
   231  }
   232  
   233  // TestDealLifeCycle is function to test dealLifeCycle().
   234  func TestDealLifeCycle(t *testing.T) {
   235  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   236  	dtContext, _ := dtcontext.InitDTContext()
   237  	tests := []struct {
   238  		name     string
   239  		context  *dtcontext.DTContext
   240  		resource string
   241  		msg      interface{}
   242  		wantErr  error
   243  	}{
   244  		{
   245  			name:    "dealLifeCycleTest-WrongMessageFormat",
   246  			context: dtContext,
   247  			msg:     "",
   248  			wantErr: errors.New("msg not Message type"),
   249  		},
   250  		{
   251  			name:    "dealLifeCycleTest-CloudConnected",
   252  			context: dtContext,
   253  			msg:     &model.Message{Content: cloudconn.CloudConnected},
   254  			wantErr: nil,
   255  		},
   256  		{
   257  			name:    "dealLifeCycleTest-CloudNotConnected",
   258  			context: dtContext,
   259  			msg:     &model.Message{Content: cloudconn.CloudDisconnected},
   260  			wantErr: nil,
   261  		},
   262  	}
   263  	for _, test := range tests {
   264  		t.Run(test.name, func(t *testing.T) {
   265  			_, err := dealLifeCycle(test.context, test.resource, test.msg)
   266  			if !reflect.DeepEqual(err, test.wantErr) {
   267  				t.Errorf("dealLifeCycle() error = %v, wantErr %v", err, test.wantErr)
   268  			}
   269  		})
   270  	}
   271  }
   272  
   273  // TestDealConfirm is function to test dealConfirm().
   274  func TestDealConfirm(t *testing.T) {
   275  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   276  	dtContext, _ := dtcontext.InitDTContext()
   277  	tests := []struct {
   278  		name     string
   279  		context  *dtcontext.DTContext
   280  		resource string
   281  		msg      interface{}
   282  		wantErr  error
   283  	}{
   284  		{
   285  			name:    "dealConfirmTest-WrongMsg",
   286  			context: dtContext,
   287  			msg:     "",
   288  			wantErr: errors.New("CommModule deal confirm, type not correct"),
   289  		},
   290  		{
   291  			name:    "dealConfirmTest-CorrectMsg",
   292  			context: dtContext,
   293  			msg:     &model.Message{Header: model.MessageHeader{ID: "id", ParentID: "parentId"}},
   294  			wantErr: nil,
   295  		},
   296  	}
   297  	for _, test := range tests {
   298  		t.Run(test.name, func(t *testing.T) {
   299  			_, err := dealConfirm(test.context, test.resource, test.msg)
   300  			if !reflect.DeepEqual(err, test.wantErr) {
   301  				t.Errorf("dealConfirm() error = %v, wantErr %v", err, test.wantErr)
   302  				return
   303  			}
   304  			if err == nil {
   305  				_, exist := test.context.ConfirmMap.Load("parentId")
   306  				if exist {
   307  					t.Errorf("dealConfirm failed() ParentMessageId still present in beehiveContext ConfirmMap")
   308  				}
   309  			}
   310  		})
   311  	}
   312  }
   313  
   314  // TestCheckConfirm is function to test checkConfirm().
   315  func TestCheckConfirm(t *testing.T) {
   316  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   317  	dtContext, _ := dtcontext.InitDTContext()
   318  	dtContext.State = dtcommon.Connected
   319  	dtContext.ConfirmMap.Store("emptyMessage", &dttype.DTMessage{})
   320  	dtContext.ConfirmMap.Store("actionMessage", &dttype.DTMessage{
   321  		Msg:    &model.Message{},
   322  		Action: dtcommon.SendToCloud,
   323  	})
   324  	tests := []struct {
   325  		name    string
   326  		Worker  Worker
   327  		context *dtcontext.DTContext
   328  		msg     interface{}
   329  	}{
   330  		{
   331  			name:    "checkConfirmTest",
   332  			Worker:  Worker{DTContexts: dtContext},
   333  			context: dtContext,
   334  			msg:     &dttype.DTMessage{Action: "action"},
   335  		},
   336  	}
   337  	for _, test := range tests {
   338  		t.Run(test.name, func(t *testing.T) {
   339  			cw := CommWorker{
   340  				Worker: test.Worker,
   341  			}
   342  			cw.checkConfirm(test.context, test.msg)
   343  			_, exist := test.context.ConfirmMap.Load("actionMessage")
   344  			if !exist {
   345  				t.Errorf(" checkconfirm() failed because dealSendToCloud() failed to store message in ConfirmMap")
   346  				return
   347  			}
   348  		})
   349  	}
   350  }