|
|
|
@ -21,13 +21,12 @@ package com.tencent.cloud.polaris.router.scg;
|
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
|
import java.net.URI;
|
|
|
|
|
import java.net.URLDecoder;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
|
|
import com.google.common.collect.Lists;
|
|
|
|
|
import com.google.common.collect.Sets;
|
|
|
|
|
import com.tencent.cloud.common.constant.RouterConstant;
|
|
|
|
|
import com.tencent.cloud.common.metadata.MetadataContext;
|
|
|
|
|
import com.tencent.cloud.common.metadata.MetadataContextHolder;
|
|
|
|
@ -37,15 +36,13 @@ import com.tencent.cloud.common.util.JacksonUtils;
|
|
|
|
|
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
|
|
|
|
|
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
|
|
|
|
|
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
|
|
|
|
|
import org.junit.AfterClass;
|
|
|
|
|
import org.junit.Assert;
|
|
|
|
|
import org.junit.BeforeClass;
|
|
|
|
|
import org.junit.Test;
|
|
|
|
|
import org.junit.runner.RunWith;
|
|
|
|
|
import org.assertj.core.util.Lists;
|
|
|
|
|
import org.assertj.core.util.Sets;
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
|
|
|
import org.mockito.Mock;
|
|
|
|
|
import org.mockito.MockedStatic;
|
|
|
|
|
import org.mockito.Mockito;
|
|
|
|
|
import org.mockito.junit.MockitoJUnitRunner;
|
|
|
|
|
import org.mockito.junit.jupiter.MockitoExtension;
|
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
|
|
|
|
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
|
|
|
@ -59,27 +56,27 @@ import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider;
|
|
|
|
|
import org.springframework.http.HttpHeaders;
|
|
|
|
|
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
|
|
|
|
import org.springframework.mock.web.server.MockServerWebExchange;
|
|
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
import org.springframework.web.server.ServerWebExchange;
|
|
|
|
|
|
|
|
|
|
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
|
|
import static org.mockito.Mockito.mockStatic;
|
|
|
|
|
import static org.mockito.Mockito.when;
|
|
|
|
|
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
|
|
|
|
|
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test for ${@link PolarisReactiveLoadBalancerClientFilter}.
|
|
|
|
|
*@author lepdou 2022-07-04
|
|
|
|
|
*
|
|
|
|
|
* @author lepdou 2022-07-04
|
|
|
|
|
*/
|
|
|
|
|
@RunWith(MockitoJUnitRunner.class)
|
|
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
|
|
|
public class PolarisReactiveLoadBalancerClientFilterTest {
|
|
|
|
|
|
|
|
|
|
private static final String callerService = "callerService";
|
|
|
|
|
private static final String testNamespaceAndService = "testNamespaceAndService";
|
|
|
|
|
private static final String calleeService = "calleeService";
|
|
|
|
|
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
|
|
|
|
|
private static MockedStatic<MetadataContextHolder> mockedMetadataContextHolder;
|
|
|
|
|
|
|
|
|
|
@Mock
|
|
|
|
|
private StaticMetadataManager staticMetadataManager;
|
|
|
|
@ -94,95 +91,105 @@ public class PolarisReactiveLoadBalancerClientFilterTest {
|
|
|
|
|
@Mock
|
|
|
|
|
private PolarisContextProperties polarisContextProperties;
|
|
|
|
|
|
|
|
|
|
@BeforeClass
|
|
|
|
|
public static void beforeClass() {
|
|
|
|
|
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
|
|
|
|
|
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
|
|
|
|
.thenReturn(callerService);
|
|
|
|
|
|
|
|
|
|
MetadataContext metadataContext = mock(MetadataContext.class);
|
|
|
|
|
|
|
|
|
|
// mock transitive metadata
|
|
|
|
|
Map<String, String> transitiveLabels = new HashMap<>();
|
|
|
|
|
transitiveLabels.put("t1", "v1");
|
|
|
|
|
transitiveLabels.put("t2", "v2");
|
|
|
|
|
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
|
|
|
|
|
|
|
|
|
|
mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class);
|
|
|
|
|
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AfterClass
|
|
|
|
|
public static void afterClass() {
|
|
|
|
|
mockedApplicationContextAwareUtils.close();
|
|
|
|
|
mockedMetadataContextHolder.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testGenRouterHttpHeaders() throws UnsupportedEncodingException {
|
|
|
|
|
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
|
|
|
|
|
gatewayLoadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
|
|
|
|
|
Lists.newArrayList(routerLabelResolver), polarisContextProperties);
|
|
|
|
|
|
|
|
|
|
Map<String, String> localMetadata = new HashMap<>();
|
|
|
|
|
localMetadata.put("env", "blue");
|
|
|
|
|
when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata);
|
|
|
|
|
|
|
|
|
|
Set<String> expressionLabelKeys = Sets.newHashSet("${http.header.k1}", "${http.query.userid}");
|
|
|
|
|
when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString())).thenReturn(expressionLabelKeys);
|
|
|
|
|
|
|
|
|
|
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users")
|
|
|
|
|
.header("k1", "v1")
|
|
|
|
|
.queryParam("userid", "zhangsan")
|
|
|
|
|
.build();
|
|
|
|
|
MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build();
|
|
|
|
|
|
|
|
|
|
Map<String, String> customMetadata = new HashMap<>();
|
|
|
|
|
customMetadata.put("k2", "v2");
|
|
|
|
|
when(routerLabelResolver.resolve(webExchange, expressionLabelKeys)).thenReturn(customMetadata);
|
|
|
|
|
|
|
|
|
|
HttpHeaders headers = filter.genRouterHttpHeaders(webExchange, calleeService);
|
|
|
|
|
|
|
|
|
|
Assert.assertNotNull(headers);
|
|
|
|
|
List<String> routerHeaders = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
|
|
|
|
|
Assert.assertFalse(CollectionUtils.isEmpty(routerHeaders));
|
|
|
|
|
|
|
|
|
|
Map<String, String> routerLabels = JacksonUtils.deserialize2Map(URLDecoder.decode(routerHeaders.get(0), UTF_8));
|
|
|
|
|
Assert.assertEquals("v1", routerLabels.get("${http.header.k1}"));
|
|
|
|
|
Assert.assertEquals("zhangsan", routerLabels.get("${http.query.userid}"));
|
|
|
|
|
Assert.assertEquals("blue", routerLabels.get("env"));
|
|
|
|
|
Assert.assertEquals("v1", routerLabels.get("t1"));
|
|
|
|
|
Assert.assertEquals("v2", routerLabels.get("t2"));
|
|
|
|
|
try (
|
|
|
|
|
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
|
|
|
|
|
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class)
|
|
|
|
|
) {
|
|
|
|
|
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
|
|
|
|
.thenReturn(testNamespaceAndService);
|
|
|
|
|
|
|
|
|
|
MetadataContext metadataContext = mock(MetadataContext.class);
|
|
|
|
|
|
|
|
|
|
// mock transitive metadata
|
|
|
|
|
Map<String, String> transitiveLabels = new HashMap<>();
|
|
|
|
|
transitiveLabels.put("t1", "v1");
|
|
|
|
|
transitiveLabels.put("t2", "v2");
|
|
|
|
|
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
|
|
|
|
|
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
|
|
|
|
|
|
|
|
|
|
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
|
|
|
|
|
gatewayLoadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
|
|
|
|
|
Collections.singletonList(routerLabelResolver), polarisContextProperties);
|
|
|
|
|
|
|
|
|
|
Map<String, String> localMetadata = new HashMap<>();
|
|
|
|
|
localMetadata.put("env", "blue");
|
|
|
|
|
when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata);
|
|
|
|
|
|
|
|
|
|
Set<String> expressionLabelKeys = Sets.set("${http.header.k1}", "${http.query.userid}");
|
|
|
|
|
when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString())).thenReturn(expressionLabelKeys);
|
|
|
|
|
|
|
|
|
|
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users")
|
|
|
|
|
.header("k1", "v1")
|
|
|
|
|
.queryParam("userid", "zhangsan")
|
|
|
|
|
.build();
|
|
|
|
|
MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build();
|
|
|
|
|
|
|
|
|
|
Map<String, String> customMetadata = new HashMap<>();
|
|
|
|
|
customMetadata.put("k2", "v2");
|
|
|
|
|
when(routerLabelResolver.resolve(webExchange, expressionLabelKeys)).thenReturn(customMetadata);
|
|
|
|
|
|
|
|
|
|
HttpHeaders headers = filter.genRouterHttpHeaders(webExchange, calleeService);
|
|
|
|
|
|
|
|
|
|
assertThat(headers).isNotNull();
|
|
|
|
|
List<String> routerHeaders = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
|
|
|
|
|
assertThat(routerHeaders).isNotNull();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map<String, String> routerLabels = JacksonUtils.deserialize2Map(URLDecoder.decode(routerHeaders.get(0), UTF_8));
|
|
|
|
|
assertThat(routerLabels.get("${http.header.k1}")).isEqualTo("v1");
|
|
|
|
|
assertThat(routerLabels.get("${http.query.userid}")).isEqualTo("zhangsan");
|
|
|
|
|
assertThat(routerLabels.get("env")).isEqualTo("blue");
|
|
|
|
|
assertThat(routerLabels.get("t1")).isEqualTo("v1");
|
|
|
|
|
assertThat(routerLabels.get("t2")).isEqualTo("v2");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testFilter01() throws Exception {
|
|
|
|
|
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
|
|
|
|
|
gatewayLoadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
|
|
|
|
|
Lists.newArrayList(routerLabelResolver), polarisContextProperties);
|
|
|
|
|
|
|
|
|
|
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users").build();
|
|
|
|
|
MockServerWebExchange exchange = new MockServerWebExchange.Builder(request).build();
|
|
|
|
|
|
|
|
|
|
// mock no lb
|
|
|
|
|
EmptyGatewayFilterChain chain = new EmptyGatewayFilterChain();
|
|
|
|
|
Mono<Void> ret = filter.filter(exchange, chain);
|
|
|
|
|
Assert.assertEquals(ret, Mono.empty());
|
|
|
|
|
|
|
|
|
|
// mock with lb
|
|
|
|
|
exchange = new MockServerWebExchange.Builder(request).build();
|
|
|
|
|
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("https://" + calleeService + ":8091"));
|
|
|
|
|
exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, "lb");
|
|
|
|
|
|
|
|
|
|
NoopServiceInstanceListSupplier serviceInstanceListSupplier = new NoopServiceInstanceListSupplier();
|
|
|
|
|
RoundRobinLoadBalancer roundRobinLoadBalancer = new RoundRobinLoadBalancer(new SimpleObjectProvider<>(serviceInstanceListSupplier), calleeService);
|
|
|
|
|
|
|
|
|
|
when(loadBalancerClientFactory.getInstance(calleeService, ReactorServiceInstanceLoadBalancer.class)).thenReturn(roundRobinLoadBalancer);
|
|
|
|
|
LoadBalancerProperties loadBalancerProperties = mock(LoadBalancerProperties.class);
|
|
|
|
|
when(loadBalancerProperties.getHint()).thenReturn(new HashMap<>());
|
|
|
|
|
when(loadBalancerClientFactory.getProperties(calleeService)).thenReturn(loadBalancerProperties);
|
|
|
|
|
filter.filter(exchange, chain);
|
|
|
|
|
|
|
|
|
|
try (
|
|
|
|
|
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
|
|
|
|
|
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class)
|
|
|
|
|
) {
|
|
|
|
|
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
|
|
|
|
.thenReturn(testNamespaceAndService);
|
|
|
|
|
|
|
|
|
|
MetadataContext metadataContext = mock(MetadataContext.class);
|
|
|
|
|
|
|
|
|
|
// mock transitive metadata
|
|
|
|
|
Map<String, String> transitiveLabels = new HashMap<>();
|
|
|
|
|
transitiveLabels.put("t1", "v1");
|
|
|
|
|
transitiveLabels.put("t2", "v2");
|
|
|
|
|
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
|
|
|
|
|
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
|
|
|
|
|
|
|
|
|
|
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
|
|
|
|
|
gatewayLoadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
|
|
|
|
|
Lists.list(routerLabelResolver), polarisContextProperties);
|
|
|
|
|
|
|
|
|
|
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users").build();
|
|
|
|
|
MockServerWebExchange exchange = new MockServerWebExchange.Builder(request).build();
|
|
|
|
|
|
|
|
|
|
// mock no lb
|
|
|
|
|
EmptyGatewayFilterChain chain = new EmptyGatewayFilterChain();
|
|
|
|
|
Mono<Void> ret = filter.filter(exchange, chain);
|
|
|
|
|
assertThat(ret).isEqualTo(Mono.empty());
|
|
|
|
|
|
|
|
|
|
// mock with lb
|
|
|
|
|
exchange = new MockServerWebExchange.Builder(request).build();
|
|
|
|
|
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("https://" + calleeService + ":8091"));
|
|
|
|
|
exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, "lb");
|
|
|
|
|
|
|
|
|
|
NoopServiceInstanceListSupplier serviceInstanceListSupplier = new NoopServiceInstanceListSupplier();
|
|
|
|
|
RoundRobinLoadBalancer roundRobinLoadBalancer = new RoundRobinLoadBalancer(new SimpleObjectProvider<>(serviceInstanceListSupplier), calleeService);
|
|
|
|
|
|
|
|
|
|
when(loadBalancerClientFactory.getInstance(calleeService, ReactorServiceInstanceLoadBalancer.class)).thenReturn(roundRobinLoadBalancer);
|
|
|
|
|
LoadBalancerProperties loadBalancerProperties = mock(LoadBalancerProperties.class);
|
|
|
|
|
when(loadBalancerProperties.getHint()).thenReturn(new HashMap<>());
|
|
|
|
|
when(loadBalancerClientFactory.getProperties(calleeService)).thenReturn(loadBalancerProperties);
|
|
|
|
|
filter.filter(exchange, chain);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class EmptyGatewayFilterChain implements GatewayFilterChain {
|
|
|
|
@ -192,5 +199,4 @@ public class PolarisReactiveLoadBalancerClientFilterTest {
|
|
|
|
|
return Mono.empty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|