github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/watchapi/watch_test.go (about)

     1  package watchapi
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/docker/swarmkit/api"
     8  	"github.com/docker/swarmkit/manager/state/store"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestWatch(t *testing.T) {
    14  	ts := newTestServer(t)
    15  	defer ts.Stop()
    16  
    17  	ctx := context.Background()
    18  
    19  	// Watch for node creates
    20  	watch, err := ts.Client.Watch(ctx, &api.WatchRequest{
    21  		Entries: []*api.WatchRequest_WatchEntry{
    22  			{
    23  				Kind:   "node",
    24  				Action: api.WatchActionKindCreate,
    25  			},
    26  		},
    27  	})
    28  	assert.NoError(t, err)
    29  
    30  	// Should receive an initial message that indicates the watch is ready
    31  	msg, err := watch.Recv()
    32  	assert.NoError(t, err)
    33  	assert.Equal(t, &api.WatchMessage{}, msg)
    34  
    35  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
    36  	msg, err = watch.Recv()
    37  	assert.NoError(t, err)
    38  	assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action)
    39  	require.NotNil(t, msg.Events[0].Object.GetNode())
    40  	assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID)
    41  
    42  	watch.CloseSend()
    43  
    44  	// Watch for node creates that match a name prefix and a custom index, or
    45  	// are managers
    46  	watch, err = ts.Client.Watch(ctx, &api.WatchRequest{
    47  		Entries: []*api.WatchRequest_WatchEntry{
    48  			{
    49  				Kind:   "node",
    50  				Action: api.WatchActionKindCreate,
    51  				Filters: []*api.SelectBy{
    52  					{
    53  						By: &api.SelectBy_NamePrefix{
    54  							NamePrefix: "east",
    55  						},
    56  					},
    57  					{
    58  						By: &api.SelectBy_Custom{
    59  							Custom: &api.SelectByCustom{
    60  								Index: "myindex",
    61  								Value: "myval",
    62  							},
    63  						},
    64  					},
    65  				},
    66  			},
    67  			{
    68  				Kind:   "node",
    69  				Action: api.WatchActionKindCreate,
    70  				Filters: []*api.SelectBy{
    71  					{
    72  						By: &api.SelectBy_Role{
    73  							Role: api.NodeRoleManager,
    74  						},
    75  					},
    76  				},
    77  			},
    78  		},
    79  	})
    80  	assert.NoError(t, err)
    81  
    82  	// Should receive an initial message that indicates the watch is ready
    83  	msg, err = watch.Recv()
    84  	assert.NoError(t, err)
    85  	assert.Equal(t, &api.WatchMessage{}, msg)
    86  
    87  	createNode(t, ts, "id2", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
    88  	msg, err = watch.Recv()
    89  	assert.NoError(t, err)
    90  	assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action)
    91  	require.NotNil(t, msg.Events[0].Object.GetNode())
    92  	assert.Equal(t, "id2", msg.Events[0].Object.GetNode().ID)
    93  
    94  	// Shouldn't be seen by the watch
    95  	createNode(t, ts, "id3", api.NodeRoleWorker, api.NodeMembershipAccepted, api.NodeStatus_READY)
    96  
    97  	// Shouldn't be seen either - no hostname
    98  	node := &api.Node{
    99  		ID: "id4",
   100  		Spec: api.NodeSpec{
   101  			Annotations: api.Annotations{
   102  				Indices: []api.IndexEntry{
   103  					{Key: "myindex", Val: "myval"},
   104  				},
   105  			},
   106  		},
   107  		Role: api.NodeRoleWorker,
   108  	}
   109  	err = ts.Store.Update(func(tx store.Tx) error {
   110  		return store.CreateNode(tx, node)
   111  	})
   112  	assert.NoError(t, err)
   113  
   114  	// Shouldn't be seen either - hostname doesn't match filter
   115  	node = &api.Node{
   116  		ID: "id5",
   117  		Description: &api.NodeDescription{
   118  			Hostname: "west-40",
   119  		},
   120  		Spec: api.NodeSpec{
   121  			Annotations: api.Annotations{
   122  				Indices: []api.IndexEntry{
   123  					{Key: "myindex", Val: "myval"},
   124  				},
   125  			},
   126  		},
   127  		Role: api.NodeRoleWorker,
   128  	}
   129  	err = ts.Store.Update(func(tx store.Tx) error {
   130  		return store.CreateNode(tx, node)
   131  	})
   132  	assert.NoError(t, err)
   133  
   134  	// This one should be seen
   135  	node = &api.Node{
   136  		ID: "id6",
   137  		Description: &api.NodeDescription{
   138  			Hostname: "east-95",
   139  		},
   140  		Spec: api.NodeSpec{
   141  			Annotations: api.Annotations{
   142  				Indices: []api.IndexEntry{
   143  					{Key: "myindex", Val: "myval"},
   144  				},
   145  			},
   146  		},
   147  		Role: api.NodeRoleWorker,
   148  	}
   149  	err = ts.Store.Update(func(tx store.Tx) error {
   150  		return store.CreateNode(tx, node)
   151  	})
   152  	assert.NoError(t, err)
   153  
   154  	msg, err = watch.Recv()
   155  	assert.NoError(t, err)
   156  	assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action)
   157  	require.NotNil(t, msg.Events[0].Object.GetNode())
   158  	assert.Equal(t, "id6", msg.Events[0].Object.GetNode().ID)
   159  
   160  	watch.CloseSend()
   161  }
   162  
   163  func TestWatchMultipleActions(t *testing.T) {
   164  	ts := newTestServer(t)
   165  	defer ts.Stop()
   166  
   167  	ctx := context.Background()
   168  
   169  	// Watch for node creates
   170  	watch, err := ts.Client.Watch(ctx, &api.WatchRequest{
   171  		Entries: []*api.WatchRequest_WatchEntry{
   172  			{
   173  				Kind:   "node",
   174  				Action: api.WatchActionKindCreate | api.WatchActionKindRemove,
   175  			},
   176  		},
   177  	})
   178  	assert.NoError(t, err)
   179  
   180  	// Should receive an initial message that indicates the watch is ready
   181  	msg, err := watch.Recv()
   182  	assert.NoError(t, err)
   183  	assert.Equal(t, &api.WatchMessage{}, msg)
   184  
   185  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   186  	msg, err = watch.Recv()
   187  	assert.NoError(t, err)
   188  	assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action)
   189  	require.NotNil(t, msg.Events[0].Object.GetNode())
   190  	assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID)
   191  
   192  	// Update should not be seen
   193  	err = ts.Store.Update(func(tx store.Tx) error {
   194  		node := store.GetNode(tx, "id1")
   195  		require.NotNil(t, node)
   196  		node.Role = api.NodeRoleWorker
   197  		return store.UpdateNode(tx, node)
   198  	})
   199  	assert.NoError(t, err)
   200  
   201  	// Delete should be seen
   202  	err = ts.Store.Update(func(tx store.Tx) error {
   203  		return store.DeleteNode(tx, "id1")
   204  	})
   205  	assert.NoError(t, err)
   206  	msg, err = watch.Recv()
   207  	assert.NoError(t, err)
   208  	assert.Equal(t, api.WatchActionKindRemove, msg.Events[0].Action)
   209  	require.NotNil(t, msg.Events[0].Object.GetNode())
   210  	assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID)
   211  
   212  	watch.CloseSend()
   213  }
   214  
   215  func TestWatchIncludeOldObject(t *testing.T) {
   216  	ts := newTestServer(t)
   217  	defer ts.Stop()
   218  
   219  	ctx := context.Background()
   220  
   221  	// Watch for node updates
   222  	watch, err := ts.Client.Watch(ctx, &api.WatchRequest{
   223  		Entries: []*api.WatchRequest_WatchEntry{
   224  			{
   225  				Kind:   "node",
   226  				Action: api.WatchActionKindUpdate,
   227  			},
   228  		},
   229  		IncludeOldObject: true,
   230  	})
   231  	assert.NoError(t, err)
   232  
   233  	// Should receive an initial message that indicates the watch is ready
   234  	msg, err := watch.Recv()
   235  	assert.NoError(t, err)
   236  	assert.Equal(t, &api.WatchMessage{}, msg)
   237  
   238  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   239  
   240  	err = ts.Store.Update(func(tx store.Tx) error {
   241  		node := store.GetNode(tx, "id1")
   242  		require.NotNil(t, node)
   243  		node.Role = api.NodeRoleWorker
   244  		return store.UpdateNode(tx, node)
   245  	})
   246  	assert.NoError(t, err)
   247  
   248  	msg, err = watch.Recv()
   249  	assert.NoError(t, err)
   250  	assert.Equal(t, api.WatchActionKindUpdate, msg.Events[0].Action)
   251  	require.NotNil(t, msg.Events[0].Object.GetNode())
   252  	assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID)
   253  	assert.Equal(t, api.NodeRoleWorker, msg.Events[0].Object.GetNode().Role)
   254  	require.NotNil(t, msg.Events[0].OldObject.GetNode())
   255  	assert.Equal(t, "id1", msg.Events[0].OldObject.GetNode().ID)
   256  	assert.Equal(t, api.NodeRoleManager, msg.Events[0].OldObject.GetNode().Role)
   257  
   258  	watch.CloseSend()
   259  }
   260  
   261  func TestWatchResumeFrom(t *testing.T) {
   262  	ts := newTestServer(t)
   263  	defer ts.Stop()
   264  
   265  	ctx := context.Background()
   266  
   267  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   268  	node2 := createNode(t, ts, "id2", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   269  
   270  	// Watch for node creates, starting from after the first node creation.
   271  	watch, err := ts.Client.Watch(ctx, &api.WatchRequest{
   272  		Entries: []*api.WatchRequest_WatchEntry{
   273  			{
   274  				Kind:   "node",
   275  				Action: api.WatchActionKindCreate,
   276  			},
   277  		},
   278  		ResumeFrom: &node2.Meta.Version,
   279  	})
   280  	assert.NoError(t, err)
   281  
   282  	// Should receive an initial message that indicates the watch is ready
   283  	msg, err := watch.Recv()
   284  	assert.NoError(t, err)
   285  	assert.Equal(t, &api.WatchMessage{}, msg)
   286  
   287  	msg, err = watch.Recv()
   288  	assert.NoError(t, err)
   289  	assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action)
   290  	require.NotNil(t, msg.Events[0].Object.GetNode())
   291  	assert.Equal(t, "id2", msg.Events[0].Object.GetNode().ID)
   292  	assert.Equal(t, node2.Meta.Version.Index+3, msg.Version.Index)
   293  
   294  	// Create a new node
   295  	node3 := createNode(t, ts, "id3", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   296  
   297  	msg, err = watch.Recv()
   298  	assert.NoError(t, err)
   299  	assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action)
   300  	require.NotNil(t, msg.Events[0].Object.GetNode())
   301  	assert.Equal(t, "id3", msg.Events[0].Object.GetNode().ID)
   302  	assert.Equal(t, node3.Meta.Version.Index+3, msg.Version.Index)
   303  
   304  	watch.CloseSend()
   305  }