Repository: grpc/grpc-go
File: xds/internal/xdsclient/tests/lds_watchers_test.go (Go)

Code before:
	wantUpdate := listenerUpdateErrTuple{
		update: xdsresource.ListenerUpdate{
			RouteConfigName: rdsName,
			HTTPFilters:     []xdsresource.HTTPFilter{{Name: "router"}},
		},
	}
	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
		t.Fatal(err)
	}

	// Remove the listener resource on the management server.
	resource = e2e.UpdateOptions{
		NodeID:         nodeID,
		Listeners:      []*v3listenerpb.Listener{},
		SkipValidation: true,
	}
	if err := mgmtServer.Update(ctx, resource); err != nil {
		t.Fatalf("Failed to update management server with resource: %v, err: %v", resource, err)
	}

	// The existing watcher should receive a resource removed error.
	if err := verifyListenerUpdate(ctx, lw1.updateCh, listenerUpdateErrTuple{
		err: xdsresource.NewErrorf(xdsresource.ErrorTypeResourceNotFound, ""),
	}); err != nil {
		t.Fatal(err)
	}

	// Any new watcher trying to register for removed resource, should get
	// resource removed error as well.
	lw2 := newListenerWatcher()
	ldsCancel2 := xdsresource.WatchListener(client, resourceName, lw2)
	defer ldsCancel2()
	if err := verifyListenerUpdate(ctx, lw2.updateCh, listenerUpdateErrTuple{
		err: xdsresource.NewErrorf(xdsresource.ErrorTypeResourceNotFound, ""),
	}); err != nil {
		t.Fatal(err)
	}
}

// TestLDSWatch_NACKError covers the case where an update from the management
// server is NACK'ed by the xdsclient. The test verifies that the error is
// propagated to the watcher.
func (s) TestLDSWatch_NACKError(t *testing.T) {
	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})

	nodeID := uuid.New().String()
	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
	testutils.CreateBootstrapFileForTesting(t, bc)

	// Create an xDS client with the above bootstrap contents.
	client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{

Review comment (suggestion):
This is a little hard to read. Could we do something like

```golang
	updateErr := listenerUpdateErrTuple{err: xdsresource.NewErrorf(xdsresource.ErrorTypeResourceNotFound, "")}
	if err := verifyListenerUpdate(ctx, lw1.updateCh, updateErr); err != nil {
		t.Fatal(err)
	}
```

Code after:
	wantUpdate := listenerUpdateErrTuple{
		update: xdsresource.ListenerUpdate{
			RouteConfigName: rdsName,
			HTTPFilters:     []xdsresource.HTTPFilter{{Name: "router"}},
		},
	}
	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
		t.Fatal(err)
	}

	// Remove the listener resource on the management server.
	resource = e2e.UpdateOptions{
		NodeID:         nodeID,
		Listeners:      []*v3listenerpb.Listener{},
		SkipValidation: true,
	}
	if err := mgmtServer.Update(ctx, resource); err != nil {
		t.Fatalf("Failed to update management server with resource: %v, err: %v", resource, err)
	}

	// The existing watcher should receive a resource removed error.
	updateError := listenerUpdateErrTuple{err: xdsresource.NewErrorf(xdsresource.ErrorTypeResourceNotFound, "")}
	if err := verifyListenerUpdate(ctx, lw1.updateCh, updateError); err != nil {
		t.Fatal(err)
	}

	// New watchers attempting to register for a deleted resource should also
	// receive a "resource removed" error.
	lw2 := newListenerWatcher()
	ldsCancel2 := xdsresource.WatchListener(client, ldsName, lw2)
	defer ldsCancel2()
	if err := verifyListenerUpdate(ctx, lw2.updateCh, updateError); err != nil {
		t.Fatal(err)
	}
}

// TestLDSWatch_NACKError covers the case where an update from the management
// server is NACK'ed by the xdsclient. The test verifies that the error is
// propagated to the watcher.
func (s) TestLDSWatch_NACKError(t *testing.T) {
	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})

	nodeID := uuid.New().String()
	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
	testutils.CreateBootstrapFileForTesting(t, bc)

	// Create an xDS client with the above bootstrap contents.
	client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
		Name:     t.Name(),
		Contents: bc,
	})