feat:merge features from 1.5.2-Hoxton.SR9 except router. (#226)
parent
422feff466
commit
fc4bd10564
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.metadata.core;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* resolve custom transitive metadata from request.
|
||||
*@author lepdou 2022-05-20
|
||||
*/
|
||||
public class CustomTransitiveMetadataResolver {
|
||||
|
||||
private static final String TRANSITIVE_HEADER_PREFIX = "X-SCT-Metadata-Transitive-";
|
||||
private static final int TRANSITIVE_HEADER_PREFIX_LENGTH = TRANSITIVE_HEADER_PREFIX.length();
|
||||
|
||||
public static Map<String, String> resolve(ServerWebExchange exchange) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
HttpHeaders headers = exchange.getRequest().getHeaders();
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
|
||||
if (StringUtils.isNotBlank(key) &&
|
||||
StringUtils.startsWithIgnoreCase(key, TRANSITIVE_HEADER_PREFIX)
|
||||
&& !CollectionUtils.isEmpty(entry.getValue())) {
|
||||
|
||||
String sourceKey = StringUtils.substring(key, TRANSITIVE_HEADER_PREFIX_LENGTH);
|
||||
result.put(sourceKey, entry.getValue().get(0));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, String> resolve(HttpServletRequest request) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
Enumeration<String> headers = request.getHeaderNames();
|
||||
while (headers.hasMoreElements()) {
|
||||
String key = headers.nextElement();
|
||||
|
||||
if (StringUtils.isNotBlank(key) &&
|
||||
StringUtils.startsWithIgnoreCase(key, TRANSITIVE_HEADER_PREFIX)
|
||||
&& StringUtils.isNotBlank(request.getHeader(key))) {
|
||||
|
||||
String sourceKey = StringUtils.substring(key, TRANSITIVE_HEADER_PREFIX_LENGTH);
|
||||
result.put(sourceKey, request.getHeader(key));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.circuitbreaker;
|
||||
|
||||
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor;
|
||||
import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
|
||||
import com.tencent.polaris.api.core.ConsumerAPI;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisFeignClientAutoConfiguration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisFeignClientAutoConfigurationTest {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(
|
||||
PolarisContextAutoConfiguration.class,
|
||||
PolarisFeignClientAutoConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true");
|
||||
|
||||
@Test
|
||||
public void testDefaultInitialization() {
|
||||
this.contextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(ConsumerAPI.class);
|
||||
assertThat(context).hasSingleBean(PolarisFeignBeanPostProcessor.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||
|
||||
import com.tencent.polaris.api.core.ConsumerAPI;
|
||||
import feign.Client;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisFeignBeanPostProcessor}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisFeignBeanPostProcessorTest {
|
||||
|
||||
private PolarisFeignBeanPostProcessor polarisFeignBeanPostProcessor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
ConsumerAPI consumerAPI = mock(ConsumerAPI.class);
|
||||
|
||||
polarisFeignBeanPostProcessor = new PolarisFeignBeanPostProcessor(consumerAPI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostProcessBeforeInitialization() {
|
||||
BeanFactory beanFactory = mock(BeanFactory.class);
|
||||
doAnswer(invocation -> {
|
||||
Class<?> clazz = invocation.getArgument(0);
|
||||
if (clazz.equals(BlockingLoadBalancerClient.class)) {
|
||||
return mock(BlockingLoadBalancerClient.class);
|
||||
}
|
||||
if (clazz.equals(LoadBalancerProperties.class)) {
|
||||
return mock(LoadBalancerProperties.class);
|
||||
}
|
||||
if (clazz.equals(LoadBalancerClientFactory.class)) {
|
||||
return mock(LoadBalancerClientFactory.class);
|
||||
}
|
||||
return null;
|
||||
}).when(beanFactory).getBean(any(Class.class));
|
||||
polarisFeignBeanPostProcessor.setBeanFactory(beanFactory);
|
||||
|
||||
// isNeedWrap(bean) == false
|
||||
Object bean1 = new Object();
|
||||
Object bean = polarisFeignBeanPostProcessor.postProcessBeforeInitialization(bean1, "bean1");
|
||||
assertThat(bean).isNotInstanceOfAny(
|
||||
PolarisFeignClient.class,
|
||||
PolarisFeignBlockingLoadBalancerClient.class);
|
||||
|
||||
// bean instanceOf Client.class
|
||||
Client bean2 = mock(Client.class);
|
||||
bean = polarisFeignBeanPostProcessor.postProcessBeforeInitialization(bean2, "bean2");
|
||||
assertThat(bean).isInstanceOf(PolarisFeignClient.class);
|
||||
|
||||
// bean instanceOf FeignBlockingLoadBalancerClient.class
|
||||
FeignBlockingLoadBalancerClient bean3 = mock(FeignBlockingLoadBalancerClient.class);
|
||||
doReturn(mock(Client.class)).when(bean3).getDelegate();
|
||||
bean = polarisFeignBeanPostProcessor.postProcessBeforeInitialization(bean3, "bean3");
|
||||
assertThat(bean).isInstanceOf(PolarisFeignBlockingLoadBalancerClient.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisFeignBlockingLoadBalancerClient}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisFeignBlockingLoadBalancerClientTest {
|
||||
|
||||
@Test
|
||||
public void testConstructor() {
|
||||
try {
|
||||
new PolarisFeignBlockingLoadBalancerClient(null, null, null, null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assertions.fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.circuitbreaker.feign;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
/**
|
||||
* Test application.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
public class TestPolarisFeignApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestPolarisFeignApp.class);
|
||||
}
|
||||
|
||||
@FeignClient(name = "feign-service-polaris", fallback = TestPolarisServiceFallback.class)
|
||||
public interface TestPolarisService {
|
||||
|
||||
/**
|
||||
* Get info of service B.
|
||||
*/
|
||||
@GetMapping("/example/service/b/info")
|
||||
String info();
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
public static class TestPolarisServiceFallback implements TestPolarisService {
|
||||
|
||||
@Override
|
||||
public String info() {
|
||||
return "trigger the refuse";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris;
|
||||
|
||||
import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
|
||||
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
|
||||
import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties;
|
||||
import com.tencent.polaris.api.core.ConsumerAPI;
|
||||
import com.tencent.polaris.api.core.ProviderAPI;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link DiscoveryPropertiesAutoConfiguration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class DiscoveryPropertiesAutoConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void testDefaultInitialization() {
|
||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(PolarisContextAutoConfiguration.class,
|
||||
DiscoveryPropertiesAutoConfiguration.class));
|
||||
applicationContextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(DiscoveryPropertiesAutoConfiguration.class);
|
||||
assertThat(context).hasSingleBean(PolarisDiscoveryProperties.class);
|
||||
assertThat(context).hasSingleBean(ConsulContextProperties.class);
|
||||
assertThat(context).hasSingleBean(ProviderAPI.class);
|
||||
assertThat(context).hasSingleBean(ConsumerAPI.class);
|
||||
assertThat(context).hasSingleBean(PolarisDiscoveryHandler.class);
|
||||
assertThat(context).hasSingleBean(DiscoveryConfigModifier.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInit() {
|
||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(PolarisContextAutoConfiguration.class,
|
||||
TestConfiguration.class,
|
||||
DiscoveryPropertiesAutoConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.polaris.discovery.register=false")
|
||||
.withPropertyValues("spring.cloud.consul.discovery.register=false")
|
||||
.withPropertyValues("spring.cloud.consul.discovery.enabled=false");
|
||||
applicationContextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(DiscoveryPropertiesAutoConfiguration.class);
|
||||
DiscoveryPropertiesAutoConfiguration discoveryPropertiesAutoConfiguration = context.getBean(DiscoveryPropertiesAutoConfiguration.class);
|
||||
assertThat(discoveryPropertiesAutoConfiguration.isRegisterEnabled()).isFalse();
|
||||
assertThat(discoveryPropertiesAutoConfiguration.isDiscoveryEnabled()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
@Bean
|
||||
public PolarisDiscoveryProperties polarisDiscoveryProperties() {
|
||||
PolarisDiscoveryProperties polarisDiscoveryProperties = new PolarisDiscoveryProperties();
|
||||
polarisDiscoveryProperties.setEnabled(false);
|
||||
return polarisDiscoveryProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsulContextProperties consulContextProperties() {
|
||||
ConsulContextProperties consulContextProperties = new ConsulContextProperties();
|
||||
consulContextProperties.setEnabled(true);
|
||||
return consulContextProperties;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris;
|
||||
|
||||
import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link DiscoveryPropertiesBootstrapAutoConfiguration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class DiscoveryPropertiesBootstrapAutoConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void testDefaultInitialization() {
|
||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(PolarisContextAutoConfiguration.class,
|
||||
DiscoveryPropertiesBootstrapAutoConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.polaris.enabled=true");
|
||||
applicationContextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(DiscoveryPropertiesBootstrapAutoConfiguration.class);
|
||||
assertThat(context).hasSingleBean(DiscoveryPropertiesAutoConfiguration.class);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
|
||||
import static com.tencent.polaris.test.common.Consts.PORT;
|
||||
import static com.tencent.polaris.test.common.Consts.PROVIDER_TOKEN;
|
||||
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisDiscoveryProperties}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisDiscoveryPropertiesTest {
|
||||
|
||||
@Test
|
||||
public void testGetAndSet() {
|
||||
PolarisDiscoveryProperties polarisDiscoveryProperties = new PolarisDiscoveryProperties();
|
||||
|
||||
// HeartbeatEnabled
|
||||
polarisDiscoveryProperties.setHeartbeatEnabled(true);
|
||||
assertThat(polarisDiscoveryProperties.isHeartbeatEnabled()).isTrue();
|
||||
|
||||
// Namespace
|
||||
polarisDiscoveryProperties.setNamespace(NAMESPACE_TEST);
|
||||
assertThat(polarisDiscoveryProperties.getNamespace()).isEqualTo(NAMESPACE_TEST);
|
||||
|
||||
// Weight
|
||||
polarisDiscoveryProperties.setWeight(10);
|
||||
assertThat(polarisDiscoveryProperties.getWeight()).isEqualTo(10);
|
||||
|
||||
// Service
|
||||
polarisDiscoveryProperties.setService(SERVICE_PROVIDER);
|
||||
assertThat(polarisDiscoveryProperties.getService()).isEqualTo(SERVICE_PROVIDER);
|
||||
|
||||
// Enabled
|
||||
polarisDiscoveryProperties.setEnabled(true);
|
||||
assertThat(polarisDiscoveryProperties.isEnabled()).isTrue();
|
||||
|
||||
// RegisterEnabled
|
||||
polarisDiscoveryProperties.setRegisterEnabled(true);
|
||||
assertThat(polarisDiscoveryProperties.isRegisterEnabled()).isTrue();
|
||||
|
||||
// Token
|
||||
polarisDiscoveryProperties.setToken(PROVIDER_TOKEN);
|
||||
assertThat(polarisDiscoveryProperties.getToken()).isEqualTo(PROVIDER_TOKEN);
|
||||
|
||||
// Version
|
||||
polarisDiscoveryProperties.setVersion("1.0.0");
|
||||
assertThat(polarisDiscoveryProperties.getVersion()).isEqualTo("1.0.0");
|
||||
|
||||
// HTTP
|
||||
polarisDiscoveryProperties.setProtocol("HTTP");
|
||||
assertThat(polarisDiscoveryProperties.getProtocol()).isEqualTo("HTTP");
|
||||
|
||||
// Port
|
||||
polarisDiscoveryProperties.setPort(PORT);
|
||||
assertThat(polarisDiscoveryProperties.getPort()).isEqualTo(PORT);
|
||||
|
||||
// HealthCheckUrl
|
||||
polarisDiscoveryProperties.setHealthCheckUrl("/health");
|
||||
assertThat(polarisDiscoveryProperties.getHealthCheckUrl()).isEqualTo("/health");
|
||||
|
||||
// ServiceListRefreshInterval
|
||||
polarisDiscoveryProperties.setServiceListRefreshInterval(1000L);
|
||||
assertThat(polarisDiscoveryProperties.getServiceListRefreshInterval()).isEqualTo(1000L);
|
||||
|
||||
assertThat(polarisDiscoveryProperties.toString())
|
||||
.isEqualTo("PolarisDiscoveryProperties{"
|
||||
+ "namespace='Test'"
|
||||
+ ", service='java_provider_test'"
|
||||
+ ", token='19485a7674294e3c88dba293373c1534'"
|
||||
+ ", weight=10, version='1.0.0'"
|
||||
+ ", protocol='HTTP'"
|
||||
+ ", port=9091"
|
||||
+ ", enabled=true"
|
||||
+ ", registerEnabled=true"
|
||||
+ ", heartbeatEnabled=true"
|
||||
+ ", healthCheckUrl='/health'"
|
||||
+ ", serviceListRefreshInterval=1000}");
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.discovery.refresh;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.tencent.polaris.api.pojo.DefaultInstance;
|
||||
import com.tencent.polaris.api.pojo.ServiceEventKey;
|
||||
import com.tencent.polaris.api.pojo.ServiceInfo;
|
||||
import com.tencent.polaris.api.pojo.ServiceKey;
|
||||
import com.tencent.polaris.client.pojo.ServiceInstancesByProto;
|
||||
import com.tencent.polaris.client.pojo.ServicesByProto;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import static com.tencent.polaris.test.common.Consts.HOST;
|
||||
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
|
||||
import static com.tencent.polaris.test.common.Consts.PORT;
|
||||
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisServiceStatusChangeListener}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisServiceStatusChangeListenerTest {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
publisher = mock(ApplicationEventPublisher.class);
|
||||
doNothing().when(publisher).publishEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnResourceUpdated() {
|
||||
PolarisServiceStatusChangeListener polarisServiceStatusChangeListener = new PolarisServiceStatusChangeListener();
|
||||
polarisServiceStatusChangeListener.setApplicationEventPublisher(publisher);
|
||||
|
||||
// Service update event
|
||||
ServiceEventKey serviceUpdateEventKey = new ServiceEventKey(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER), ServiceEventKey.EventType.SERVICE);
|
||||
ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.setNamespace(NAMESPACE_TEST);
|
||||
serviceInfo.setService(SERVICE_PROVIDER);
|
||||
// Need update
|
||||
ServicesByProto oldServices = new ServicesByProto(Collections.emptyList());
|
||||
ServicesByProto newServices = new ServicesByProto(Collections.singletonList(serviceInfo));
|
||||
polarisServiceStatusChangeListener.onResourceUpdated(serviceUpdateEventKey, oldServices, newServices);
|
||||
verify(publisher, times(1)).publishEvent(any(ApplicationEvent.class));
|
||||
// No need update
|
||||
oldServices = new ServicesByProto(Collections.singletonList(serviceInfo));
|
||||
newServices = new ServicesByProto(Collections.singletonList(serviceInfo));
|
||||
polarisServiceStatusChangeListener.onResourceUpdated(serviceUpdateEventKey, oldServices, newServices);
|
||||
verify(publisher, times(1)).publishEvent(any(ApplicationEvent.class));
|
||||
|
||||
|
||||
// Instance update event
|
||||
ServiceEventKey instanceUpdateEventKey = new ServiceEventKey(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER), ServiceEventKey.EventType.INSTANCE);
|
||||
DefaultInstance instance = new DefaultInstance();
|
||||
instance.setNamespace(NAMESPACE_TEST);
|
||||
instance.setService(SERVICE_PROVIDER);
|
||||
instance.setHost(HOST);
|
||||
instance.setPort(PORT);
|
||||
try {
|
||||
Field instances = ServiceInstancesByProto.class.getDeclaredField("instances");
|
||||
instances.setAccessible(true);
|
||||
|
||||
// Need update
|
||||
ServiceInstancesByProto oldInstances = new ServiceInstancesByProto();
|
||||
instances.set(oldInstances, Collections.emptyList());
|
||||
ServiceInstancesByProto newInstances = new ServiceInstancesByProto();
|
||||
instances.set(newInstances, Collections.singletonList(instance));
|
||||
polarisServiceStatusChangeListener.onResourceUpdated(serviceUpdateEventKey, oldInstances, newInstances);
|
||||
verify(publisher, times(2)).publishEvent(any(ApplicationEvent.class));
|
||||
|
||||
// No need update
|
||||
oldInstances = new ServiceInstancesByProto();
|
||||
instances.set(oldInstances, Collections.singletonList(instance));
|
||||
newInstances = new ServiceInstancesByProto();
|
||||
instances.set(newInstances, Collections.singletonList(instance));
|
||||
polarisServiceStatusChangeListener.onResourceUpdated(serviceUpdateEventKey, oldInstances, newInstances);
|
||||
verify(publisher, times(2)).publishEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
Assertions.fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.extend.consul;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.polaris.client.api.SDKContext;
|
||||
import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY;
|
||||
import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY;
|
||||
import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY;
|
||||
import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY;
|
||||
import static com.tencent.polaris.test.common.Consts.HOST;
|
||||
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link ConsulContextProperties}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ConsulContextPropertiesTest.TestApplication.class)
|
||||
@ActiveProfiles("test")
|
||||
public class ConsulContextPropertiesTest {
|
||||
|
||||
@Autowired
|
||||
private ConsulContextProperties consulContextProperties;
|
||||
|
||||
@Autowired
|
||||
private SDKContext sdkContext;
|
||||
|
||||
@Test
|
||||
public void testDefaultInitialization() {
|
||||
assertThat(consulContextProperties).isNotNull();
|
||||
assertThat(consulContextProperties.isEnabled()).isTrue();
|
||||
assertThat(consulContextProperties.getHost()).isEqualTo("127.0.0.1");
|
||||
assertThat(consulContextProperties.getPort()).isEqualTo(8500);
|
||||
assertThat(consulContextProperties.isRegister()).isTrue();
|
||||
assertThat(consulContextProperties.isDiscoveryEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModify() {
|
||||
assertThat(sdkContext).isNotNull();
|
||||
com.tencent.polaris.api.config.Configuration configuration = sdkContext.getConfig();
|
||||
List<ServerConnectorConfigImpl> serverConnectorConfigs = configuration.getGlobal().getServerConnectors();
|
||||
Map<String, String> metadata = null;
|
||||
for (ServerConnectorConfigImpl serverConnectorConfig : serverConnectorConfigs) {
|
||||
if (serverConnectorConfig.getId().equals("consul")) {
|
||||
metadata = serverConnectorConfig.getMetadata();
|
||||
}
|
||||
}
|
||||
assertThat(metadata).isNotNull();
|
||||
assertThat(metadata.get(SERVICE_NAME_KEY)).isEqualTo(SERVICE_PROVIDER);
|
||||
assertThat(metadata.get(INSTANCE_ID_KEY)).isEqualTo("ins-test");
|
||||
assertThat(metadata.get(PREFER_IP_ADDRESS_KEY)).isEqualTo("true");
|
||||
assertThat(metadata.get(IP_ADDRESS_KEY)).isEqualTo(HOST);
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
protected static class TestApplication {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.registry;
|
||||
|
||||
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static com.tencent.polaris.test.common.Consts.PORT;
|
||||
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisAutoServiceRegistration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PolarisAutoServiceRegistrationTest {
|
||||
|
||||
@Mock
|
||||
private ServiceRegistry<Registration> serviceRegistry;
|
||||
|
||||
@Mock
|
||||
private AutoServiceRegistrationProperties autoServiceRegistrationProperties;
|
||||
|
||||
@Mock
|
||||
private PolarisDiscoveryProperties polarisDiscoveryProperties;
|
||||
|
||||
@Mock
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Mock
|
||||
private Environment environment;
|
||||
|
||||
@Mock
|
||||
private PolarisRegistration registration;
|
||||
|
||||
private PolarisAutoServiceRegistration polarisAutoServiceRegistration;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
doReturn(polarisDiscoveryProperties).when(registration).getPolarisProperties();
|
||||
|
||||
doNothing().when(serviceRegistry).register(nullable(Registration.class));
|
||||
|
||||
polarisAutoServiceRegistration =
|
||||
new PolarisAutoServiceRegistration(serviceRegistry, autoServiceRegistrationProperties, registration);
|
||||
|
||||
doReturn(environment).when(applicationContext).getEnvironment();
|
||||
polarisAutoServiceRegistration.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
doReturn(false).when(registration).isRegisterEnabled();
|
||||
try {
|
||||
polarisAutoServiceRegistration.register();
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
doReturn(true).when(registration).isRegisterEnabled();
|
||||
doReturn(-1).when(registration).getPort();
|
||||
try {
|
||||
polarisAutoServiceRegistration.register();
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
doReturn(PORT).when(registration).getPort();
|
||||
try {
|
||||
polarisAutoServiceRegistration.register();
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetManagementRegistration() {
|
||||
assertThat(polarisAutoServiceRegistration.getManagementRegistration()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterManagement() {
|
||||
doReturn(false).when(registration).isRegisterEnabled();
|
||||
try {
|
||||
polarisAutoServiceRegistration.registerManagement();
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
doReturn(true).when(registration).isRegisterEnabled();
|
||||
try {
|
||||
polarisAutoServiceRegistration.registerManagement();
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAppName() {
|
||||
doReturn("application").when(environment).getProperty(anyString(), anyString());
|
||||
assertThat(polarisAutoServiceRegistration.getAppName()).isEqualTo("application");
|
||||
|
||||
doReturn(SERVICE_PROVIDER).when(polarisDiscoveryProperties).getService();
|
||||
assertThat(polarisAutoServiceRegistration.getAppName()).isEqualTo(SERVICE_PROVIDER);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.registry;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.metadata.StaticMetadataManager;
|
||||
import com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration;
|
||||
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
|
||||
import com.tencent.polaris.api.config.Configuration;
|
||||
import com.tencent.polaris.api.config.global.APIConfig;
|
||||
import com.tencent.polaris.api.config.global.GlobalConfig;
|
||||
import com.tencent.polaris.client.api.SDKContext;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static com.tencent.polaris.test.common.Consts.HOST;
|
||||
import static com.tencent.polaris.test.common.Consts.PORT;
|
||||
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisRegistration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PolarisRegistrationTest {
|
||||
|
||||
private PolarisRegistration polarisRegistration;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// mock DiscoveryPropertiesAutoConfiguration
|
||||
DiscoveryPropertiesAutoConfiguration discoveryPropertiesAutoConfiguration =
|
||||
mock(DiscoveryPropertiesAutoConfiguration.class);
|
||||
doReturn(true).when(discoveryPropertiesAutoConfiguration).isRegisterEnabled();
|
||||
|
||||
// mock PolarisDiscoveryProperties
|
||||
PolarisDiscoveryProperties polarisDiscoveryProperties = mock(PolarisDiscoveryProperties.class);
|
||||
doReturn(SERVICE_PROVIDER).when(polarisDiscoveryProperties).getService();
|
||||
doReturn(PORT).when(polarisDiscoveryProperties).getPort();
|
||||
doReturn("http").when(polarisDiscoveryProperties).getProtocol();
|
||||
|
||||
// mock SDKContext
|
||||
APIConfig apiConfig = mock(APIConfig.class);
|
||||
doReturn(HOST).when(apiConfig).getBindIP();
|
||||
GlobalConfig globalConfig = mock(GlobalConfig.class);
|
||||
doReturn(apiConfig).when(globalConfig).getAPI();
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
doReturn(globalConfig).when(configuration).getGlobal();
|
||||
SDKContext polarisContext = mock(SDKContext.class);
|
||||
doReturn(configuration).when(polarisContext).getConfig();
|
||||
|
||||
// mock StaticMetadataManager
|
||||
StaticMetadataManager staticMetadataManager = mock(StaticMetadataManager.class);
|
||||
doReturn(Collections.singletonMap("key1", "value1")).when(staticMetadataManager).getMergedStaticMetadata();
|
||||
doReturn(Collections.singletonMap("key2", "value2")).when(staticMetadataManager).getLocationMetadata();
|
||||
|
||||
polarisRegistration = new PolarisRegistration(
|
||||
discoveryPropertiesAutoConfiguration, polarisDiscoveryProperties, polarisContext, staticMetadataManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetServiceId() {
|
||||
assertThat(polarisRegistration.getServiceId()).isEqualTo(SERVICE_PROVIDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetHost() {
|
||||
assertThat(polarisRegistration.getHost()).isEqualTo(HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPort() {
|
||||
assertThat(polarisRegistration.getPort()).isEqualTo(PORT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSecure() {
|
||||
assertThat(polarisRegistration.isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUri() {
|
||||
assertThat(polarisRegistration.getUri().toString()).isEqualTo("http://" + HOST + ":" + PORT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadata() {
|
||||
Map<String, String> metadata = polarisRegistration.getMetadata();
|
||||
assertThat(metadata).isNotNull();
|
||||
assertThat(metadata).isNotEmpty();
|
||||
assertThat(metadata.size()).isEqualTo(2);
|
||||
assertThat(metadata.get("key1")).isEqualTo("value1");
|
||||
assertThat(metadata.get("key2")).isEqualTo("value2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPolarisProperties() {
|
||||
assertThat(polarisRegistration.getPolarisProperties()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRegisterEnabled() {
|
||||
assertThat(polarisRegistration.isRegisterEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
System.out.println(polarisRegistration);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.util;
|
||||
|
||||
import org.assertj.core.util.Maps;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link OkHttpUtil}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = OkHttpUtilTest.TestApplication.class)
|
||||
public class OkHttpUtilTest {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Test
|
||||
public void testGet() {
|
||||
assertThat(OkHttpUtil.get("http://localhost:" + port + "/test", Maps.newHashMap("key", "value"))).isTrue();
|
||||
assertThat(OkHttpUtil.get("http://localhost:" + port + "/error", Maps.newHashMap("key", "value"))).isFalse();
|
||||
assertThat(OkHttpUtil.get("http://localhost:55555/error", Maps.newHashMap("key", "value"))).isFalse();
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
static class TestApplication {
|
||||
@GetMapping("/test")
|
||||
public String test() {
|
||||
return "test";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
server:
|
||||
port: 48084
|
||||
spring:
|
||||
application:
|
||||
name: java_provider_test
|
||||
cloud:
|
||||
polaris:
|
||||
address: grpc://127.0.0.1:8091
|
||||
namespace: Test
|
||||
enabled: true
|
||||
discovery:
|
||||
enabled: true
|
||||
register: true
|
||||
consul:
|
||||
port: 8500
|
||||
host: 127.0.0.1
|
||||
enabled: true
|
||||
discovery:
|
||||
enabled: true
|
||||
register: true
|
||||
instance-id: ins-test
|
||||
service-name: ${spring.application.name}
|
||||
ip-address: 127.0.0.1
|
||||
prefer-ip-address: true
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.tencent.cloud.common.util.ExpressionLabelUtils;
|
||||
import com.tencent.cloud.polaris.context.ServiceRuleManager;
|
||||
import com.tencent.polaris.client.pb.ModelProto;
|
||||
import com.tencent.polaris.client.pb.RateLimitProto;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* resolve labels from rate limit rule.
|
||||
*
|
||||
*@author lepdou 2022-05-13
|
||||
*/
|
||||
public class RateLimitRuleLabelResolver {
|
||||
|
||||
private final ServiceRuleManager serviceRuleManager;
|
||||
|
||||
public RateLimitRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
|
||||
this.serviceRuleManager = serviceRuleManager;
|
||||
}
|
||||
|
||||
public Set<String> getExpressionLabelKeys(String namespace, String service) {
|
||||
RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service);
|
||||
if (rateLimitRule == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<RateLimitProto.Rule> rules = rateLimitRule.getRulesList();
|
||||
if (CollectionUtils.isEmpty(rules)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> expressionLabels = new HashSet<>();
|
||||
for (RateLimitProto.Rule rule : rules) {
|
||||
Map<String, ModelProto.MatchString> labels = rule.getLabelsMap();
|
||||
if (CollectionUtils.isEmpty(labels)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
for (String key : labels.keySet()) {
|
||||
if (ExpressionLabelUtils.isExpressionLabel(key)) {
|
||||
expressionLabels.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expressionLabels;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.config;
|
||||
|
||||
import com.tencent.cloud.common.constant.ContextConstant;
|
||||
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
|
||||
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
|
||||
import com.tencent.polaris.factory.config.ConfigurationImpl;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Autoconfiguration of rate limit at bootstrap phase.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnPolarisEnabled
|
||||
@ConditionalOnProperty(name = "spring.cloud.polaris.ratelimit.enabled", matchIfMissing = true)
|
||||
public class PolarisRateLimitBootstrapConfiguration {
|
||||
|
||||
@Bean
|
||||
public PolarisRateLimitProperties polarisRateLimitProperties() {
|
||||
return new PolarisRateLimitProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RateLimitConfigModifier rateLimitConfigModifier(PolarisRateLimitProperties polarisRateLimitProperties) {
|
||||
return new RateLimitConfigModifier(polarisRateLimitProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Config modifier for rate limit.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public static class RateLimitConfigModifier implements PolarisConfigModifier {
|
||||
|
||||
private PolarisRateLimitProperties polarisRateLimitProperties;
|
||||
|
||||
public RateLimitConfigModifier(PolarisRateLimitProperties polarisRateLimitProperties) {
|
||||
this.polarisRateLimitProperties = polarisRateLimitProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modify(ConfigurationImpl configuration) {
|
||||
// Update MaxQueuingTime.
|
||||
configuration.getProvider().getRateLimit()
|
||||
.setMaxQueuingTime(polarisRateLimitProperties.getMaxQueuingTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,2 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.tencent.cloud.polaris.ratelimit.config.RateLimitConfiguration
|
||||
com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitConfiguration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitBootstrapConfiguration
|
||||
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.protobuf.StringValue;
|
||||
import com.tencent.cloud.polaris.context.ServiceRuleManager;
|
||||
import com.tencent.polaris.client.pb.ModelProto;
|
||||
import com.tencent.polaris.client.pb.RateLimitProto;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test for {@link RateLimitRuleLabelResolver}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RateLimitRuleLabelResolverTest {
|
||||
|
||||
private ServiceRuleManager serviceRuleManager;
|
||||
|
||||
private RateLimitRuleLabelResolver rateLimitRuleLabelResolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
serviceRuleManager = mock(ServiceRuleManager.class);
|
||||
when(serviceRuleManager.getServiceRateLimitRule(any(), anyString())).thenAnswer(invocationOnMock -> {
|
||||
String serviceName = invocationOnMock.getArgument(1).toString();
|
||||
if (serviceName.equals("TestApp1")) {
|
||||
return null;
|
||||
}
|
||||
else if (serviceName.equals("TestApp2")) {
|
||||
return RateLimitProto.RateLimit.newBuilder().build();
|
||||
}
|
||||
else if (serviceName.equals("TestApp3")) {
|
||||
RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder().build();
|
||||
return RateLimitProto.RateLimit.newBuilder().addRules(rule).build();
|
||||
}
|
||||
else {
|
||||
ModelProto.MatchString matchString = ModelProto.MatchString.newBuilder()
|
||||
.setType(ModelProto.MatchString.MatchStringType.EXACT)
|
||||
.setValue(StringValue.of("value"))
|
||||
.setValueType(ModelProto.MatchString.ValueType.TEXT).build();
|
||||
RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder()
|
||||
.putLabels("${http.method}", matchString).build();
|
||||
return RateLimitProto.RateLimit.newBuilder().addRules(rule).build();
|
||||
}
|
||||
});
|
||||
|
||||
rateLimitRuleLabelResolver = new RateLimitRuleLabelResolver(serviceRuleManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExpressionLabelKeys() {
|
||||
// rateLimitRule == null
|
||||
String serviceName = "TestApp1";
|
||||
Set<String> labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
|
||||
assertThat(labelKeys).isEmpty();
|
||||
|
||||
// CollectionUtils.isEmpty(rules)
|
||||
serviceName = "TestApp2";
|
||||
labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
|
||||
assertThat(labelKeys).isEmpty();
|
||||
|
||||
// CollectionUtils.isEmpty(labels)
|
||||
serviceName = "TestApp3";
|
||||
labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
|
||||
assertThat(labelKeys).isEmpty();
|
||||
|
||||
// Has labels
|
||||
serviceName = "TestApp4";
|
||||
labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName);
|
||||
assertThat(labelKeys).isNotEmpty();
|
||||
assertThat(labelKeys).contains("${http.method}");
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.config;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisRateLimitBootstrapConfiguration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisRateLimitBootstrapConfigurationTest {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(PolarisRateLimitBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.polaris.ratelimit.enabled=true");
|
||||
|
||||
@Test
|
||||
public void testDefaultInitialization() {
|
||||
this.contextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(PolarisRateLimitProperties.class);
|
||||
assertThat(context).hasSingleBean(PolarisRateLimitBootstrapConfiguration.RateLimitConfigModifier.class);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.config;
|
||||
|
||||
import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
|
||||
import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter;
|
||||
import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter;
|
||||
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisRateLimitConfiguration}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisRateLimitConfigurationTest {
|
||||
|
||||
private ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner();
|
||||
|
||||
private WebApplicationContextRunner webApplicationContextRunner = new WebApplicationContextRunner();
|
||||
|
||||
private ReactiveWebApplicationContextRunner reactiveWebApplicationContextRunner = new ReactiveWebApplicationContextRunner();
|
||||
|
||||
@Test
|
||||
public void testNoWebApplication() {
|
||||
this.applicationContextRunner
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
PolarisContextAutoConfiguration.class,
|
||||
PolarisRateLimitProperties.class,
|
||||
PolarisRateLimitConfiguration.class))
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(LimitAPI.class);
|
||||
assertThat(context).hasSingleBean(RateLimitRuleLabelResolver.class);
|
||||
assertThat(context).doesNotHaveBean(PolarisRateLimitConfiguration.QuotaCheckFilterConfig.class);
|
||||
assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class);
|
||||
assertThat(context).doesNotHaveBean(FilterRegistrationBean.class);
|
||||
assertThat(context).doesNotHaveBean(PolarisRateLimitConfiguration.MetadataReactiveFilterConfig.class);
|
||||
assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServletWebApplication() {
|
||||
this.webApplicationContextRunner
|
||||
.withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class,
|
||||
PolarisRateLimitProperties.class,
|
||||
PolarisRateLimitConfiguration.class))
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(LimitAPI.class);
|
||||
assertThat(context).hasSingleBean(RateLimitRuleLabelResolver.class);
|
||||
assertThat(context).hasSingleBean(PolarisRateLimitConfiguration.QuotaCheckFilterConfig.class);
|
||||
assertThat(context).hasSingleBean(QuotaCheckServletFilter.class);
|
||||
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
|
||||
assertThat(context).doesNotHaveBean(PolarisRateLimitConfiguration.MetadataReactiveFilterConfig.class);
|
||||
assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReactiveWebApplication() {
|
||||
this.reactiveWebApplicationContextRunner
|
||||
.withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class,
|
||||
PolarisRateLimitProperties.class,
|
||||
PolarisRateLimitConfiguration.class))
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(LimitAPI.class);
|
||||
assertThat(context).hasSingleBean(RateLimitRuleLabelResolver.class);
|
||||
assertThat(context).doesNotHaveBean(PolarisRateLimitConfiguration.QuotaCheckFilterConfig.class);
|
||||
assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class);
|
||||
assertThat(context).doesNotHaveBean(FilterRegistrationBean.class);
|
||||
assertThat(context).hasSingleBean(PolarisRateLimitConfiguration.MetadataReactiveFilterConfig.class);
|
||||
assertThat(context).hasSingleBean(QuotaCheckReactiveFilter.class);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.config;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link PolarisRateLimitProperties}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisRateLimitPropertiesTest {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(PolarisRateLimitPropertiesAutoConfiguration.class, PolarisRateLimitProperties.class))
|
||||
.withPropertyValues("spring.cloud.polaris.ratelimit.rejectRequestTips=xxx")
|
||||
.withPropertyValues("spring.cloud.polaris.ratelimit.rejectRequestTipsFilePath=/index.html")
|
||||
.withPropertyValues("spring.cloud.polaris.ratelimit.rejectHttpCode=419")
|
||||
.withPropertyValues("spring.cloud.polaris.ratelimit.maxQueuingTime=500");
|
||||
|
||||
@Test
|
||||
public void testDefaultInitialization() {
|
||||
this.contextRunner.run(context -> {
|
||||
PolarisRateLimitProperties polarisRateLimitProperties = context.getBean(PolarisRateLimitProperties.class);
|
||||
assertThat(polarisRateLimitProperties.getRejectRequestTips()).isEqualTo("xxx");
|
||||
assertThat(polarisRateLimitProperties.getRejectRequestTipsFilePath()).isEqualTo("/index.html");
|
||||
assertThat(polarisRateLimitProperties.getRejectHttpCode()).isEqualTo(419);
|
||||
assertThat(polarisRateLimitProperties.getMaxQueuingTime()).isEqualTo(500L);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
static class PolarisRateLimitPropertiesAutoConfiguration {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.filter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.metadata.MetadataContext;
|
||||
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
|
||||
import com.tencent.cloud.common.util.ExpressionLabelUtils;
|
||||
import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
|
||||
import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant;
|
||||
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver;
|
||||
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
|
||||
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anySet;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test for {@link QuotaCheckReactiveFilter}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@SpringBootTest(classes = QuotaCheckReactiveFilterTest.TestApplication.class, properties = {
|
||||
"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"
|
||||
})
|
||||
public class QuotaCheckReactiveFilterTest {
|
||||
|
||||
private PolarisRateLimiterLabelReactiveResolver labelResolver = exchange -> Collections.singletonMap("ReactiveResolver", "ReactiveResolver");
|
||||
|
||||
private QuotaCheckReactiveFilter quotaCheckReactiveFilter;
|
||||
|
||||
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
|
||||
private static MockedStatic<ExpressionLabelUtils> expressionLabelUtilsMockedStatic;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
expressionLabelUtilsMockedStatic = mockStatic(ExpressionLabelUtils.class);
|
||||
when(ExpressionLabelUtils.resolve(any(ServerWebExchange.class), anySet())).thenReturn(Collections.singletonMap("RuleLabelResolver", "RuleLabelResolver"));
|
||||
|
||||
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
|
||||
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
||||
.thenReturn("unit-test");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
mockedApplicationContextAwareUtils.close();
|
||||
expressionLabelUtilsMockedStatic.close();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MetadataContext.LOCAL_NAMESPACE = "TEST";
|
||||
|
||||
LimitAPI limitAPI = mock(LimitAPI.class);
|
||||
when(limitAPI.getQuota(any(QuotaRequest.class))).thenAnswer(invocationOnMock -> {
|
||||
String serviceName = ((QuotaRequest) invocationOnMock.getArgument(0)).getService();
|
||||
if (serviceName.equals("TestApp1")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "QuotaResultOk"));
|
||||
}
|
||||
else if (serviceName.equals("TestApp2")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 1000, "QuotaResultOk"));
|
||||
}
|
||||
else if (serviceName.equals("TestApp3")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited"));
|
||||
}
|
||||
else {
|
||||
return new QuotaResponse(new QuotaResult(null, 0, null));
|
||||
}
|
||||
});
|
||||
|
||||
PolarisRateLimitProperties polarisRateLimitProperties = new PolarisRateLimitProperties();
|
||||
polarisRateLimitProperties.setRejectRequestTips("RejectRequestTips");
|
||||
polarisRateLimitProperties.setRejectHttpCode(419);
|
||||
|
||||
RateLimitRuleLabelResolver rateLimitRuleLabelResolver = mock(RateLimitRuleLabelResolver.class);
|
||||
when(rateLimitRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString())).thenReturn(Collections.EMPTY_SET);
|
||||
|
||||
this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, labelResolver, polarisRateLimitProperties, rateLimitRuleLabelResolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOrder() {
|
||||
assertThat(this.quotaCheckReactiveFilter.getOrder()).isEqualTo(RateLimitConstant.FILTER_ORDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInit() {
|
||||
quotaCheckReactiveFilter.init();
|
||||
try {
|
||||
Field rejectTips = QuotaCheckReactiveFilter.class.getDeclaredField("rejectTips");
|
||||
rejectTips.setAccessible(true);
|
||||
assertThat(rejectTips.get(quotaCheckReactiveFilter)).isEqualTo("RejectRequestTips");
|
||||
}
|
||||
catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuleExpressionLabels() {
|
||||
try {
|
||||
Method getCustomResolvedLabels = QuotaCheckReactiveFilter.class.getDeclaredMethod("getCustomResolvedLabels", ServerWebExchange.class);
|
||||
getCustomResolvedLabels.setAccessible(true);
|
||||
|
||||
// Mock request
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost:8080/test").build();
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||
|
||||
// labelResolver != null
|
||||
Map<String, String> result = (Map<String, String>) getCustomResolvedLabels.invoke(quotaCheckReactiveFilter, exchange);
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
assertThat(result.get("ReactiveResolver")).isEqualTo("ReactiveResolver");
|
||||
|
||||
// throw exception
|
||||
PolarisRateLimiterLabelReactiveResolver exceptionLabelResolver = new PolarisRateLimiterLabelReactiveResolver() {
|
||||
@Override
|
||||
public Map<String, String> resolve(ServerWebExchange exchange) {
|
||||
throw new RuntimeException("Mock exception.");
|
||||
}
|
||||
};
|
||||
quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(null, exceptionLabelResolver, null, null);
|
||||
result = (Map<String, String>) getCustomResolvedLabels.invoke(quotaCheckReactiveFilter, exchange);
|
||||
assertThat(result.size()).isEqualTo(0);
|
||||
|
||||
// labelResolver == null
|
||||
quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(null, null, null, null);
|
||||
result = (Map<String, String>) getCustomResolvedLabels.invoke(quotaCheckReactiveFilter, exchange);
|
||||
assertThat(result.size()).isEqualTo(0);
|
||||
|
||||
getCustomResolvedLabels.setAccessible(false);
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter() {
|
||||
// Create mock WebFilterChain
|
||||
WebFilterChain webFilterChain = serverWebExchange -> Mono.empty();
|
||||
|
||||
// Mock request
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost:8080/test").build();
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||
|
||||
quotaCheckReactiveFilter.init();
|
||||
|
||||
// Pass
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp1";
|
||||
quotaCheckReactiveFilter.filter(exchange, webFilterChain);
|
||||
|
||||
// Unirate waiting 1000ms
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp2";
|
||||
long startTimestamp = System.currentTimeMillis();
|
||||
quotaCheckReactiveFilter.filter(exchange, webFilterChain);
|
||||
assertThat(System.currentTimeMillis() - startTimestamp).isGreaterThanOrEqualTo(1000L);
|
||||
|
||||
// Rate limited
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp3";
|
||||
quotaCheckReactiveFilter.filter(exchange, webFilterChain);
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getRawStatusCode()).isEqualTo(419);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INSUFFICIENT_SPACE_ON_RESOURCE);
|
||||
|
||||
// Exception
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp4";
|
||||
quotaCheckReactiveFilter.filter(exchange, webFilterChain);
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
protected static class TestApplication {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.tencent.cloud.common.metadata.MetadataContext;
|
||||
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
|
||||
import com.tencent.cloud.common.util.ExpressionLabelUtils;
|
||||
import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
|
||||
import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver;
|
||||
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
|
||||
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anySet;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test for {@link QuotaCheckServletFilter}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@SpringBootTest(classes = QuotaCheckServletFilterTest.TestApplication.class, properties = {
|
||||
"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"
|
||||
})
|
||||
public class QuotaCheckServletFilterTest {
|
||||
|
||||
private PolarisRateLimiterLabelServletResolver labelResolver = exchange -> Collections.singletonMap("ServletResolver", "ServletResolver");
|
||||
|
||||
private QuotaCheckServletFilter quotaCheckServletFilter;
|
||||
|
||||
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
|
||||
private static MockedStatic<ExpressionLabelUtils> expressionLabelUtilsMockedStatic;
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
expressionLabelUtilsMockedStatic = mockStatic(ExpressionLabelUtils.class);
|
||||
when(ExpressionLabelUtils.resolve(any(ServerWebExchange.class), anySet())).thenReturn(Collections.singletonMap("RuleLabelResolver", "RuleLabelResolver"));
|
||||
|
||||
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
|
||||
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
||||
.thenReturn("unit-test");
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
mockedApplicationContextAwareUtils.close();
|
||||
expressionLabelUtilsMockedStatic.close();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MetadataContext.LOCAL_NAMESPACE = "TEST";
|
||||
|
||||
LimitAPI limitAPI = mock(LimitAPI.class);
|
||||
when(limitAPI.getQuota(any(QuotaRequest.class))).thenAnswer(invocationOnMock -> {
|
||||
String serviceName = ((QuotaRequest) invocationOnMock.getArgument(0)).getService();
|
||||
if (serviceName.equals("TestApp1")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "QuotaResultOk"));
|
||||
}
|
||||
else if (serviceName.equals("TestApp2")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 1000, "QuotaResultOk"));
|
||||
}
|
||||
else if (serviceName.equals("TestApp3")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited"));
|
||||
}
|
||||
else {
|
||||
return new QuotaResponse(new QuotaResult(null, 0, null));
|
||||
}
|
||||
});
|
||||
|
||||
PolarisRateLimitProperties polarisRateLimitProperties = new PolarisRateLimitProperties();
|
||||
polarisRateLimitProperties.setRejectRequestTips("RejectRequestTips");
|
||||
polarisRateLimitProperties.setRejectHttpCode(419);
|
||||
|
||||
RateLimitRuleLabelResolver rateLimitRuleLabelResolver = mock(RateLimitRuleLabelResolver.class);
|
||||
when(rateLimitRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString())).thenReturn(Collections.EMPTY_SET);
|
||||
|
||||
this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, labelResolver, polarisRateLimitProperties, rateLimitRuleLabelResolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInit() {
|
||||
quotaCheckServletFilter.init();
|
||||
try {
|
||||
Field rejectTips = QuotaCheckServletFilter.class.getDeclaredField("rejectTips");
|
||||
rejectTips.setAccessible(true);
|
||||
assertThat(rejectTips.get(quotaCheckServletFilter)).isEqualTo("RejectRequestTips");
|
||||
}
|
||||
catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRuleExpressionLabels() {
|
||||
try {
|
||||
Method getCustomResolvedLabels = QuotaCheckServletFilter.class.getDeclaredMethod("getCustomResolvedLabels", HttpServletRequest.class);
|
||||
getCustomResolvedLabels.setAccessible(true);
|
||||
|
||||
// Mock request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
// labelResolver != null
|
||||
Map<String, String> result = (Map<String, String>) getCustomResolvedLabels.invoke(quotaCheckServletFilter, request);
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
assertThat(result.get("ServletResolver")).isEqualTo("ServletResolver");
|
||||
|
||||
// throw exception
|
||||
PolarisRateLimiterLabelServletResolver exceptionLabelResolver = request1 -> {
|
||||
throw new RuntimeException("Mock exception.");
|
||||
};
|
||||
quotaCheckServletFilter = new QuotaCheckServletFilter(null, exceptionLabelResolver, null, null);
|
||||
result = (Map<String, String>) getCustomResolvedLabels.invoke(quotaCheckServletFilter, request);
|
||||
assertThat(result.size()).isEqualTo(0);
|
||||
|
||||
// labelResolver == null
|
||||
quotaCheckServletFilter = new QuotaCheckServletFilter(null, null, null, null);
|
||||
result = (Map<String, String>) getCustomResolvedLabels.invoke(quotaCheckServletFilter, request);
|
||||
assertThat(result.size()).isEqualTo(0);
|
||||
|
||||
getCustomResolvedLabels.setAccessible(false);
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoFilterInternal() {
|
||||
// Create mock FilterChain
|
||||
FilterChain filterChain = (servletRequest, servletResponse) -> {
|
||||
|
||||
};
|
||||
|
||||
// Mock request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
quotaCheckServletFilter.init();
|
||||
try {
|
||||
// Pass
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp1";
|
||||
quotaCheckServletFilter.doFilterInternal(request, response, filterChain);
|
||||
|
||||
// Unirate waiting 1000ms
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp2";
|
||||
long startTimestamp = System.currentTimeMillis();
|
||||
quotaCheckServletFilter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(System.currentTimeMillis() - startTimestamp).isGreaterThanOrEqualTo(1000L);
|
||||
|
||||
// Rate limited
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp3";
|
||||
quotaCheckServletFilter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(response.getStatus()).isEqualTo(419);
|
||||
assertThat(response.getContentAsString()).isEqualTo("RejectRequestTips");
|
||||
|
||||
|
||||
// Exception
|
||||
MetadataContext.LOCAL_SERVICE = "TestApp4";
|
||||
quotaCheckServletFilter.doFilterInternal(request, response, filterChain);
|
||||
}
|
||||
catch (ServletException | IOException e) {
|
||||
fail("Exception encountered.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
protected static class TestApplication {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.utils;
|
||||
|
||||
import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult;
|
||||
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
|
||||
import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test for {@link QuotaCheckUtils}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class QuotaCheckUtilsTest {
|
||||
|
||||
private LimitAPI limitAPI;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
limitAPI = mock(LimitAPI.class);
|
||||
when(limitAPI.getQuota(any(QuotaRequest.class))).thenAnswer(invocationOnMock -> {
|
||||
String serviceName = ((QuotaRequest) invocationOnMock.getArgument(0)).getService();
|
||||
if (serviceName.equals("TestApp1")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "QuotaResultOk"));
|
||||
}
|
||||
else if (serviceName.equals("TestApp2")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 1000, "QuotaResultOk"));
|
||||
}
|
||||
else if (serviceName.equals("TestApp3")) {
|
||||
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited"));
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("Mock exception.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetQuota() {
|
||||
// Pass
|
||||
String serviceName = "TestApp1";
|
||||
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null, null);
|
||||
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
|
||||
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
|
||||
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk");
|
||||
|
||||
// Unirate waiting 1000ms
|
||||
serviceName = "TestApp2";
|
||||
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null, null);
|
||||
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
|
||||
assertThat(quotaResponse.getWaitMs()).isEqualTo(1000);
|
||||
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk");
|
||||
|
||||
// Rate limited
|
||||
serviceName = "TestApp3";
|
||||
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null, null);
|
||||
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited);
|
||||
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
|
||||
assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited");
|
||||
|
||||
// Exception
|
||||
serviceName = "TestApp4";
|
||||
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null, null);
|
||||
assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk);
|
||||
assertThat(quotaResponse.getWaitMs()).isEqualTo(0);
|
||||
assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed");
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.polaris.ratelimit.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.tencent.cloud.common.util.ResourceFileUtils;
|
||||
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.QUOTA_LIMITED_INFO;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test for {@link RateLimitUtils}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RateLimitUtilsTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws IOException {
|
||||
mockStatic(ResourceFileUtils.class);
|
||||
when(ResourceFileUtils.readFile(anyString())).thenAnswer(invocation -> {
|
||||
String rejectFilePath = invocation.getArgument(0).toString();
|
||||
if (rejectFilePath.equals("exception.html")) {
|
||||
throw new IOException("Mock exceptions");
|
||||
}
|
||||
else {
|
||||
return "RejectRequestTips";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRejectTips() {
|
||||
PolarisRateLimitProperties polarisRateLimitProperties = new PolarisRateLimitProperties();
|
||||
|
||||
// RejectRequestTips
|
||||
polarisRateLimitProperties.setRejectRequestTips("RejectRequestTips");
|
||||
assertThat(RateLimitUtils.getRejectTips(polarisRateLimitProperties)).isEqualTo("RejectRequestTips");
|
||||
|
||||
// RejectRequestTipsFilePath
|
||||
polarisRateLimitProperties.setRejectRequestTips(null);
|
||||
polarisRateLimitProperties.setRejectRequestTipsFilePath("reject-tips.html");
|
||||
assertThat(RateLimitUtils.getRejectTips(polarisRateLimitProperties)).isEqualTo("RejectRequestTips");
|
||||
|
||||
// RejectRequestTipsFilePath with Exception
|
||||
polarisRateLimitProperties.setRejectRequestTips(null);
|
||||
polarisRateLimitProperties.setRejectRequestTipsFilePath("exception.html");
|
||||
assertThat(RateLimitUtils.getRejectTips(polarisRateLimitProperties)).isEqualTo(QUOTA_LIMITED_INFO);
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.metadata;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* manage metadata from env/config file.
|
||||
*
|
||||
*@author lepdou 2022-05-20
|
||||
*/
|
||||
public class StaticMetadataManager {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StaticMetadataManager.class);
|
||||
|
||||
private static final String ENV_METADATA_PREFIX = "SCT_METADATA_CONTENT_";
|
||||
private static final int ENV_METADATA_PREFIX_LENGTH = ENV_METADATA_PREFIX.length();
|
||||
private static final String ENV_METADATA_CONTENT_TRANSITIVE = "SCT_METADATA_CONTENT_TRANSITIVE";
|
||||
private static final String ENV_METADATA_ZONE = "SCT_METADATA_ZONE";
|
||||
private static final String ENV_METADATA_REGION = "SCT_METADATA_REGION";
|
||||
private static final String ENV_METADATA_CAMPUS = "SCT_METADATA_CAMPUS";
|
||||
|
||||
private static final String LOCATION_KEY_REGION = "region";
|
||||
private static final String LOCATION_KEY_ZONE = "zone";
|
||||
private static final String LOCATION_KEY_CAMPUS = "campus";
|
||||
|
||||
private Map<String, String> envMetadata;
|
||||
private Map<String, String> envTransitiveMetadata;
|
||||
private Map<String, String> configMetadata;
|
||||
private Map<String, String> configTransitiveMetadata;
|
||||
private Map<String, String> mergedStaticMetadata;
|
||||
private Map<String, String> mergedStaticTransitiveMetadata;
|
||||
private String zone;
|
||||
private String region;
|
||||
private String campus;
|
||||
|
||||
public StaticMetadataManager(MetadataLocalProperties metadataLocalProperties) {
|
||||
parseConfigMetadata(metadataLocalProperties);
|
||||
parseEnvMetadata();
|
||||
merge();
|
||||
parseLocationMetadata();
|
||||
|
||||
LOGGER.info("[SCT] Loaded static metadata info. {}", this);
|
||||
}
|
||||
|
||||
private void parseEnvMetadata() {
|
||||
Map<String, String> allEnvs = System.getenv();
|
||||
|
||||
envMetadata = new HashMap<>();
|
||||
// parse all metadata
|
||||
for (Map.Entry<String, String> entry : allEnvs.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (StringUtils.isNotBlank(key) && key.startsWith(ENV_METADATA_PREFIX)
|
||||
&& !key.equals(ENV_METADATA_CONTENT_TRANSITIVE)) {
|
||||
String sourceKey = StringUtils.substring(key, ENV_METADATA_PREFIX_LENGTH);
|
||||
envMetadata.put(sourceKey, value);
|
||||
|
||||
LOGGER.info("[SCT] resolve metadata from env. key = {}, value = {}", sourceKey, value);
|
||||
}
|
||||
}
|
||||
envMetadata = Collections.unmodifiableMap(envMetadata);
|
||||
|
||||
envTransitiveMetadata = new HashMap<>();
|
||||
// parse transitive metadata
|
||||
String transitiveKeys = allEnvs.get(ENV_METADATA_CONTENT_TRANSITIVE);
|
||||
if (StringUtils.isNotBlank(transitiveKeys)) {
|
||||
String[] keyArr = StringUtils.split(transitiveKeys, ",");
|
||||
if (keyArr != null && keyArr.length > 0) {
|
||||
for (String key : keyArr) {
|
||||
String value = envMetadata.get(key);
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
envTransitiveMetadata.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
envTransitiveMetadata = Collections.unmodifiableMap(envTransitiveMetadata);
|
||||
}
|
||||
|
||||
private void parseConfigMetadata(MetadataLocalProperties metadataLocalProperties) {
|
||||
Map<String, String> allMetadata = metadataLocalProperties.getContent();
|
||||
List<String> transitiveKeys = metadataLocalProperties.getTransitive();
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
for (String key : transitiveKeys) {
|
||||
if (allMetadata.containsKey(key)) {
|
||||
result.put(key, allMetadata.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
configTransitiveMetadata = Collections.unmodifiableMap(result);
|
||||
configMetadata = Collections.unmodifiableMap(allMetadata);
|
||||
}
|
||||
|
||||
private void merge() {
|
||||
// env priority is bigger than config
|
||||
Map<String, String> mergedMetadataResult = new HashMap<>();
|
||||
|
||||
mergedMetadataResult.putAll(configMetadata);
|
||||
mergedMetadataResult.putAll(envMetadata);
|
||||
|
||||
this.mergedStaticMetadata = Collections.unmodifiableMap(mergedMetadataResult);
|
||||
|
||||
Map<String, String> mergedTransitiveMetadataResult = new HashMap<>();
|
||||
mergedTransitiveMetadataResult.putAll(configTransitiveMetadata);
|
||||
mergedTransitiveMetadataResult.putAll(envTransitiveMetadata);
|
||||
|
||||
this.mergedStaticTransitiveMetadata = Collections.unmodifiableMap(mergedTransitiveMetadataResult);
|
||||
}
|
||||
|
||||
private void parseLocationMetadata() {
|
||||
zone = System.getenv(ENV_METADATA_ZONE);
|
||||
region = System.getenv(ENV_METADATA_REGION);
|
||||
campus = System.getenv(ENV_METADATA_CAMPUS);
|
||||
}
|
||||
|
||||
public Map<String, String> getAllEnvMetadata() {
|
||||
return envMetadata;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvTransitiveMetadata() {
|
||||
return envTransitiveMetadata;
|
||||
}
|
||||
|
||||
public Map<String, String> getAllConfigMetadata() {
|
||||
return configMetadata;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfigTransitiveMetadata() {
|
||||
return configTransitiveMetadata;
|
||||
}
|
||||
|
||||
public Map<String, String> getMergedStaticMetadata() {
|
||||
return mergedStaticMetadata;
|
||||
}
|
||||
|
||||
public Map<String, String> getMergedStaticTransitiveMetadata() {
|
||||
return mergedStaticTransitiveMetadata;
|
||||
}
|
||||
|
||||
public String getZone() {
|
||||
return zone;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public String getCampus() {
|
||||
return campus;
|
||||
}
|
||||
|
||||
public Map<String, String> getLocationMetadata() {
|
||||
Map<String, String> locationMetadata = new HashMap<>();
|
||||
if (StringUtils.isNotBlank(region)) {
|
||||
locationMetadata.put(LOCATION_KEY_REGION, region);
|
||||
}
|
||||
if (StringUtils.isNotBlank(zone)) {
|
||||
locationMetadata.put(LOCATION_KEY_ZONE, zone);
|
||||
}
|
||||
if (StringUtils.isNotBlank(campus)) {
|
||||
locationMetadata.put(LOCATION_KEY_CAMPUS, campus);
|
||||
}
|
||||
return locationMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StaticMetadataManager{" +
|
||||
"envMetadata=" + envMetadata +
|
||||
", envTransitiveMetadata=" + envTransitiveMetadata +
|
||||
", configMetadata=" + configMetadata +
|
||||
", configTransitiveMetadata=" + configTransitiveMetadata +
|
||||
", mergedStaticMetadata=" + mergedStaticMetadata +
|
||||
", mergedStaticTransitiveMetadata=" + mergedStaticTransitiveMetadata +
|
||||
", zone='" + zone + '\'' +
|
||||
", region='" + region + '\'' +
|
||||
", campus='" + campus + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
|
||||
/**
|
||||
* the utils for bean factory.
|
||||
* @author lepdou 2022-05-23
|
||||
*/
|
||||
public class BeanFactoryUtils {
|
||||
|
||||
public static <T> List<T> getBeans(BeanFactory beanFactory, Class<T> requiredType) {
|
||||
if (!(beanFactory instanceof DefaultListableBeanFactory)) {
|
||||
throw new RuntimeException("bean factory not support get list bean. factory type = " + beanFactory.getClass()
|
||||
.getName());
|
||||
}
|
||||
|
||||
String[] beanNames = ((DefaultListableBeanFactory) beanFactory).getBeanNamesForType(requiredType);
|
||||
|
||||
if (beanNames.length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Arrays.stream(beanNames).map(
|
||||
beanName -> beanFactory.getBean(beanName, requiredType)
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* the utils for parse label expression.
|
||||
*
|
||||
*@author lepdou 2022-05-13
|
||||
*/
|
||||
public class ExpressionLabelUtils {
|
||||
|
||||
/**
|
||||
* the expression prefix of header label.
|
||||
*/
|
||||
public static final String LABEL_HEADER_PREFIX = "${http.header.";
|
||||
/**
|
||||
* the length of expression header label prefix.
|
||||
*/
|
||||
public static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length();
|
||||
/**
|
||||
* the expression prefix of query.
|
||||
*/
|
||||
public static final String LABEL_QUERY_PREFIX = "${http.query.";
|
||||
/**
|
||||
* the length of expression query label prefix.
|
||||
*/
|
||||
public static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length();
|
||||
/**
|
||||
* the expression prefix of cookie.
|
||||
*/
|
||||
public static final String LABEL_COOKIE_PREFIX = "${http.cookie.";
|
||||
/**
|
||||
* the length of expression cookie label prefix.
|
||||
*/
|
||||
public static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length();
|
||||
/**
|
||||
* the expression of method.
|
||||
*/
|
||||
public static final String LABEL_METHOD = "${http.method}";
|
||||
/**
|
||||
* the expression of uri.
|
||||
*/
|
||||
public static final String LABEL_URI = "${http.uri}";
|
||||
/**
|
||||
* the prefix of expression.
|
||||
*/
|
||||
public static final String LABEL_PREFIX = "${";
|
||||
/**
|
||||
* the suffix of expression.
|
||||
*/
|
||||
public static final String LABEL_SUFFIX = "}";
|
||||
/**
|
||||
* the escape prefix of label.
|
||||
*/
|
||||
public static final String LABEL_ESCAPE_PREFIX = "##@$@##";
|
||||
|
||||
public static boolean isExpressionLabel(String labelKey) {
|
||||
if (StringUtils.isEmpty(labelKey)) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey) ||
|
||||
StringUtils.startsWithIgnoreCase(LABEL_URI, labelKey)) {
|
||||
return true;
|
||||
}
|
||||
return (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX) ||
|
||||
StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX) ||
|
||||
StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX))
|
||||
&& StringUtils.endsWith(labelKey, LABEL_SUFFIX);
|
||||
}
|
||||
|
||||
public static String escape(String str) {
|
||||
return StringUtils.replace(str, LABEL_PREFIX, LABEL_ESCAPE_PREFIX);
|
||||
}
|
||||
|
||||
public static String unescape(String str) {
|
||||
return StringUtils.replace(str, LABEL_ESCAPE_PREFIX, LABEL_PREFIX);
|
||||
}
|
||||
|
||||
public static Map<String, String> resolve(HttpServletRequest request, Set<String> labelKeys) {
|
||||
if (CollectionUtils.isEmpty(labelKeys)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
|
||||
for (String labelKey : labelKeys) {
|
||||
if (!isExpressionLabel(labelKey)) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) {
|
||||
String headerKey = parseHeaderKey(labelKey);
|
||||
if (StringUtils.isBlank(headerKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, request.getHeader(headerKey));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) {
|
||||
String queryKey = parseQueryKey(labelKey);
|
||||
if (StringUtils.isBlank(queryKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getQueryValue(request.getQueryString(), queryKey));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) {
|
||||
String cookieKey = parseCookieKey(labelKey);
|
||||
if (StringUtils.isBlank(cookieKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getCookieValue(request.getCookies(), cookieKey));
|
||||
}
|
||||
else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) {
|
||||
labels.put(labelKey, request.getMethod());
|
||||
}
|
||||
else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) {
|
||||
labels.put(labelKey, request.getRequestURI());
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public static Map<String, String> resolve(ServerWebExchange exchange, Set<String> labelKeys) {
|
||||
if (CollectionUtils.isEmpty(labelKeys)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
|
||||
for (String labelKey : labelKeys) {
|
||||
if (!isExpressionLabel(labelKey)) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) {
|
||||
String headerKey = parseHeaderKey(labelKey);
|
||||
if (StringUtils.isBlank(headerKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getHeaderValue(exchange.getRequest(), headerKey));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) {
|
||||
String queryKey = parseQueryKey(labelKey);
|
||||
if (StringUtils.isBlank(queryKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getQueryValue(exchange.getRequest(), queryKey));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) {
|
||||
String cookieKey = parseCookieKey(labelKey);
|
||||
if (StringUtils.isBlank(cookieKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey));
|
||||
}
|
||||
else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) {
|
||||
labels.put(labelKey, exchange.getRequest().getMethodValue());
|
||||
}
|
||||
else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) {
|
||||
labels.put(labelKey, exchange.getRequest().getURI().getPath());
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public static Map<String, String> resolve(HttpRequest request, Set<String> labelKeys) {
|
||||
if (CollectionUtils.isEmpty(labelKeys)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
|
||||
for (String labelKey : labelKeys) {
|
||||
if (!isExpressionLabel(labelKey)) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) {
|
||||
String headerKey = parseHeaderKey(labelKey);
|
||||
if (StringUtils.isBlank(headerKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getHeaderValue(request, headerKey));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) {
|
||||
String queryKey = parseQueryKey(labelKey);
|
||||
if (StringUtils.isBlank(queryKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getQueryValue(request, queryKey));
|
||||
}
|
||||
else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) {
|
||||
labels.put(labelKey, request.getMethodValue());
|
||||
}
|
||||
else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) {
|
||||
labels.put(labelKey, request.getURI().getPath());
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public static String parseHeaderKey(String expression) {
|
||||
return expression.substring(LABEL_HEADER_PREFIX_LEN, expression.length() - 1);
|
||||
}
|
||||
|
||||
public static String parseQueryKey(String expression) {
|
||||
return expression.substring(LABEL_QUERY_PREFIX_LEN, expression.length() - 1);
|
||||
}
|
||||
|
||||
public static String parseCookieKey(String expression) {
|
||||
return expression.substring(LABEL_COOKIE_PREFIX_LEN, expression.length() - 1);
|
||||
}
|
||||
|
||||
public static String getQueryValue(String queryString, String queryKey) {
|
||||
if (StringUtils.isBlank(queryString)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
String[] queries = StringUtils.split(queryString, "&");
|
||||
if (queries == null || queries.length == 0) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
for (String query : queries) {
|
||||
String[] queryKV = StringUtils.split(query, "=");
|
||||
if (queryKV != null && queryKV.length == 2 && StringUtils.equals(queryKV[0], queryKey)) {
|
||||
return queryKV[1];
|
||||
}
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
public static String getCookieValue(Cookie[] cookies, String key) {
|
||||
if (cookies == null || cookies.length == 0) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
for (Cookie cookie : cookies) {
|
||||
if (StringUtils.equals(cookie.getName(), key)) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
public static String getHeaderValue(ServerHttpRequest request, String key) {
|
||||
String value = request.getHeaders().getFirst(key);
|
||||
if (value == null) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getQueryValue(ServerHttpRequest request, String key) {
|
||||
MultiValueMap<String, String> queries = request.getQueryParams();
|
||||
if (CollectionUtils.isEmpty(queries)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
String value = queries.getFirst(key);
|
||||
if (value == null) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getCookieValue(ServerHttpRequest request, String key) {
|
||||
HttpCookie cookie = request.getCookies().getFirst(key);
|
||||
if (cookie == null) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return cookie.getValue();
|
||||
}
|
||||
|
||||
public static String getHeaderValue(HttpRequest request, String key) {
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
return headers.getFirst(key);
|
||||
}
|
||||
|
||||
public static String getQueryValue(HttpRequest request, String key) {
|
||||
String query = request.getURI().getQuery();
|
||||
return getQueryValue(query, key);
|
||||
}
|
||||
|
||||
public static String getFirstValue(Map<String, Collection<String>> valueMaps, String key) {
|
||||
if (CollectionUtils.isEmpty(valueMaps)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
Collection<String> values = valueMaps.get(key);
|
||||
|
||||
if (CollectionUtils.isEmpty(values)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
for (String value : values) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* test for {@link AddressUtils}
|
||||
*@author lepdou 2022-05-27
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AddressUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testEmptyStr() {
|
||||
List<String> result = AddressUtils.parseAddressList("");
|
||||
Assert.assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullStr() {
|
||||
List<String> result = AddressUtils.parseAddressList(null);
|
||||
Assert.assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneStr() {
|
||||
String host1 = "http://localhost";
|
||||
List<String> result = AddressUtils.parseAddressList(host1);
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertTrue(result.contains("localhost"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiStr() {
|
||||
String host1 = "http://localhost";
|
||||
String host2 = "http://localhost2";
|
||||
String host3 = "http://localhost3";
|
||||
List<String> result = AddressUtils.parseAddressList(host1 + "," + host2 + "," + host3);
|
||||
Assert.assertEquals(3, result.size());
|
||||
Assert.assertTrue(result.contains("localhost"));
|
||||
Assert.assertTrue(result.contains("localhost2"));
|
||||
Assert.assertTrue(result.contains("localhost3"));
|
||||
}
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.http.client.MockClientHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.MockCookie;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
|
||||
/**
|
||||
* test for {@link ExpressionLabelUtils}
|
||||
*@author lepdou 2022-05-27
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ExpressionLabelUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testExpressionLabel() {
|
||||
String validLabel1 = "${http.query.uid}";
|
||||
String validLabel2 = "${http.header.uid}";
|
||||
String validLabel3 = "${http.cookie.uid}";
|
||||
String validLabel4 = "${http.method}";
|
||||
String validLabel5 = "${http.uri}";
|
||||
String invalidLabel1 = "${http.queryuid}";
|
||||
String invalidLabel2 = "{http.query.uid}";
|
||||
String invalidLabel3 = "${http.query.uid";
|
||||
String invalidLabel4 = "$ {http.query.uid}";
|
||||
String invalidLabel5 = "${ http.query.uid}";
|
||||
String invalidLabel6 = "${query.uid}";
|
||||
String invalidLabel7 = "http.query.uid";
|
||||
String invalidLabel8 = "$${http.uri}";
|
||||
String invalidLabel9 = "#{http.uri}";
|
||||
|
||||
Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel1));
|
||||
Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel2));
|
||||
Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel3));
|
||||
Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel4));
|
||||
Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel5));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel1));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel2));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel3));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel4));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel5));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel6));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel7));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel8));
|
||||
Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel9));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscape() {
|
||||
String validLabel1 = "${http.query.uid}";
|
||||
String validLabel2 = "${http.header.uid}";
|
||||
String validLabel3 = "${http.cookie.uid}";
|
||||
String validLabel4 = "${http.method}";
|
||||
String validLabel5 = "${http.uri}";
|
||||
String invalidLabel1 = "${http.queryuid}";
|
||||
String invalidLabel2 = "{http.query.uid}";
|
||||
String invalidLabel3 = "${http.query.uid";
|
||||
String invalidLabel4 = "$ {http.query.uid}";
|
||||
String invalidLabel5 = "${ http.query.uid}";
|
||||
String invalidLabel6 = "${query.uid}";
|
||||
String invalidLabel7 = "http.query.uid";
|
||||
String invalidLabel8 = "$${http.uri}";
|
||||
String invalidLabel9 = "#{http.uri}";
|
||||
|
||||
Assert.assertEquals(validLabel1, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel1)));
|
||||
Assert.assertEquals(validLabel2, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel2)));
|
||||
Assert.assertEquals(validLabel3, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel3)));
|
||||
Assert.assertEquals(validLabel4, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel4)));
|
||||
Assert.assertEquals(validLabel5, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(validLabel5)));
|
||||
Assert.assertEquals(invalidLabel1, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel1)));
|
||||
Assert.assertEquals(invalidLabel2, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel2)));
|
||||
Assert.assertEquals(invalidLabel3, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel3)));
|
||||
Assert.assertEquals(invalidLabel4, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel4)));
|
||||
Assert.assertEquals(invalidLabel5, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel5)));
|
||||
Assert.assertEquals(invalidLabel6, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel6)));
|
||||
Assert.assertEquals(invalidLabel7, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel7)));
|
||||
Assert.assertEquals(invalidLabel8, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel8)));
|
||||
Assert.assertEquals(invalidLabel9, ExpressionLabelUtils.unescape(ExpressionLabelUtils.escape(invalidLabel9)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveHttpServletRequest() {
|
||||
String validLabel1 = "${http.query.uid}";
|
||||
String validLabel2 = "${http.header.uid}";
|
||||
String validLabel3 = "${http.cookie.uid}";
|
||||
String validLabel4 = "${http.method}";
|
||||
String validLabel5 = "${http.uri}";
|
||||
String invalidLabel1 = "${http.queryuid}";
|
||||
String invalidLabel2 = "{http.query.uid}";
|
||||
String invalidLabel3 = "${http.query.uid";
|
||||
String invalidLabel4 = "$ {http.query.uid}";
|
||||
String invalidLabel5 = "${ http.query.uid}";
|
||||
String invalidLabel6 = "${query.uid}";
|
||||
String invalidLabel7 = "http.query.uid";
|
||||
String invalidLabel8 = "$${http.uri}";
|
||||
String invalidLabel9 = "#{http.uri}";
|
||||
|
||||
Set<String> labelKeys = Sets.newHashSet(validLabel1, validLabel2, validLabel3, validLabel4, validLabel5,
|
||||
invalidLabel1, invalidLabel2, invalidLabel3, invalidLabel4, invalidLabel5, invalidLabel6, invalidLabel7,
|
||||
invalidLabel8, invalidLabel9);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setQueryString("uid=zhangsan");
|
||||
request.addHeader("uid", "zhangsan");
|
||||
request.setCookies(new MockCookie("uid", "zhangsan"));
|
||||
request.setMethod(HttpMethod.GET.name());
|
||||
request.setRequestURI("/users");
|
||||
|
||||
Map<String, String> result = ExpressionLabelUtils.resolve(request, labelKeys);
|
||||
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel1));
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel2));
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel3));
|
||||
Assert.assertEquals("GET", result.get(validLabel4));
|
||||
Assert.assertEquals("/users", result.get(validLabel5));
|
||||
Assert.assertNull(result.get(invalidLabel1));
|
||||
Assert.assertNull(result.get(invalidLabel2));
|
||||
Assert.assertNull(result.get(invalidLabel3));
|
||||
Assert.assertNull(result.get(invalidLabel4));
|
||||
Assert.assertNull(result.get(invalidLabel5));
|
||||
Assert.assertNull(result.get(invalidLabel6));
|
||||
Assert.assertNull(result.get(invalidLabel7));
|
||||
Assert.assertNull(result.get(invalidLabel8));
|
||||
Assert.assertNull(result.get(invalidLabel9));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveServerWebExchange() {
|
||||
String validLabel1 = "${http.query.uid}";
|
||||
String validLabel2 = "${http.header.uid}";
|
||||
String validLabel3 = "${http.cookie.uid}";
|
||||
String validLabel4 = "${http.method}";
|
||||
String validLabel5 = "${http.uri}";
|
||||
String invalidLabel1 = "${http.queryuid}";
|
||||
String invalidLabel2 = "{http.query.uid}";
|
||||
String invalidLabel3 = "${http.query.uid";
|
||||
String invalidLabel4 = "$ {http.query.uid}";
|
||||
String invalidLabel5 = "${ http.query.uid}";
|
||||
String invalidLabel6 = "${query.uid}";
|
||||
String invalidLabel7 = "http.query.uid";
|
||||
String invalidLabel8 = "$${http.uri}";
|
||||
String invalidLabel9 = "#{http.uri}";
|
||||
|
||||
Set<String> labelKeys = Sets.newHashSet(validLabel1, validLabel2, validLabel3, validLabel4, validLabel5,
|
||||
invalidLabel1, invalidLabel2, invalidLabel3, invalidLabel4, invalidLabel5, invalidLabel6, invalidLabel7,
|
||||
invalidLabel8, invalidLabel9);
|
||||
|
||||
MockServerHttpRequest httpRequest = MockServerHttpRequest.get("http://calleeService/user/get?uid=zhangsan")
|
||||
.header("uid", "zhangsan")
|
||||
.cookie(new HttpCookie("uid", "zhangsan")).build();
|
||||
MockServerWebExchange exchange = new MockServerWebExchange.Builder(httpRequest).build();
|
||||
|
||||
Map<String, String> result = ExpressionLabelUtils.resolve(exchange, labelKeys);
|
||||
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel1));
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel2));
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel3));
|
||||
Assert.assertEquals("GET", result.get(validLabel4));
|
||||
Assert.assertEquals("/user/get", result.get(validLabel5));
|
||||
Assert.assertNull(result.get(invalidLabel1));
|
||||
Assert.assertNull(result.get(invalidLabel2));
|
||||
Assert.assertNull(result.get(invalidLabel3));
|
||||
Assert.assertNull(result.get(invalidLabel4));
|
||||
Assert.assertNull(result.get(invalidLabel5));
|
||||
Assert.assertNull(result.get(invalidLabel6));
|
||||
Assert.assertNull(result.get(invalidLabel7));
|
||||
Assert.assertNull(result.get(invalidLabel8));
|
||||
Assert.assertNull(result.get(invalidLabel9));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveHttpRequest() {
|
||||
String validLabel1 = "${http.query.uid}";
|
||||
String validLabel2 = "${http.header.uid}";
|
||||
String validLabel3 = "${http.cookie.uid}";
|
||||
String validLabel4 = "${http.method}";
|
||||
String validLabel5 = "${http.uri}";
|
||||
String invalidLabel1 = "${http.queryuid}";
|
||||
String invalidLabel2 = "{http.query.uid}";
|
||||
String invalidLabel3 = "${http.query.uid";
|
||||
String invalidLabel4 = "$ {http.query.uid}";
|
||||
String invalidLabel5 = "${ http.query.uid}";
|
||||
String invalidLabel6 = "${query.uid}";
|
||||
String invalidLabel7 = "http.query.uid";
|
||||
String invalidLabel8 = "$${http.uri}";
|
||||
String invalidLabel9 = "#{http.uri}";
|
||||
|
||||
Set<String> labelKeys = Sets.newHashSet(validLabel1, validLabel2, validLabel3, validLabel4, validLabel5,
|
||||
invalidLabel1, invalidLabel2, invalidLabel3, invalidLabel4, invalidLabel5, invalidLabel6, invalidLabel7,
|
||||
invalidLabel8, invalidLabel9);
|
||||
|
||||
MockClientHttpRequest request = new MockClientHttpRequest();
|
||||
request.setMethod(HttpMethod.GET);
|
||||
request.setURI(URI.create("http://calleeService/user/get?uid=zhangsan"));
|
||||
request.getHeaders().add("uid", "zhangsan");
|
||||
|
||||
Map<String, String> result = ExpressionLabelUtils.resolve(request, labelKeys);
|
||||
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel1));
|
||||
Assert.assertEquals("zhangsan", result.get(validLabel2));
|
||||
Assert.assertNull(result.get(validLabel3));
|
||||
Assert.assertEquals("GET", result.get(validLabel4));
|
||||
Assert.assertEquals("/user/get", result.get(validLabel5));
|
||||
Assert.assertNull(result.get(invalidLabel1));
|
||||
Assert.assertNull(result.get(invalidLabel2));
|
||||
Assert.assertNull(result.get(invalidLabel3));
|
||||
Assert.assertNull(result.get(invalidLabel4));
|
||||
Assert.assertNull(result.get(invalidLabel5));
|
||||
Assert.assertNull(result.get(invalidLabel6));
|
||||
Assert.assertNull(result.get(invalidLabel7));
|
||||
Assert.assertNull(result.get(invalidLabel8));
|
||||
Assert.assertNull(result.get(invalidLabel9));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Test for {@link JacksonUtils}.
|
||||
*
|
||||
* @author lepdou, Haotian Zhang
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JacksonUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testSerialize2Json() {
|
||||
Map<String, String> sourceMap = new HashMap<>();
|
||||
sourceMap.put("k1", "v1");
|
||||
sourceMap.put("k2", "v2");
|
||||
sourceMap.put("k3", "v3");
|
||||
|
||||
String jsonStr = JacksonUtils.serialize2Json(sourceMap);
|
||||
|
||||
assertThat(jsonStr).isEqualTo("{\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeserialize2Map() {
|
||||
String jsonStr = "{\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\"}";
|
||||
Map<String, String> map = JacksonUtils.deserialize2Map(jsonStr);
|
||||
assertThat(map.size()).isEqualTo(3);
|
||||
assertThat(map.get("k1")).isEqualTo("v1");
|
||||
assertThat(map.get("k2")).isEqualTo("v2");
|
||||
assertThat(map.get("k3")).isEqualTo("v3");
|
||||
|
||||
assertThat(JacksonUtils.deserialize2Map("")).isNotNull();
|
||||
assertThat(JacksonUtils.deserialize2Map("")).isEmpty();
|
||||
|
||||
jsonStr = "{\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\"";
|
||||
try {
|
||||
JacksonUtils.deserialize2Map(jsonStr);
|
||||
fail("RuntimeException should be thrown.");
|
||||
}
|
||||
catch (RuntimeException exception) {
|
||||
assertThat(exception.getMessage()).isEqualTo("Json to map failed.");
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
fail("RuntimeException should be thrown.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* test for {@link ResourceFileUtils}
|
||||
*@author lepdou 2022-05-27
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ResourceFileUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testReadExistedFile() throws IOException {
|
||||
String content = ResourceFileUtils.readFile("test.txt");
|
||||
Assert.assertEquals("just for test\n", content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNotExistedFile() throws IOException {
|
||||
String content = ResourceFileUtils.readFile("not_existed_test.txt");
|
||||
Assert.assertEquals("", content);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
just for test
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue