github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/cluster/calcium/node_test.go (about)

     1  package calcium
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/projecteru2/core/engine/factory"
    10  	enginemocks "github.com/projecteru2/core/engine/mocks"
    11  	enginetypes "github.com/projecteru2/core/engine/types"
    12  	lockmocks "github.com/projecteru2/core/lock/mocks"
    13  	resourcemocks "github.com/projecteru2/core/resource/mocks"
    14  	plugintypes "github.com/projecteru2/core/resource/plugins/types"
    15  	resourcetypes "github.com/projecteru2/core/resource/types"
    16  	storemocks "github.com/projecteru2/core/store/mocks"
    17  	"github.com/projecteru2/core/types"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/mock"
    21  )
    22  
    23  func TestAddNode(t *testing.T) {
    24  	c := NewTestCluster()
    25  	ctx := context.Background()
    26  	factory.InitEngineCache(ctx, c.config, nil)
    27  
    28  	opts := &types.AddNodeOptions{}
    29  	// failed by validating
    30  	_, err := c.AddNode(ctx, opts)
    31  	assert.Error(t, err)
    32  
    33  	nodename := "nodename"
    34  	podname := "podname"
    35  	opts.Nodename = nodename
    36  	opts.Podname = podname
    37  	opts.Endpoint = fmt.Sprintf("mock://%s", nodename)
    38  
    39  	// failed by rmgr.AddNode
    40  	rmgr := c.rmgr.(*resourcemocks.Manager)
    41  	rmgr.On("AddNode", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
    42  	_, err = c.AddNode(ctx, opts)
    43  	assert.Error(t, err)
    44  	rmgr.AssertExpectations(t)
    45  	rmgr.On("AddNode", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
    46  		resourcetypes.Resources{}, nil)
    47  	rmgr.On("RemoveNode", mock.Anything, mock.Anything).Return(nil)
    48  
    49  	// failed by store.AddNode
    50  	store := c.store.(*storemocks.Store)
    51  	store.On("AddNode", mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
    52  	_, err = c.AddNode(ctx, opts)
    53  	assert.Error(t, err)
    54  	store.AssertExpectations(t)
    55  	name := "test"
    56  	node := &types.Node{
    57  		NodeMeta: types.NodeMeta{
    58  			Name:     name,
    59  			Endpoint: "endpoint",
    60  		},
    61  	}
    62  	store.On("AddNode", mock.Anything, mock.Anything).Return(node, nil)
    63  	rmgr.On("GetNodeMetrics", mock.Anything, mock.Anything).Return([]*plugintypes.Metrics{}, nil)
    64  	n, err := c.AddNode(ctx, opts)
    65  	assert.NoError(t, err)
    66  	assert.Equal(t, n.Name, name)
    67  }
    68  
    69  func TestRemoveNode(t *testing.T) {
    70  	c := NewTestCluster()
    71  	ctx := context.Background()
    72  	store := c.store.(*storemocks.Store)
    73  
    74  	lock := &lockmocks.DistributedLock{}
    75  	lock.On("Lock", mock.Anything).Return(ctx, nil)
    76  	lock.On("Unlock", mock.Anything).Return(nil)
    77  	store.On("CreateLock", mock.Anything, mock.Anything).Return(lock, nil)
    78  	name := "test"
    79  	node := &types.Node{NodeMeta: types.NodeMeta{Name: name}}
    80  	store.On("GetNode", mock.Anything, mock.Anything).Return(node, nil)
    81  
    82  	// fail, ListNodeWorkloads fail
    83  	store.On("ListNodeWorkloads", mock.Anything, mock.Anything, mock.Anything).Return([]*types.Workload{}, types.ErrMockError).Once()
    84  	assert.Error(t, c.RemoveNode(ctx, name))
    85  
    86  	// fail, node still has associated workloads
    87  	store.On("ListNodeWorkloads", mock.Anything, mock.Anything, mock.Anything).Return([]*types.Workload{{}}, nil).Once()
    88  	assert.Error(t, c.RemoveNode(ctx, name))
    89  	store.AssertExpectations(t)
    90  
    91  	// fail by store.RemoveNode
    92  	store.On("ListNodeWorkloads", mock.Anything, mock.Anything, mock.Anything).Return([]*types.Workload{}, nil)
    93  	store.On("RemoveNode", mock.Anything, mock.Anything).Return(types.ErrMockError).Once()
    94  	assert.Error(t, c.RemoveNode(ctx, name))
    95  
    96  	// success
    97  	store.On("RemoveNode", mock.Anything, mock.Anything).Return(nil)
    98  	rmgr := c.rmgr.(*resourcemocks.Manager)
    99  	rmgr.On("RemoveNode", mock.Anything, mock.Anything).Return(nil)
   100  	assert.NoError(t, c.RemoveNode(ctx, name))
   101  	store.AssertExpectations(t)
   102  	rmgr.AssertExpectations(t)
   103  }
   104  
   105  func TestListPodNodes(t *testing.T) {
   106  	c := NewTestCluster()
   107  	ctx := context.Background()
   108  
   109  	opts := &types.ListNodesOptions{}
   110  	store := c.store.(*storemocks.Store)
   111  	// failed by GetNodesByPod
   112  	store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
   113  	_, err := c.ListPodNodes(ctx, opts)
   114  	assert.Error(t, err)
   115  	store.AssertExpectations(t)
   116  
   117  	// success
   118  	engine := &enginemocks.API{}
   119  	engine.On("Info", mock.Anything).Return(nil, types.ErrMockError)
   120  	name1 := "test1"
   121  	name2 := "test2"
   122  	nodes := []*types.Node{
   123  		{NodeMeta: types.NodeMeta{Name: name1}, Engine: engine, Available: true},
   124  		{NodeMeta: types.NodeMeta{Name: name2}, Engine: engine, Available: false},
   125  	}
   126  	store.On("GetNodesByPod", mock.Anything, mock.Anything, mock.Anything).Return(nodes, nil)
   127  	rmgr := c.rmgr.(*resourcemocks.Manager)
   128  	rmgr.On("GetNodeResourceInfo", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil, types.ErrMockError)
   129  	opts.CallInfo = true
   130  
   131  	ns, err := c.ListPodNodes(ctx, &types.ListNodesOptions{})
   132  	assert.NoError(t, err)
   133  	cnt := 0
   134  	for range ns {
   135  		cnt++
   136  	}
   137  	assert.Equal(t, cnt, 2)
   138  	rmgr.AssertExpectations(t)
   139  	store.AssertExpectations(t)
   140  }
   141  
   142  func TestGetNode(t *testing.T) {
   143  	c := NewTestCluster()
   144  	ctx := context.Background()
   145  	// fail by validating
   146  	_, err := c.GetNode(ctx, "")
   147  	assert.Error(t, err)
   148  	nodename := "test"
   149  
   150  	// failed by store.GetNode
   151  	store := c.store.(*storemocks.Store)
   152  	store.On("GetNode", mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
   153  	_, err = c.GetNode(ctx, nodename)
   154  	assert.Error(t, err)
   155  
   156  	node := &types.Node{
   157  		NodeMeta: types.NodeMeta{Name: nodename},
   158  	}
   159  	store.On("GetNode", mock.Anything, mock.Anything).Return(node, nil)
   160  
   161  	// failed by GetNodeResourceInfo
   162  	rmgr := c.rmgr.(*resourcemocks.Manager)
   163  	rmgr.On("GetNodeResourceInfo", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil, types.ErrMockError).Once()
   164  	_, err = c.GetNode(ctx, nodename)
   165  	assert.Error(t, err)
   166  
   167  	rmgr.On("GetNodeResourceInfo", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil, nil)
   168  
   169  	// success
   170  	node, err = c.GetNode(ctx, nodename)
   171  	assert.NoError(t, err)
   172  	assert.Equal(t, node.Name, nodename)
   173  
   174  	rmgr.AssertExpectations(t)
   175  	store.AssertExpectations(t)
   176  }
   177  
   178  func TestGetNodeEngine(t *testing.T) {
   179  	c := NewTestCluster()
   180  	ctx := context.Background()
   181  
   182  	// fail by validating
   183  	_, err := c.GetNodeEngineInfo(ctx, "")
   184  	assert.Error(t, err)
   185  	nodename := "test"
   186  
   187  	// fail by store.GetNode
   188  	store := c.store.(*storemocks.Store)
   189  	store.On("GetNode", mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
   190  	_, err = c.GetNode(ctx, nodename)
   191  	assert.Error(t, err)
   192  
   193  	// success
   194  	engine := &enginemocks.API{}
   195  	engine.On("Info", mock.Anything).Return(&enginetypes.Info{Type: "fake"}, nil)
   196  	node := &types.Node{
   197  		NodeMeta: types.NodeMeta{Name: nodename},
   198  		Engine:   engine,
   199  	}
   200  	store.On("GetNode", mock.Anything, mock.Anything).Return(node, nil)
   201  
   202  	e, err := c.GetNodeEngineInfo(ctx, nodename)
   203  	assert.NoError(t, err)
   204  	assert.Equal(t, e.Type, "fake")
   205  	store.AssertExpectations(t)
   206  }
   207  
   208  func TestSetNode(t *testing.T) {
   209  	c := NewTestCluster()
   210  	ctx := context.Background()
   211  
   212  	opts := &types.SetNodeOptions{}
   213  
   214  	// failed by validating
   215  	_, err := c.SetNode(ctx, opts)
   216  	assert.Error(t, err)
   217  
   218  	store := c.store.(*storemocks.Store)
   219  	lock := &lockmocks.DistributedLock{}
   220  	lock.On("Lock", mock.Anything).Return(ctx, nil)
   221  	lock.On("Unlock", mock.Anything).Return(nil)
   222  	store.On("CreateLock", mock.Anything, mock.Anything).Return(lock, nil)
   223  	name := "test"
   224  	opts.Nodename = name
   225  	node := &types.Node{NodeMeta: types.NodeMeta{Name: name}}
   226  	store.On("GetNode", mock.Anything, mock.Anything).Return(node, nil)
   227  
   228  	// failed by GetNodeResourceInfo
   229  	rmgr := c.rmgr.(*resourcemocks.Manager)
   230  	rmgr.On("GetNodeResourceInfo", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil, types.ErrMockError).Once()
   231  	_, err = c.SetNode(ctx, opts)
   232  	assert.Error(t, err)
   233  	rmgr.On("GetNodeResourceInfo", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil, nil)
   234  
   235  	// for bypass
   236  	opts.Bypass = types.TriTrue
   237  	opts.WorkloadsDown = true
   238  	// for setAllWorkloadsOnNodeDown
   239  	workloads := []*types.Workload{{ID: "1", Name: "wrong_name"}, {ID: "2", Name: "a_b_c"}}
   240  	store.On("ListNodeWorkloads", mock.Anything, mock.Anything, mock.Anything).Return(workloads, nil)
   241  	store.On("SetWorkloadStatus", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   242  
   243  	// for set endpoint
   244  	endpoint := "mock://test2"
   245  	opts.Endpoint = endpoint
   246  
   247  	// for labels update
   248  	labels := map[string]string{"a": "1", "b": "2"}
   249  	opts.Labels = labels
   250  
   251  	// failed by SetNodeResourceCapacity
   252  	opts.Resources = resourcetypes.Resources{"a": {"a": 1}}
   253  	rmgr.On("SetNodeResourceCapacity", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
   254  		nil, nil, types.ErrMockError,
   255  	).Once()
   256  	_, err = c.SetNode(ctx, opts)
   257  	assert.Error(t, err)
   258  	rmgr.On("SetNodeResourceCapacity", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
   259  		nil, nil, nil,
   260  	)
   261  
   262  	// rollback
   263  	store.On("UpdateNodes", mock.Anything, mock.Anything).Return(types.ErrMockError).Once()
   264  	_, err = c.SetNode(ctx, opts)
   265  	assert.Error(t, err)
   266  	store.On("UpdateNodes", mock.Anything, mock.Anything).Return(nil)
   267  	rmgr.On("GetNodeMetrics", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]*plugintypes.Metrics{}, nil)
   268  
   269  	// done
   270  	node, err = c.SetNode(ctx, opts)
   271  	assert.NoError(t, err)
   272  	assert.Equal(t, node.Endpoint, endpoint)
   273  	assert.Equal(t, labels["a"], node.Labels["a"])
   274  	store.AssertExpectations(t)
   275  	time.Sleep(100 * time.Millisecond) // for send metrics testing
   276  	rmgr.AssertExpectations(t)
   277  }
   278  
   279  func TestFilterNodes(t *testing.T) {
   280  	c := NewTestCluster()
   281  	ctx := context.Background()
   282  	store := c.store.(*storemocks.Store)
   283  
   284  	// failed by GetNode
   285  	nf := &types.NodeFilter{Includes: []string{"test"}}
   286  	store.On("GetNode", mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
   287  	_, err := c.filterNodes(ctx, nf)
   288  	assert.Error(t, err)
   289  
   290  	// succ by GetNode
   291  	node1 := &types.Node{NodeMeta: types.NodeMeta{Name: "0"}}
   292  	store.On("GetNode", mock.Anything, mock.Anything).Return(node1, nil)
   293  	ns, err := c.filterNodes(ctx, nf)
   294  	assert.NoError(t, err)
   295  	assert.Len(t, ns, 1)
   296  
   297  	// failed by GetNodesByPod
   298  	nf.Includes = []string{}
   299  	store.On("GetNodesByPod", mock.Anything, mock.Anything).Return(nil, types.ErrMockError).Once()
   300  	_, err = c.filterNodes(ctx, nf)
   301  	assert.Error(t, err)
   302  
   303  	nodes := []*types.Node{
   304  		{
   305  			NodeMeta: types.NodeMeta{Name: "A"},
   306  		},
   307  		{
   308  			NodeMeta: types.NodeMeta{Name: "B"},
   309  		},
   310  		{
   311  			NodeMeta: types.NodeMeta{Name: "C"},
   312  		},
   313  		{
   314  			NodeMeta: types.NodeMeta{Name: "D"},
   315  		},
   316  	}
   317  	store.On("GetNodesByPod", mock.Anything, mock.Anything).Return(nodes, nil)
   318  
   319  	// no excludes
   320  	ns, err = c.filterNodes(ctx, nf)
   321  	assert.NoError(t, err)
   322  	assert.Len(t, ns, 4)
   323  
   324  	// excludes
   325  	nf.Excludes = []string{"A", "C"}
   326  	ns, err = c.filterNodes(ctx, nf)
   327  	assert.NoError(t, err)
   328  	assert.Len(t, ns, 2)
   329  }