|
|
|
|
@ -133,8 +133,9 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
private static final Node NODE = Node.newBuilder().setId(NODE_ID).build();
|
|
|
|
|
private static final Any FAILING_ANY = MessageFactory.FAILING_ANY;
|
|
|
|
|
private static final ChannelCredentials CHANNEL_CREDENTIALS = InsecureChannelCredentials.create();
|
|
|
|
|
private final ServerInfo lrsServerInfo =
|
|
|
|
|
ServerInfo.create(SERVER_URI, CHANNEL_CREDENTIALS, useProtocolV3());
|
|
|
|
|
|
|
|
|
|
// xDS control plane server info.
|
|
|
|
|
private ServerInfo xdsServerInfo;
|
|
|
|
|
|
|
|
|
|
private static final FakeClock.TaskFilter RPC_RETRY_TASK_FILTER =
|
|
|
|
|
new FakeClock.TaskFilter() {
|
|
|
|
|
@ -316,10 +317,11 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
xdsServerInfo = ServerInfo.create(SERVER_URI, CHANNEL_CREDENTIALS, useProtocolV3(),
|
|
|
|
|
ignoreResourceDeletion());
|
|
|
|
|
Bootstrapper.BootstrapInfo bootstrapInfo =
|
|
|
|
|
Bootstrapper.BootstrapInfo.builder()
|
|
|
|
|
.servers(Arrays.asList(
|
|
|
|
|
Bootstrapper.ServerInfo.create(SERVER_URI, CHANNEL_CREDENTIALS, useProtocolV3())))
|
|
|
|
|
.servers(Collections.singletonList(xdsServerInfo))
|
|
|
|
|
.node(NODE)
|
|
|
|
|
.authorities(ImmutableMap.of(
|
|
|
|
|
"authority.xds.com",
|
|
|
|
|
@ -365,6 +367,9 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
|
|
|
|
|
protected abstract boolean useProtocolV3();
|
|
|
|
|
|
|
|
|
|
/** Whether ignore_resource_deletion server feature is enabled for the given test. */
|
|
|
|
|
protected abstract boolean ignoreResourceDeletion();
|
|
|
|
|
|
|
|
|
|
protected abstract BindableService createAdsService();
|
|
|
|
|
|
|
|
|
|
protected abstract BindableService createLrsService();
|
|
|
|
|
@ -484,10 +489,73 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper method to validate {@link XdsClient.EdsUpdate} created for the test CDS resource
|
|
|
|
|
* {@link ClientXdsClientTestBase#testClusterLoadAssignment}.
|
|
|
|
|
* Verifies the LDS update against the golden Listener with vhosts {@link #testListenerVhosts}.
|
|
|
|
|
*/
|
|
|
|
|
private void validateTestClusterLoadAssigment(EdsUpdate edsUpdate) {
|
|
|
|
|
private void verifyGoldenListenerVhosts(LdsUpdate ldsUpdate) {
|
|
|
|
|
assertThat(ldsUpdate.listener()).isNull();
|
|
|
|
|
HttpConnectionManager hcm = ldsUpdate.httpConnectionManager();
|
|
|
|
|
assertThat(hcm.rdsName()).isNull();
|
|
|
|
|
assertThat(hcm.virtualHosts()).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenHcm(hcm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Verifies the LDS update against the golden Listener with RDS name {@link #testListenerRds}.
|
|
|
|
|
*/
|
|
|
|
|
private void verifyGoldenListenerRds(LdsUpdate ldsUpdate) {
|
|
|
|
|
assertThat(ldsUpdate.listener()).isNull();
|
|
|
|
|
HttpConnectionManager hcm = ldsUpdate.httpConnectionManager();
|
|
|
|
|
assertThat(hcm.rdsName()).isEqualTo(RDS_RESOURCE);
|
|
|
|
|
assertThat(hcm.virtualHosts()).isNull();
|
|
|
|
|
verifyGoldenHcm(hcm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void verifyGoldenHcm(HttpConnectionManager hcm) {
|
|
|
|
|
if (useProtocolV3()) {
|
|
|
|
|
// The last configured filter has to be a terminal filter.
|
|
|
|
|
assertThat(hcm.httpFilterConfigs()).isNotNull();
|
|
|
|
|
assertThat(hcm.httpFilterConfigs()).hasSize(1);
|
|
|
|
|
assertThat(hcm.httpFilterConfigs().get(0).name).isEqualTo("terminal");
|
|
|
|
|
assertThat(hcm.httpFilterConfigs().get(0).filterConfig).isEqualTo(RouterFilter.ROUTER_CONFIG);
|
|
|
|
|
} else {
|
|
|
|
|
assertThat(hcm.httpFilterConfigs()).isNull();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Verifies the RDS update against the golden route config {@link #testRouteConfig}.
|
|
|
|
|
*/
|
|
|
|
|
private void verifyGoldenRouteConfig(RdsUpdate rdsUpdate) {
|
|
|
|
|
assertThat(rdsUpdate.virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
for (VirtualHost vhost : rdsUpdate.virtualHosts) {
|
|
|
|
|
assertThat(vhost.name()).contains("do not care");
|
|
|
|
|
assertThat(vhost.domains()).hasSize(1);
|
|
|
|
|
assertThat(vhost.routes()).hasSize(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Verifies the CDS update against the golden Round Robin Cluster {@link #testClusterRoundRobin}.
|
|
|
|
|
*/
|
|
|
|
|
private void verifyGoldenClusterRoundRobin(CdsUpdate cdsUpdate) {
|
|
|
|
|
assertThat(cdsUpdate.clusterName()).isEqualTo(CDS_RESOURCE);
|
|
|
|
|
assertThat(cdsUpdate.clusterType()).isEqualTo(ClusterType.EDS);
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isNull();
|
|
|
|
|
LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(cdsUpdate.lbPolicyConfig());
|
|
|
|
|
assertThat(lbConfig.getPolicyName()).isEqualTo("wrr_locality_experimental");
|
|
|
|
|
List<LbConfig> childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Verifies the EDS update against the golden Cluster with load assignment
|
|
|
|
|
* {@link #testClusterLoadAssignment}.
|
|
|
|
|
*/
|
|
|
|
|
private void validateGoldenClusterLoadAssignment(EdsUpdate edsUpdate) {
|
|
|
|
|
assertThat(edsUpdate.clusterName).isEqualTo(EDS_RESOURCE);
|
|
|
|
|
assertThat(edsUpdate.dropPolicies)
|
|
|
|
|
.containsExactly(
|
|
|
|
|
@ -620,7 +688,12 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verifyResourceMetadataAcked(LDS, "A", resourcesV2.get("A"), VERSION_2, TIME_INCREMENT * 2);
|
|
|
|
|
verifyResourceMetadataNacked(LDS, "B", resourcesV1.get("B"), VERSION_1, TIME_INCREMENT,
|
|
|
|
|
VERSION_2, TIME_INCREMENT * 2, errorsV2);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(LDS, "C");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(LDS, "C");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {C} stays ACKed in the previous version VERSION_1.
|
|
|
|
|
verifyResourceMetadataAcked(LDS, "C", resourcesV1.get("C"), VERSION_1, TIME_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
call.verifyRequestNack(LDS, subscribedResourceNames, VERSION_1, "0001", NODE, errorsV2);
|
|
|
|
|
|
|
|
|
|
// LDS -> {B, C} version 3
|
|
|
|
|
@ -630,7 +703,12 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, resourcesV3.values().asList(), VERSION_3, "0002");
|
|
|
|
|
// {A} -> does not exist
|
|
|
|
|
// {B, C} -> ACK, version 3
|
|
|
|
|
verifyResourceMetadataDoesNotExist(LDS, "A");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(LDS, "A");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {A} stays ACKed in the previous version VERSION_2.
|
|
|
|
|
verifyResourceMetadataAcked(LDS, "A", resourcesV2.get("A"), VERSION_2, TIME_INCREMENT * 2);
|
|
|
|
|
}
|
|
|
|
|
verifyResourceMetadataAcked(LDS, "B", resourcesV3.get("B"), VERSION_3, TIME_INCREMENT * 3);
|
|
|
|
|
verifyResourceMetadataAcked(LDS, "C", resourcesV3.get("C"), VERSION_3, TIME_INCREMENT * 3);
|
|
|
|
|
call.verifyRequest(LDS, subscribedResourceNames, VERSION_3, "0002", NODE);
|
|
|
|
|
@ -638,7 +716,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void ldsResponseErrorHandling_subscribedResourceInvalid_withRdsSubscriptioin() {
|
|
|
|
|
public void ldsResponseErrorHandling_subscribedResourceInvalid_withRdsSubscription() {
|
|
|
|
|
List<String> subscribedResourceNames = ImmutableList.of("A", "B", "C");
|
|
|
|
|
xdsClient.watchLdsResource("A", ldsResourceWatcher);
|
|
|
|
|
xdsClient.watchRdsResource("A.1", rdsResourceWatcher);
|
|
|
|
|
@ -694,14 +772,26 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verifyResourceMetadataNacked(
|
|
|
|
|
LDS, "B", resourcesV1.get("B"), VERSION_1, TIME_INCREMENT, VERSION_2, TIME_INCREMENT * 3,
|
|
|
|
|
errorsV2);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(LDS, "C");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(LDS, "C");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {C} stays ACKed in the previous version VERSION_1.
|
|
|
|
|
verifyResourceMetadataAcked(LDS, "C", resourcesV1.get("C"), VERSION_1, TIME_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
call.verifyRequestNack(LDS, subscribedResourceNames, VERSION_1, "0001", NODE, errorsV2);
|
|
|
|
|
// {A.1} -> does not exist
|
|
|
|
|
// {A.1} -> does not exist, missing from {A}
|
|
|
|
|
// {B.1} -> version 1
|
|
|
|
|
// {C.1} -> does not exist
|
|
|
|
|
// {C.1} -> does not exist because {C} does not exist
|
|
|
|
|
verifyResourceMetadataDoesNotExist(RDS, "A.1");
|
|
|
|
|
verifyResourceMetadataAcked(RDS, "B.1", resourcesV11.get("B.1"), VERSION_1, TIME_INCREMENT * 2);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(RDS, "C.1");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(RDS, "C.1");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {C.1} is not deleted when {C} is deleted.
|
|
|
|
|
// Verify {C.1} stays in the previous version VERSION_1.
|
|
|
|
|
verifyResourceMetadataAcked(RDS, "C.1", resourcesV11.get("C.1"), VERSION_1,
|
|
|
|
|
TIME_INCREMENT * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@ -712,8 +802,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
@ -727,8 +816,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, mf.buildWrappedResource(testListenerVhosts), VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
@ -742,8 +830,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sends an ACK LDS request.
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
|
|
|
|
.isEqualTo(RDS_RESOURCE);
|
|
|
|
|
verifyGoldenListenerRds(ldsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
@ -760,8 +847,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
LdsResourceWatcher watcher = mock(LdsResourceWatcher.class);
|
|
|
|
|
xdsClient.watchLdsResource(LDS_RESOURCE, watcher);
|
|
|
|
|
verify(watcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
|
|
|
|
.isEqualTo(RDS_RESOURCE);
|
|
|
|
|
verifyGoldenListenerRds(ldsUpdateCaptor.getValue());
|
|
|
|
|
call.verifyNoMoreRequest();
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
@ -790,16 +876,14 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
|
|
|
|
|
// Updated LDS response.
|
|
|
|
|
call.sendResponse(LDS, testListenerRds, VERSION_2, "0001");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_2, "0001", NODE);
|
|
|
|
|
verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
|
|
|
|
.isEqualTo(RDS_RESOURCE);
|
|
|
|
|
verifyGoldenListenerRds(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_2, TIME_INCREMENT * 2);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
assertThat(channelForCustomAuthority).isNull();
|
|
|
|
|
@ -821,8 +905,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, ldsResourceName, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(
|
|
|
|
|
LDS, ldsResourceName, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
@ -842,8 +925,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, ldsResourceName, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(
|
|
|
|
|
LDS, ldsResourceName, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
@ -1072,6 +1154,8 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void ldsResourceDeleted() {
|
|
|
|
|
Assume.assumeFalse(ignoreResourceDeletion());
|
|
|
|
|
|
|
|
|
|
DiscoveryRpcCall call = startResourceWatcher(LDS, LDS_RESOURCE, ldsResourceWatcher);
|
|
|
|
|
verifyResourceMetadataRequested(LDS, LDS_RESOURCE);
|
|
|
|
|
|
|
|
|
|
@ -1079,8 +1163,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
@ -1092,6 +1175,46 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* When ignore_resource_deletion server feature is on, xDS client should keep the deleted listener
|
|
|
|
|
* on empty response, and resume the normal work when LDS contains the listener again.
|
|
|
|
|
* */
|
|
|
|
|
@Test
|
|
|
|
|
public void ldsResourceDeleted_ignoreResourceDeletion() {
|
|
|
|
|
Assume.assumeTrue(ignoreResourceDeletion());
|
|
|
|
|
|
|
|
|
|
DiscoveryRpcCall call = startResourceWatcher(LDS, LDS_RESOURCE, ldsResourceWatcher);
|
|
|
|
|
verifyResourceMetadataRequested(LDS, LDS_RESOURCE);
|
|
|
|
|
|
|
|
|
|
// Initial LDS response.
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
// Empty LDS response does not delete the listener.
|
|
|
|
|
call.sendResponse(LDS, Collections.emptyList(), VERSION_2, "0001");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_2, "0001", NODE);
|
|
|
|
|
// The resource is still ACKED at VERSION_1 (no changes).
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
// onResourceDoesNotExist not called
|
|
|
|
|
verify(ldsResourceWatcher, never()).onResourceDoesNotExist(LDS_RESOURCE);
|
|
|
|
|
|
|
|
|
|
// Next update is correct, and contains the listener again.
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_3, "0003");
|
|
|
|
|
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_3, "0003", NODE);
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
// LDS is now ACKEd at VERSION_3.
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_3,
|
|
|
|
|
TIME_INCREMENT * 3);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
|
|
|
|
verifyNoMoreInteractions(ldsResourceWatcher);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void multipleLdsWatchers() {
|
|
|
|
|
String ldsResourceTwo = "bar.googleapis.com";
|
|
|
|
|
@ -1119,17 +1242,14 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(LDS, ImmutableList.of(testListenerVhosts, listenerTwo), VERSION_1, "0000");
|
|
|
|
|
// ldsResourceWatcher called with listenerVhosts.
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
// watcher1 called with listenerTwo.
|
|
|
|
|
verify(watcher1).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
|
|
|
|
.isEqualTo(RDS_RESOURCE);
|
|
|
|
|
verifyGoldenListenerRds(ldsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts()).isNull();
|
|
|
|
|
// watcher2 called with listenerTwo.
|
|
|
|
|
verify(watcher2).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
|
|
|
|
.isEqualTo(RDS_RESOURCE);
|
|
|
|
|
verifyGoldenListenerRds(ldsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts()).isNull();
|
|
|
|
|
// Metadata of both listeners is stored.
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
@ -1265,7 +1385,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sends an ACK RDS request.
|
|
|
|
|
call.verifyRequest(RDS, RDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(RDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 0, 1, 0);
|
|
|
|
|
@ -1279,7 +1399,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sends an ACK RDS request.
|
|
|
|
|
call.verifyRequest(RDS, RDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(RDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 0, 1, 0);
|
|
|
|
|
@ -1296,7 +1416,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
RdsResourceWatcher watcher = mock(RdsResourceWatcher.class);
|
|
|
|
|
xdsClient.watchRdsResource(RDS_RESOURCE, watcher);
|
|
|
|
|
verify(watcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
call.verifyNoMoreRequest();
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 0, 1, 0);
|
|
|
|
|
@ -1325,7 +1445,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(RDS, testRouteConfig, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(RDS, RDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
|
|
|
|
|
// Updated RDS response.
|
|
|
|
|
@ -1353,23 +1473,25 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
DiscoveryRpcCall call = resourceDiscoveryCalls.poll();
|
|
|
|
|
call.sendResponse(LDS, testListenerRds, VERSION_1, "0000");
|
|
|
|
|
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
|
|
|
|
.isEqualTo(RDS_RESOURCE);
|
|
|
|
|
verifyGoldenListenerRds(ldsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifyResourceMetadataRequested(RDS, RDS_RESOURCE);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
|
|
|
|
|
|
|
|
|
call.sendResponse(RDS, testRouteConfig, VERSION_1, "0000");
|
|
|
|
|
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT * 2);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
|
|
|
|
|
|
|
|
|
// The Listener is getting replaced configured with an RDS name, to the one configured with
|
|
|
|
|
// vhosts. Expect the RDS resources to be discarded.
|
|
|
|
|
// Note that this must work the same despite the ignore_resource_deletion feature is on.
|
|
|
|
|
// This happens because the Listener is getting replaced, and not deleted.
|
|
|
|
|
call.sendResponse(LDS, testListenerVhosts, VERSION_2, "0001");
|
|
|
|
|
verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture());
|
|
|
|
|
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
|
|
|
|
.hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue());
|
|
|
|
|
verify(rdsResourceWatcher).onResourceDoesNotExist(RDS_RESOURCE);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(RDS, RDS_RESOURCE);
|
|
|
|
|
verifyResourceMetadataAcked(
|
|
|
|
|
@ -1413,11 +1535,13 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Simulates receiving the requested RDS resource.
|
|
|
|
|
call.sendResponse(RDS, testRouteConfig, VERSION_1, "0000");
|
|
|
|
|
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT * 2);
|
|
|
|
|
|
|
|
|
|
// Simulates receiving an updated version of the requested LDS resource as a TCP listener
|
|
|
|
|
// with a filter chain containing inlined RouteConfiguration.
|
|
|
|
|
// Note that this must work the same despite the ignore_resource_deletion feature is on.
|
|
|
|
|
// This happens because the Listener is getting replaced, and not deleted.
|
|
|
|
|
hcmFilter = mf.buildHttpConnectionManagerFilter(
|
|
|
|
|
null,
|
|
|
|
|
mf.buildRouteConfiguration(
|
|
|
|
|
@ -1466,7 +1590,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
|
|
|
|
|
call.sendResponse(RDS, testRouteConfig, VERSION_1, "0000");
|
|
|
|
|
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
|
|
|
|
verifyGoldenRouteConfig(rdsUpdateCaptor.getValue());
|
|
|
|
|
verifyNoMoreInteractions(watcher1, watcher2);
|
|
|
|
|
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(RDS, rdsResourceTwo);
|
|
|
|
|
@ -1598,7 +1722,12 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verifyResourceMetadataAcked(CDS, "A", resourcesV2.get("A"), VERSION_2, TIME_INCREMENT * 2);
|
|
|
|
|
verifyResourceMetadataNacked(CDS, "B", resourcesV1.get("B"), VERSION_1, TIME_INCREMENT,
|
|
|
|
|
VERSION_2, TIME_INCREMENT * 2, errorsV2);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(CDS, "C");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(CDS, "C");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {C} stays ACKed in the previous version VERSION_1.
|
|
|
|
|
verifyResourceMetadataAcked(CDS, "C", resourcesV1.get("C"), VERSION_1, TIME_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
call.verifyRequestNack(CDS, subscribedResourceNames, VERSION_1, "0001", NODE, errorsV2);
|
|
|
|
|
|
|
|
|
|
// CDS -> {B, C} version 3
|
|
|
|
|
@ -1612,7 +1741,12 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(CDS, resourcesV3.values().asList(), VERSION_3, "0002");
|
|
|
|
|
// {A} -> does not exit
|
|
|
|
|
// {B, C} -> ACK, version 3
|
|
|
|
|
verifyResourceMetadataDoesNotExist(CDS, "A");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(CDS, "A");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {A} stays ACKed in the previous version VERSION_2.
|
|
|
|
|
verifyResourceMetadataAcked(CDS, "A", resourcesV2.get("A"), VERSION_2, TIME_INCREMENT * 2);
|
|
|
|
|
}
|
|
|
|
|
verifyResourceMetadataAcked(CDS, "B", resourcesV3.get("B"), VERSION_3, TIME_INCREMENT * 3);
|
|
|
|
|
verifyResourceMetadataAcked(CDS, "C", resourcesV3.get("C"), VERSION_3, TIME_INCREMENT * 3);
|
|
|
|
|
call.verifyRequest(CDS, subscribedResourceNames, VERSION_3, "0002", NODE);
|
|
|
|
|
@ -1684,14 +1818,26 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verifyResourceMetadataNacked(
|
|
|
|
|
CDS, "B", resourcesV1.get("B"), VERSION_1, TIME_INCREMENT, VERSION_2, TIME_INCREMENT * 3,
|
|
|
|
|
errorsV2);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(CDS, "C");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(CDS, "C");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {C} stays ACKed in the previous version VERSION_1.
|
|
|
|
|
verifyResourceMetadataAcked(CDS, "C", resourcesV1.get("C"), VERSION_1, TIME_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
call.verifyRequestNack(CDS, subscribedResourceNames, VERSION_1, "0001", NODE, errorsV2);
|
|
|
|
|
// {A.1} -> does not exist
|
|
|
|
|
// {A.1} -> does not exist, missing from {A}
|
|
|
|
|
// {B.1} -> version 1
|
|
|
|
|
// {C.1} -> does not exist
|
|
|
|
|
// {C.1} -> does not exist because {C} does not exist
|
|
|
|
|
verifyResourceMetadataDoesNotExist(EDS, "A.1");
|
|
|
|
|
verifyResourceMetadataAcked(EDS, "B.1", resourcesV11.get("B.1"), VERSION_1, TIME_INCREMENT * 2);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(EDS, "C.1");
|
|
|
|
|
if (!ignoreResourceDeletion()) {
|
|
|
|
|
verifyResourceMetadataDoesNotExist(EDS, "C.1");
|
|
|
|
|
} else {
|
|
|
|
|
// When resource deletion is disabled, {C.1} is not deleted when {C} is deleted.
|
|
|
|
|
// Verify {C.1} stays in the previous version VERSION_1.
|
|
|
|
|
verifyResourceMetadataAcked(EDS, "C.1", resourcesV11.get("C.1"), VERSION_1,
|
|
|
|
|
TIME_INCREMENT * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@ -1702,18 +1848,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sent an ACK CDS request.
|
|
|
|
|
call.verifyRequest(CDS, CDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(cdsResourceWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
CdsUpdate cdsUpdate = cdsUpdateCaptor.getValue();
|
|
|
|
|
assertThat(cdsUpdate.clusterName()).isEqualTo(CDS_RESOURCE);
|
|
|
|
|
assertThat(cdsUpdate.clusterType()).isEqualTo(ClusterType.EDS);
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isNull();
|
|
|
|
|
LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(cdsUpdate.lbPolicyConfig());
|
|
|
|
|
assertThat(lbConfig.getPolicyName()).isEqualTo("wrr_locality_experimental");
|
|
|
|
|
List<LbConfig> childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
verifyGoldenClusterRoundRobin(cdsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(CDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
@ -1728,18 +1863,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sent an ACK CDS request.
|
|
|
|
|
call.verifyRequest(CDS, CDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(cdsResourceWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
CdsUpdate cdsUpdate = cdsUpdateCaptor.getValue();
|
|
|
|
|
assertThat(cdsUpdate.clusterName()).isEqualTo(CDS_RESOURCE);
|
|
|
|
|
assertThat(cdsUpdate.clusterType()).isEqualTo(ClusterType.EDS);
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isNull();
|
|
|
|
|
LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(cdsUpdate.lbPolicyConfig());
|
|
|
|
|
assertThat(lbConfig.getPolicyName()).isEqualTo("wrr_locality_experimental");
|
|
|
|
|
List<LbConfig> childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
verifyGoldenClusterRoundRobin(cdsUpdateCaptor.getValue());
|
|
|
|
|
assertThat(fakeClock.getPendingTasks(CDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
@ -1992,18 +2116,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
CdsResourceWatcher watcher = mock(CdsResourceWatcher.class);
|
|
|
|
|
xdsClient.watchCdsResource(CDS_RESOURCE, watcher);
|
|
|
|
|
verify(watcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
CdsUpdate cdsUpdate = cdsUpdateCaptor.getValue();
|
|
|
|
|
assertThat(cdsUpdate.clusterName()).isEqualTo(CDS_RESOURCE);
|
|
|
|
|
assertThat(cdsUpdate.clusterType()).isEqualTo(ClusterType.EDS);
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isNull();
|
|
|
|
|
LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(cdsUpdate.lbPolicyConfig());
|
|
|
|
|
assertThat(lbConfig.getPolicyName()).isEqualTo("wrr_locality_experimental");
|
|
|
|
|
List<LbConfig> childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
verifyGoldenClusterRoundRobin(cdsUpdateCaptor.getValue());
|
|
|
|
|
call.verifyNoMoreRequest();
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
@ -2070,7 +2183,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(lrsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(xdsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, clusterEds, VERSION_2, TIME_INCREMENT * 2);
|
|
|
|
|
@ -2126,6 +2239,8 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void cdsResourceDeleted() {
|
|
|
|
|
Assume.assumeFalse(ignoreResourceDeletion());
|
|
|
|
|
|
|
|
|
|
DiscoveryRpcCall call = startResourceWatcher(CDS, CDS_RESOURCE, cdsResourceWatcher);
|
|
|
|
|
verifyResourceMetadataRequested(CDS, CDS_RESOURCE);
|
|
|
|
|
|
|
|
|
|
@ -2133,18 +2248,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(CDS, testClusterRoundRobin, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(CDS, CDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(cdsResourceWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
CdsUpdate cdsUpdate = cdsUpdateCaptor.getValue();
|
|
|
|
|
assertThat(cdsUpdate.clusterName()).isEqualTo(CDS_RESOURCE);
|
|
|
|
|
assertThat(cdsUpdate.clusterType()).isEqualTo(ClusterType.EDS);
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isNull();
|
|
|
|
|
LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(cdsUpdate.lbPolicyConfig());
|
|
|
|
|
assertThat(lbConfig.getPolicyName()).isEqualTo("wrr_locality_experimental");
|
|
|
|
|
List<LbConfig> childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
verifyGoldenClusterRoundRobin(cdsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 1, 0, 0);
|
|
|
|
|
@ -2157,6 +2261,48 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 1, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* When ignore_resource_deletion server feature is on, xDS client should keep the deleted cluster
|
|
|
|
|
* on empty response, and resume the normal work when CDS contains the cluster again.
|
|
|
|
|
* */
|
|
|
|
|
@Test
|
|
|
|
|
public void cdsResourceDeleted_ignoreResourceDeletion() {
|
|
|
|
|
Assume.assumeTrue(ignoreResourceDeletion());
|
|
|
|
|
|
|
|
|
|
DiscoveryRpcCall call = startResourceWatcher(CDS, CDS_RESOURCE, cdsResourceWatcher);
|
|
|
|
|
verifyResourceMetadataRequested(CDS, CDS_RESOURCE);
|
|
|
|
|
|
|
|
|
|
// Initial CDS response.
|
|
|
|
|
call.sendResponse(CDS, testClusterRoundRobin, VERSION_1, "0000");
|
|
|
|
|
call.verifyRequest(CDS, CDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(cdsResourceWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
verifyGoldenClusterRoundRobin(cdsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 1, 0, 0);
|
|
|
|
|
|
|
|
|
|
// Empty LDS response does not delete the cluster.
|
|
|
|
|
call.sendResponse(CDS, Collections.emptyList(), VERSION_2, "0001");
|
|
|
|
|
call.verifyRequest(CDS, CDS_RESOURCE, VERSION_2, "0001", NODE);
|
|
|
|
|
|
|
|
|
|
// The resource is still ACKED at VERSION_1 (no changes).
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 1, 0, 0);
|
|
|
|
|
// onResourceDoesNotExist must not be called.
|
|
|
|
|
verify(cdsResourceWatcher, never()).onResourceDoesNotExist(CDS_RESOURCE);
|
|
|
|
|
|
|
|
|
|
// Next update is correct, and contains the cluster again.
|
|
|
|
|
call.sendResponse(CDS, testClusterRoundRobin, VERSION_3, "0003");
|
|
|
|
|
call.verifyRequest(CDS, CDS_RESOURCE, VERSION_3, "0003", NODE);
|
|
|
|
|
verify(cdsResourceWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
verifyGoldenClusterRoundRobin(cdsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(CDS, CDS_RESOURCE, testClusterRoundRobin, VERSION_3,
|
|
|
|
|
TIME_INCREMENT * 3);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 1, 0, 0);
|
|
|
|
|
verifyNoMoreInteractions(cdsResourceWatcher);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void multipleCdsWatchers() {
|
|
|
|
|
String cdsResourceTwo = "cluster-bar.googleapis.com";
|
|
|
|
|
@ -2211,7 +2357,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(lrsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(xdsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
verify(watcher2).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
@ -2224,7 +2370,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
childConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(
|
|
|
|
|
JsonUtil.getListOfObjects(lbConfig.getRawConfigValue(), "childPolicy"));
|
|
|
|
|
assertThat(childConfigs.get(0).getPolicyName()).isEqualTo("round_robin");
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(lrsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(xdsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.maxConcurrentRequests()).isNull();
|
|
|
|
|
assertThat(cdsUpdate.upstreamTlsContext()).isNull();
|
|
|
|
|
// Metadata of both clusters is stored.
|
|
|
|
|
@ -2369,7 +2515,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sent an ACK EDS request.
|
|
|
|
|
call.verifyRequest(EDS, EDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(edsResourceWatcher).onChanged(edsUpdateCaptor.capture());
|
|
|
|
|
validateTestClusterLoadAssigment(edsUpdateCaptor.getValue());
|
|
|
|
|
validateGoldenClusterLoadAssignment(edsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(EDS, EDS_RESOURCE, testClusterLoadAssignment, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 0, 0, 1);
|
|
|
|
|
@ -2383,7 +2529,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
// Client sent an ACK EDS request.
|
|
|
|
|
call.verifyRequest(EDS, EDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(edsResourceWatcher).onChanged(edsUpdateCaptor.capture());
|
|
|
|
|
validateTestClusterLoadAssigment(edsUpdateCaptor.getValue());
|
|
|
|
|
validateGoldenClusterLoadAssignment(edsUpdateCaptor.getValue());
|
|
|
|
|
verifyResourceMetadataAcked(EDS, EDS_RESOURCE, testClusterLoadAssignment, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
verifySubscribedResourcesMetadataSizes(0, 0, 0, 1);
|
|
|
|
|
@ -2400,7 +2546,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
EdsResourceWatcher watcher = mock(EdsResourceWatcher.class);
|
|
|
|
|
xdsClient.watchEdsResource(EDS_RESOURCE, watcher);
|
|
|
|
|
verify(watcher).onChanged(edsUpdateCaptor.capture());
|
|
|
|
|
validateTestClusterLoadAssigment(edsUpdateCaptor.getValue());
|
|
|
|
|
validateGoldenClusterLoadAssignment(edsUpdateCaptor.getValue());
|
|
|
|
|
call.verifyNoMoreRequest();
|
|
|
|
|
verifyResourceMetadataAcked(EDS, EDS_RESOURCE, testClusterLoadAssignment, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
@ -2430,7 +2576,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.verifyRequest(EDS, EDS_RESOURCE, VERSION_1, "0000", NODE);
|
|
|
|
|
verify(edsResourceWatcher).onChanged(edsUpdateCaptor.capture());
|
|
|
|
|
EdsUpdate edsUpdate = edsUpdateCaptor.getValue();
|
|
|
|
|
validateTestClusterLoadAssigment(edsUpdate);
|
|
|
|
|
validateGoldenClusterLoadAssignment(edsUpdate);
|
|
|
|
|
verifyResourceMetadataAcked(EDS, EDS_RESOURCE, testClusterLoadAssignment, VERSION_1,
|
|
|
|
|
TIME_INCREMENT);
|
|
|
|
|
|
|
|
|
|
@ -2505,7 +2651,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
verify(cdsWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
CdsUpdate cdsUpdate = cdsUpdateCaptor.getValue();
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isEqualTo(null);
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(lrsServerInfo);
|
|
|
|
|
assertThat(cdsUpdate.lrsServerInfo()).isEqualTo(xdsServerInfo);
|
|
|
|
|
verify(cdsResourceWatcher).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
cdsUpdate = cdsUpdateCaptor.getValue();
|
|
|
|
|
assertThat(cdsUpdate.edsServiceName()).isEqualTo(EDS_RESOURCE);
|
|
|
|
|
@ -2553,7 +2699,10 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(CDS, clusters, VERSION_2, "0001");
|
|
|
|
|
verify(cdsResourceWatcher, times(2)).onChanged(cdsUpdateCaptor.capture());
|
|
|
|
|
assertThat(cdsUpdateCaptor.getValue().edsServiceName()).isNull();
|
|
|
|
|
// Note that the endpoint must be deleted even if the ignore_resource_deletion feature.
|
|
|
|
|
// This happens because the cluster CDS_RESOURCE is getting replaced, and not deleted.
|
|
|
|
|
verify(edsResourceWatcher).onResourceDoesNotExist(EDS_RESOURCE);
|
|
|
|
|
verify(edsResourceWatcher, never()).onResourceDoesNotExist(resource);
|
|
|
|
|
verifyNoMoreInteractions(cdsWatcher, edsWatcher);
|
|
|
|
|
verifyResourceMetadataDoesNotExist(EDS, EDS_RESOURCE);
|
|
|
|
|
verifyResourceMetadataAcked(
|
|
|
|
|
@ -2588,7 +2737,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
call.sendResponse(EDS, testClusterLoadAssignment, VERSION_1, "0000");
|
|
|
|
|
verify(edsResourceWatcher).onChanged(edsUpdateCaptor.capture());
|
|
|
|
|
EdsUpdate edsUpdate = edsUpdateCaptor.getValue();
|
|
|
|
|
validateTestClusterLoadAssigment(edsUpdate);
|
|
|
|
|
validateGoldenClusterLoadAssignment(edsUpdate);
|
|
|
|
|
verifyNoMoreInteractions(watcher1, watcher2);
|
|
|
|
|
verifyResourceMetadataAcked(
|
|
|
|
|
EDS, EDS_RESOURCE, testClusterLoadAssignment, VERSION_1, TIME_INCREMENT);
|
|
|
|
|
@ -2848,7 +2997,7 @@ public abstract class ClientXdsClientTestBase {
|
|
|
|
|
public void reportLoadStatsToServer() {
|
|
|
|
|
xdsClient.watchLdsResource(LDS_RESOURCE, ldsResourceWatcher);
|
|
|
|
|
String clusterName = "cluster-foo.googleapis.com";
|
|
|
|
|
ClusterDropStats dropStats = xdsClient.addClusterDropStats(lrsServerInfo, clusterName, null);
|
|
|
|
|
ClusterDropStats dropStats = xdsClient.addClusterDropStats(xdsServerInfo, clusterName, null);
|
|
|
|
|
LrsRpcCall lrsCall = loadReportCalls.poll();
|
|
|
|
|
lrsCall.verifyNextReportClusters(Collections.<String[]>emptyList()); // initial LRS request
|
|
|
|
|
|
|
|
|
|
|