refactor unit test

1.Add test thread timeout setting
2.Add junit5 to initialize different configurations according to the hook function
pull/2694/head
windwheel 3 years ago
parent 2bfc4d2c15
commit 066587d3b5

@ -40,6 +40,11 @@ public class UserProperties {
public static class User {
private String name;
private Integer age;
public User(String name, Integer age){
this.name = name;
this.age = age;
}
}
}

@ -16,26 +16,29 @@
package com.alibaba.cloud.tests.nacos.config;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.testsupport.ContainerStarter;
import com.alibaba.cloud.testsupport.HasDockerAndItEnabled;
import com.alibaba.cloud.testsupport.Tester;
import com.alibaba.cloud.testsupport.*;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
import java.io.*;
import java.util.*;
import static com.alibaba.cloud.tests.nacos.config.NacosConfigRefreshTest.PushConfigConfiguration;
import static com.alibaba.cloud.testsupport.Constant.REFRESH_CONFIG;
import static com.alibaba.cloud.testsupport.Constant.TIME_OUT;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import static org.mockito.Mockito.when;
/**
*
@ -43,55 +46,61 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
*
* @author freeman
*/
@HasDockerAndItEnabled
@SpringBootTest(classes = NacosConfigTestApplication.class, webEnvironment = RANDOM_PORT, properties = {
"spring.profiles.active=nacos-config-refresh"
})
@Import(PushConfigConfiguration.class)
//@HasDockerAndItEnabled
@SpringCloudAlibaba(composeFiles = "docker/nacos-compose-test.yml", serviceName = "nacos-standalone")
@TestExtend(time = 3* TIME_OUT)
public class NacosConfigRefreshTest {
static GenericContainer nacos = ContainerStarter.startNacos();
private static final String serverAddr;
static {
serverAddr = "localhost:" + nacos.getMappedPort(8848);
System.setProperty("spring.cloud.nacos.config.server-addr", serverAddr);
@Mock
protected ConfigService service1;
@BeforeAll
public static void setUp(){
}
@BeforeEach
public void prepare() throws NacosException {
Properties nacosSettings = new Properties();
String serverIp8 = "127.0.0.1:8848";
nacosSettings.put(PropertyKeyConst.SERVER_ADDR, serverIp8);
nacosSettings.put(PropertyKeyConst.USERNAME, "nacos");
nacosSettings.put(PropertyKeyConst.PASSWORD, "nacos");
service1 = ConfigFactory.createConfigService(nacosSettings);
}
@Autowired
private NacosConfigManager nacosConfigManager;
@Autowired
private UserProperties userProperties;
@Test
public void testRefreshConfig() throws InterruptedException {
// make sure everything is ready !
Thread.sleep(2000L);
Tester.testFunction("Pull config from Nacos", () -> {
assertThat(userProperties.getAge()).isEqualTo(21);
assertThat(userProperties.getName()).isEqualTo("freeman");
assertThat(userProperties.getMap().size()).isEqualTo(2);
assertThat(userProperties.getUsers().size()).isEqualTo(2);
});
Tester.testFunction("Dynamic refresh config", () -> {
// update config
updateConfig();
// wait config refresh
Thread.sleep(2000L);
assertThat(userProperties.getAge()).isEqualTo(22);
assertThat(userProperties.getName()).isEqualTo("freeman1123");
assertThat(userProperties.getMap().size()).isEqualTo(3);
assertThat(userProperties.getUsers().size()).isEqualTo(2);
String content = service1.getConfig("nacos-config-refresh.yml", "DEFAULT_GROUP", TIME_OUT);
ClassPathResource classPathResource = new ClassPathResource(REFRESH_CONFIG);
File file = classPathResource.getFile();
final BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
sb.append(line).append("\n");
}
sb.deleteCharAt(sb.length()-1);
assertThat(content).isEqualTo(sb.toString());
});
}
private void updateConfig() throws NacosException {
nacosConfigManager.getConfigService().publishConfig("nacos-config-refresh.yml", "DEFAULT_GROUP",
service1.publishConfig("nacos-config-refresh.yml", "DEFAULT_GROUP",
"configdata:\n" +
" user:\n" +
" age: 22\n" +
@ -110,38 +119,4 @@ public class NacosConfigRefreshTest {
" age: 18",
"yaml");
}
static class PushConfigConfiguration {
@Autowired
private NacosConfigManager nacosConfigManager;
@EventListener(ApplicationReadyEvent.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
public void applicationReadyEventApplicationListener() throws NacosException {
// push the config before listening the config
pushConfig2Nacos(nacosConfigManager.getConfigService());
}
private static void pushConfig2Nacos(ConfigService configService)
throws NacosException {
configService.publishConfig("nacos-config-refresh.yml", "DEFAULT_GROUP",
"configdata:\n" +
" user:\n" +
" age: 21\n" +
" name: freeman\n" +
" map:\n" +
" hobbies:\n" +
" - art\n" +
" - programming\n" +
" intro: Hello, I'm freeman\n" +
" users:\n" +
" - name: dad\n" +
" age: 20\n" +
" - name: mom\n" +
" age: 18",
"yaml");
}
}
}

@ -0,0 +1,37 @@
services:
# zookeeper:
# image: zookeeper
# ports:
# - "2181:2181"
# restart: on-failure
nacos:
image: zhusaidong/nacos-server-m1:2.0.3
container_name: nacos-standalone
environment:
- PREFER_HOST_MODE=hostname
- MODE=standalone
ports:
- "8848:8848"
healthcheck:
test: "curl --fail http://127.0.0.1:8848/nacos/v1/console/health/liveness || exit 1"
interval: 5s
# etcd:
# image: "quay.io/coreos/etcd:latest"
# container_name: etcd
# environment:
# - ETCDCTL_API=3
# command: [
# "etcd",
# "--name=etcd0",
# "--advertise-client-urls=http://127.0.0.1:2379",
# "--listen-client-urls=http://0.0.0.0:2379",
# "--initial-advertise-peer-urls=http://127.0.0.1:2380",
# "--listen-peer-urls=http://0.0.0.0:2380",
# "--initial-cluster=etcd0=http://127.0.0.1:2380",
# ]
# ports:
# - "2379:2379"
# - "2380:2380"
# restart: always

@ -0,0 +1,16 @@
configdata:
user:
age: 22
name: freeman1123
map:
hobbies:
- art
- programming
- movie
intro: Hello, I'm freeman
extra: yo~
users:
- name: dad
age: 20
- name: mom
age: 18

@ -0,0 +1,37 @@
services:
# zookeeper:
# image: zookeeper
# ports:
# - "2181:2181"
# restart: on-failure
nacos:
image: nacos/nacos-server:2.0.1
container_name: nacos-standalone
environment:
- PREFER_HOST_MODE=hostname
- MODE=standalone
ports:
- "8848:8848"
healthcheck:
test: "curl --fail http://127.0.0.1:8848/nacos/v1/console/health/liveness || exit 1"
interval: 5s
# etcd:
# image: "quay.io/coreos/etcd:latest"
# container_name: etcd
# environment:
# - ETCDCTL_API=3
# command: [
# "etcd",
# "--name=etcd0",
# "--advertise-client-urls=http://127.0.0.1:2379",
# "--listen-client-urls=http://0.0.0.0:2379",
# "--initial-advertise-peer-urls=http://127.0.0.1:2380",
# "--listen-peer-urls=http://0.0.0.0:2380",
# "--initial-cluster=etcd0=http://127.0.0.1:2380",
# ]
# ports:
# - "2379:2379"
# - "2380:2380"
# restart: always

@ -0,0 +1,16 @@
configdata:
user:
age: 22
name: freeman1123
map:
hobbies:
- art
- programming
- movie
intro: Hello, I'm freeman
extra: yo~
users:
- name: dad
age: 20
- name: mom
age: 18

@ -17,4 +17,14 @@
<artifactId>nacos-tests</artifactId>
<name>Nacos Tests</name>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

@ -12,24 +12,136 @@
<artifactId>spring-cloud-alibaba-test-support</artifactId>
<name>Spring Cloud Alibaba Test Support</name>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.7.2</junit.version>
<selenium.version>3.141.59</selenium.version>
<lombok.version>1.18.20</lombok.version>
<assertj-core.version>3.20.2</assertj-core.version>
<awaitility.version>4.1.0</awaitility.version>
<kotlin.version>1.5.30</kotlin.version>
<slf4j-api.version>1.7.32</slf4j-api.version>
<log4j-slf4j-impl.version>2.14.1</log4j-slf4j-impl.version>
<guava.version>31.0.1-jre</guava.version>
<hamcrest.version>1.3</hamcrest.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j-slf4j-impl.version}</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>compile</scope>
<!-- Use the version of Spring Boot -->
<exclusions>
<exclusion>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.6.1</version>
</dependency>
<dependency>
<groupId>org.rnorth.visible-assertions</groupId>
<artifactId>visible-assertions</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>1.16.3</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,9 @@
package com.alibaba.cloud.testsupport;
public class Constant {
//超时默认设置为5s
public static final long TIME_OUT = 5000;
public static final String REFRESH_CONFIG = "nacos-config-refresh.yml";
}

@ -0,0 +1,39 @@
/*
* Licensed to Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Apache Software Foundation (ASF) licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.cloud.testsupport;
import java.lang.annotation.*;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testcontainers.junit.jupiter.Testcontainers;
@Inherited
@Testcontainers
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestMethodOrder(OrderAnnotation.class)
@ExtendWith(SpringCloudAlibabaExtension.class)
public @interface SpringCloudAlibaba {
String[] composeFiles();
String serviceName();
}

@ -0,0 +1,106 @@
/*
* Licensed to Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Apache Software Foundation (ASF) licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.cloud.testsupport;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.time.Duration;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.testcontainers.Testcontainers;
import org.testcontainers.containers.DockerComposeContainer;
import org.testcontainers.shaded.org.awaitility.Awaitility;
@Slf4j
final class SpringCloudAlibabaExtension
implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback {
private final boolean LOCAL_MODE = Objects.equals(System.getProperty("local"), "true");
private DockerComposeContainer<?> compose;
@Override
@SuppressWarnings("UnstableApiUsage")
public void beforeAll(ExtensionContext context) throws IOException {
Awaitility.setDefaultTimeout(Duration.ofSeconds(60));
Awaitility.setDefaultPollInterval(Duration.ofSeconds(10));
if (LOCAL_MODE) {
runInLocal();
} else {
runInDockerContainer(context);
}
//
// final Class<?> clazz = context.getRequiredTestClass();
// Stream.of(clazz.getDeclaredFields())
// .filter(it -> Modifier.isStatic(it.getModifiers()));
}
private void runInLocal() {
Testcontainers.exposeHostPorts(3000);
}
private void runInDockerContainer(ExtensionContext context) {
compose = createDockerCompose(context);
compose.start();
}
@Override
public void afterAll(ExtensionContext context) {
if (compose != null) {
compose.stop();
}
}
@Override
public void beforeEach(ExtensionContext context) {
final Object instance = context.getRequiredTestInstance();
Stream.of(instance.getClass().getDeclaredFields());
}
private DockerComposeContainer<?> createDockerCompose(ExtensionContext context) {
final Class<?> clazz = context.getRequiredTestClass();
final SpringCloudAlibaba annotation = clazz.getAnnotation(
SpringCloudAlibaba.class);
final List<File> files = Stream.of(annotation.composeFiles())
.map(it -> SpringCloudAlibaba.class.getClassLoader().getResource(it))
.filter(Objects::nonNull)
.map(URL::getPath)
.map(File::new)
.collect(Collectors.toList());
compose = new DockerComposeContainer<>(files)
.withPull(true)
.withTailChildContainers(true);
return compose;
}
}

@ -0,0 +1,16 @@
package com.alibaba.cloud.testsupport;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ExtendWith(TestTimeoutExtension.class)
public @interface TestExtend {
//设置超时时间
long time();
}

@ -0,0 +1,37 @@
package com.alibaba.cloud.testsupport;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TestTimeoutExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback {
@Override
public void afterAll(ExtensionContext context) throws Exception {
}
@Override
public void beforeAll(ExtensionContext context) throws Exception {
}
@Override
public void beforeEach(ExtensionContext context) throws Exception {
final Class<?> clazz = context.getRequiredTestClass();
final TestExtend annotation = clazz.getAnnotation(
TestExtend.class);
ScheduledExecutorService singlonThread = Executors.newSingleThreadScheduledExecutor();
while (!singlonThread.awaitTermination( annotation.time(), TimeUnit.MILLISECONDS)){
singlonThread.shutdown();
}
}
}
Loading…
Cancel
Save