github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/edgehub/process_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 edgehub
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"reflect"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/golang/mock/gomock"
    27  
    28  	"github.com/kubeedge/beehive/pkg/core"
    29  	beehiveContext "github.com/kubeedge/beehive/pkg/core/context"
    30  	"github.com/kubeedge/beehive/pkg/core/model"
    31  	"github.com/kubeedge/kubeedge/edge/mocks/edgehub"
    32  	module "github.com/kubeedge/kubeedge/edge/pkg/common/modules"
    33  	"github.com/kubeedge/kubeedge/edge/pkg/edgehub/config"
    34  )
    35  
    36  //TestAddKeepChannel() tests the addition of channel to the syncKeeper
    37  func TestAddKeepChannel(t *testing.T) {
    38  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
    39  	tests := []struct {
    40  		name  string
    41  		hub   *EdgeHub
    42  		msgID string
    43  	}{
    44  		{
    45  			name: "Adding a valid keep channel",
    46  			hub: &EdgeHub{
    47  				syncKeeper: make(map[string]chan model.Message),
    48  			},
    49  			msgID: "test",
    50  		},
    51  	}
    52  	for _, tt := range tests {
    53  		t.Run(tt.name, func(t *testing.T) {
    54  			got := tt.hub.addKeepChannel(tt.msgID)
    55  			if !reflect.DeepEqual(tt.hub.syncKeeper[tt.msgID], got) {
    56  				t.Errorf("TestController_addKeepChannel() = %v, want %v", got, tt.hub.syncKeeper[tt.msgID])
    57  			}
    58  		})
    59  	}
    60  }
    61  
    62  //TestDeleteKeepChannel() tests the deletion of channel in the syncKeeper
    63  func TestDeleteKeepChannel(t *testing.T) {
    64  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
    65  	tests := []struct {
    66  		name  string
    67  		hub   *EdgeHub
    68  		msgID string
    69  	}{
    70  		{
    71  			name: "Deleting a valid keep channel",
    72  			hub: &EdgeHub{
    73  				syncKeeper: make(map[string]chan model.Message),
    74  			},
    75  			msgID: "test",
    76  		},
    77  	}
    78  	for _, tt := range tests {
    79  		t.Run(tt.name, func(t *testing.T) {
    80  			tt.hub.addKeepChannel(tt.msgID)
    81  			tt.hub.deleteKeepChannel(tt.msgID)
    82  			if _, exist := tt.hub.syncKeeper[tt.msgID]; exist {
    83  				t.Errorf("TestController_deleteKeepChannel = %v, want %v", tt.hub.syncKeeper[tt.msgID], nil)
    84  			}
    85  		})
    86  	}
    87  }
    88  
    89  //TestIsSyncResponse() tests whether there exists a channel with the given message_id in the syncKeeper
    90  func TestIsSyncResponse(t *testing.T) {
    91  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
    92  	tests := []struct {
    93  		name  string
    94  		hub   *EdgeHub
    95  		msgID string
    96  		want  bool
    97  	}{
    98  		{
    99  			name: "Sync message response case",
   100  			hub: &EdgeHub{
   101  				syncKeeper: make(map[string]chan model.Message),
   102  			},
   103  			msgID: "test",
   104  			want:  true,
   105  		},
   106  		{
   107  			name: "Non sync message response  case",
   108  			hub: &EdgeHub{
   109  				syncKeeper: make(map[string]chan model.Message),
   110  			},
   111  			msgID: "",
   112  			want:  false,
   113  		},
   114  	}
   115  	for _, tt := range tests {
   116  		t.Run(tt.name, func(t *testing.T) {
   117  			if tt.want {
   118  				tt.hub.addKeepChannel(tt.msgID)
   119  			}
   120  			if got := tt.hub.isSyncResponse(tt.msgID); got != tt.want {
   121  				t.Errorf("TestController_isSyncResponse() = %v, want %v", got, tt.want)
   122  			}
   123  		})
   124  	}
   125  }
   126  
   127  //TestSendToKeepChannel() tests the reception of response in the syncKeep channel
   128  func TestSendToKeepChannel(t *testing.T) {
   129  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   130  	message := model.NewMessage("test_id")
   131  	tests := []struct {
   132  		name                string
   133  		hub                 *EdgeHub
   134  		message             *model.Message
   135  		keepChannelParentID string
   136  		expectedError       error
   137  	}{
   138  		{
   139  			name: "SyncKeeper Error Case in send to keep channel",
   140  			hub: &EdgeHub{
   141  				syncKeeper: make(map[string]chan model.Message),
   142  			},
   143  			message:             message,
   144  			keepChannelParentID: "wrong_id",
   145  			expectedError:       fmt.Errorf("failed to get sync keeper channel, messageID:%+v", *message),
   146  		},
   147  		{
   148  			name: "Negative Test Case without syncKeeper Error ",
   149  			hub: &EdgeHub{
   150  				syncKeeper: make(map[string]chan model.Message),
   151  			},
   152  			message:             model.NewMessage("test_id"),
   153  			keepChannelParentID: "test_id",
   154  			expectedError:       fmt.Errorf("failed to send message to sync keep channel"),
   155  		},
   156  		{
   157  			name: "Send to keep channel with valid input",
   158  			hub: &EdgeHub{
   159  				syncKeeper: make(map[string]chan model.Message),
   160  			},
   161  			message:             model.NewMessage("test_id"),
   162  			keepChannelParentID: "test_id",
   163  			expectedError:       nil},
   164  	}
   165  	for _, tt := range tests {
   166  		t.Run(tt.name, func(t *testing.T) {
   167  			keep := tt.hub.addKeepChannel(tt.keepChannelParentID)
   168  			if tt.expectedError == nil {
   169  				receive := func() {
   170  					<-keep
   171  				}
   172  				go receive()
   173  			}
   174  			time.Sleep(1 * time.Second)
   175  			err := tt.hub.sendToKeepChannel(*tt.message)
   176  			if !reflect.DeepEqual(err, tt.expectedError) {
   177  				t.Errorf("TestController_sendToKeepChannel() error = %v, expectedError %v", err, tt.expectedError)
   178  			}
   179  		})
   180  	}
   181  }
   182  
   183  //TestDispatch() tests whether the messages are properly dispatched to their respective modules
   184  func TestDispatch(t *testing.T) {
   185  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   186  	tests := []struct {
   187  		name          string
   188  		hub           *EdgeHub
   189  		message       *model.Message
   190  		expectedError error
   191  		isResponse    bool
   192  	}{
   193  		{
   194  			name: "dispatch with valid input",
   195  			hub: &EdgeHub{
   196  				syncKeeper: make(map[string]chan model.Message),
   197  			},
   198  			message:       model.NewMessage("").BuildRouter(ModuleNameEdgeHub, module.TwinGroup, "", ""),
   199  			expectedError: nil,
   200  			isResponse:    false,
   201  		},
   202  		{
   203  			name: "Error Case in dispatch",
   204  			hub: &EdgeHub{
   205  				syncKeeper: make(map[string]chan model.Message),
   206  			},
   207  			message:       model.NewMessage("test").BuildRouter(ModuleNameEdgeHub, module.EdgedGroup, "", ""),
   208  			expectedError: fmt.Errorf("msg_group not found"),
   209  			isResponse:    true,
   210  		},
   211  		{
   212  			name: "Response Case in dispatch",
   213  			hub: &EdgeHub{
   214  				syncKeeper: make(map[string]chan model.Message),
   215  			},
   216  			message:       model.NewMessage("test").BuildRouter(ModuleNameEdgeHub, module.TwinGroup, "", ""),
   217  			expectedError: nil,
   218  			isResponse:    true,
   219  		},
   220  	}
   221  	for _, tt := range tests {
   222  		t.Run(tt.name, func(t *testing.T) {
   223  			if tt.expectedError == nil && !tt.isResponse {
   224  				receive := func() {
   225  					keepChannel := tt.hub.addKeepChannel(tt.message.GetParentID())
   226  					<-keepChannel
   227  				}
   228  				go receive()
   229  			}
   230  			time.Sleep(1 * time.Second)
   231  			err := tt.hub.dispatch(*tt.message)
   232  			if !reflect.DeepEqual(err, tt.expectedError) {
   233  				t.Errorf("TestController_dispatch() error = %v, wantErr %v", err, tt.expectedError)
   234  			}
   235  		})
   236  	}
   237  }
   238  
   239  //TestRouteToEdge() is used to test whether the message received from websocket is dispatched to the required modules
   240  func TestRouteToEdge(t *testing.T) {
   241  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   242  	mockCtrl := gomock.NewController(t)
   243  	defer mockCtrl.Finish()
   244  	mockAdapter := edgehub.NewMockAdapter(mockCtrl)
   245  	hub := newEdgeHub(true)
   246  	hub.chClient = mockAdapter
   247  
   248  	tests := []struct {
   249  		name         string
   250  		hub          *EdgeHub
   251  		receiveTimes int
   252  	}{
   253  		{
   254  			name:         "Route to edge with proper input",
   255  			hub:          hub,
   256  			receiveTimes: 0,
   257  		},
   258  		{
   259  			name:         "Receive Error in route to edge",
   260  			hub:          hub,
   261  			receiveTimes: 1,
   262  		},
   263  	}
   264  	for _, tt := range tests {
   265  		t.Run(tt.name, func(t *testing.T) {
   266  			mockAdapter.EXPECT().Receive().Return(*model.NewMessage("test").BuildRouter(ModuleNameEdgeHub, module.EdgedGroup, "", ""), nil).Times(tt.receiveTimes)
   267  			mockAdapter.EXPECT().Receive().Return(*model.NewMessage("test").BuildRouter(ModuleNameEdgeHub, module.TwinGroup, "", ""), nil).Times(tt.receiveTimes)
   268  			mockAdapter.EXPECT().Receive().Return(*model.NewMessage(""), errors.New("Connection Refused")).Times(1)
   269  			go tt.hub.routeToEdge()
   270  			stop := <-tt.hub.reconnectChan
   271  			if stop != struct{}{} {
   272  				t.Errorf("TestRouteToEdge error got: %v want: %v", stop, struct{}{})
   273  			}
   274  		})
   275  	}
   276  }
   277  
   278  //TestSendToCloud() tests whether the send to cloud functionality works properly
   279  func TestSendToCloud(t *testing.T) {
   280  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   281  	mockCtrl := gomock.NewController(t)
   282  	defer mockCtrl.Finish()
   283  	mockAdapter := edgehub.NewMockAdapter(mockCtrl)
   284  
   285  	msg := model.NewMessage("").BuildHeader("test_id", "", 1)
   286  	msg.Header.Sync = true
   287  	tests := []struct {
   288  		name            string
   289  		hub             *EdgeHub
   290  		message         model.Message
   291  		expectedError   error
   292  		waitError       bool
   293  		mockError       error
   294  		HeartbeatPeriod int32
   295  	}{
   296  		{
   297  			name: "send to cloud with proper input",
   298  			hub: &EdgeHub{
   299  				chClient:   mockAdapter,
   300  				syncKeeper: make(map[string]chan model.Message),
   301  			},
   302  			HeartbeatPeriod: 6,
   303  			message:         *msg,
   304  			expectedError:   nil,
   305  			waitError:       false,
   306  			mockError:       nil,
   307  		},
   308  		{
   309  			name: "Wait Error in send to cloud",
   310  			hub: &EdgeHub{
   311  				chClient:   mockAdapter,
   312  				syncKeeper: make(map[string]chan model.Message),
   313  			},
   314  			HeartbeatPeriod: 3,
   315  			message:         *msg,
   316  			expectedError:   nil,
   317  			waitError:       true,
   318  			mockError:       nil,
   319  		},
   320  		{
   321  			name: "Send Failure in send to cloud",
   322  			hub: &EdgeHub{
   323  				chClient:   mockAdapter,
   324  				syncKeeper: make(map[string]chan model.Message),
   325  			},
   326  			HeartbeatPeriod: 3,
   327  			message:         model.Message{},
   328  			expectedError:   fmt.Errorf("failed to send message, error: Connection Refused"),
   329  			waitError:       false,
   330  			mockError:       errors.New("Connection Refused"),
   331  		},
   332  	}
   333  	for _, tt := range tests {
   334  		t.Run(tt.name, func(t *testing.T) {
   335  			mockAdapter.EXPECT().Send(gomock.Any()).Return(tt.mockError).Times(1)
   336  			config.Config.Heartbeat = tt.HeartbeatPeriod
   337  			if !tt.waitError && tt.expectedError == nil {
   338  				go tt.hub.sendToCloud(tt.message)
   339  				time.Sleep(1 * time.Second)
   340  				tempChannel := tt.hub.syncKeeper["test_id"]
   341  				tempChannel <- *model.NewMessage("test_id")
   342  				time.Sleep(1 * time.Second)
   343  				if _, exist := tt.hub.syncKeeper["test_id"]; exist {
   344  					t.Errorf("SendToCloud() error in receiving message")
   345  				}
   346  				return
   347  			}
   348  			err := tt.hub.sendToCloud(tt.message)
   349  			if !reflect.DeepEqual(err, tt.expectedError) {
   350  				t.Errorf("SendToCloud() error = %v, wantErr %v", err, tt.expectedError)
   351  			}
   352  			time.Sleep(time.Duration(tt.HeartbeatPeriod+2) * time.Second)
   353  			if _, exist := tt.hub.syncKeeper["test_id"]; exist {
   354  				t.Errorf("SendToCloud() error in waiting for timeout")
   355  			}
   356  		})
   357  	}
   358  }
   359  
   360  //TestRouteToCloud() tests the reception of the message from the beehive framework and forwarding of that message to cloud
   361  func TestRouteToCloud(t *testing.T) {
   362  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   363  	mockCtrl := gomock.NewController(t)
   364  	defer mockCtrl.Finish()
   365  	mockAdapter := edgehub.NewMockAdapter(mockCtrl)
   366  	hub := newEdgeHub(true)
   367  	hub.chClient = mockAdapter
   368  
   369  	tests := []struct {
   370  		name string
   371  		hub  *EdgeHub
   372  	}{
   373  		{
   374  			name: "Route to cloud with valid input",
   375  			hub:  hub,
   376  		},
   377  	}
   378  	for _, tt := range tests {
   379  		t.Run(tt.name, func(t *testing.T) {
   380  			mockAdapter.EXPECT().Send(gomock.Any()).Return(errors.New("Connection Refused")).AnyTimes()
   381  			go tt.hub.routeToCloud()
   382  			time.Sleep(2 * time.Second)
   383  			core.Register(&EdgeHub{})
   384  			beehiveContext.AddModule(ModuleNameEdgeHub)
   385  			msg := model.NewMessage("").BuildHeader("test_id", "", 1)
   386  			beehiveContext.Send(ModuleNameEdgeHub, *msg)
   387  			stopChan := <-tt.hub.reconnectChan
   388  			if stopChan != struct{}{} {
   389  				t.Errorf("Error in route to cloud")
   390  			}
   391  		})
   392  	}
   393  }
   394  
   395  //TestKeepalive() tests whether ping message sent to the cloud at regular intervals happens properly
   396  func TestKeepalive(t *testing.T) {
   397  	CertFile := "/tmp/kubeedge/certs/edge.crt"
   398  	KeyFile := "/tmp/kubeedge/certs/edge.key"
   399  	beehiveContext.InitContext(beehiveContext.MsgCtxTypeChannel)
   400  	mockCtrl := gomock.NewController(t)
   401  	defer mockCtrl.Finish()
   402  	mockAdapter := edgehub.NewMockAdapter(mockCtrl)
   403  	tests := []struct {
   404  		name string
   405  		hub  *EdgeHub
   406  	}{
   407  		{
   408  			name: "Heartbeat failure Case",
   409  			hub: &EdgeHub{
   410  				chClient:      mockAdapter,
   411  				reconnectChan: make(chan struct{}),
   412  			},
   413  		},
   414  	}
   415  	edgeHubConfig := config.Config
   416  	edgeHubConfig.TLSCertFile = CertFile
   417  	edgeHubConfig.TLSPrivateKeyFile = KeyFile
   418  
   419  	for _, tt := range tests {
   420  		t.Run(tt.name, func(t *testing.T) {
   421  			mockAdapter.EXPECT().Send(gomock.Any()).Return(nil).Times(1)
   422  			mockAdapter.EXPECT().Send(gomock.Any()).Return(errors.New("Connection Refused")).Times(1)
   423  			go tt.hub.keepalive()
   424  			got := <-tt.hub.reconnectChan
   425  			if got != struct{}{} {
   426  				t.Errorf("TestKeepalive() StopChan = %v, want %v", got, struct{}{})
   427  			}
   428  		})
   429  	}
   430  }