Skip to content

Commit 90b327d

Browse files
committed
将测试文件改成使用Juint来写同时修改CI/CD流程
1 parent 4e44fd1 commit 90b327d

11 files changed

Lines changed: 705 additions & 124 deletions

File tree

.github/workflows/maven.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ jobs:
5050
- name: Build with Maven
5151
run: mvn clean install -DskipTests
5252

53+
- name: Run Unit Tests
54+
run: |
55+
echo "Running unit tests..."
56+
mvn test -pl rpc-core -am -Dtest="**/extension/*Test,**/serialization/*Test,**/loadbalancer/*Test,**/registry/*Test,**/config/*Test,**/protocol/*Test"
57+
5358
- name: Start RPC Provider (Java Server)
5459
run: |
5560
# Build classpath including project jars and dependencies

rpc-core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@
6666
<artifactId>gson</artifactId>
6767
<version>2.10.1</version>
6868
</dependency>
69+
<dependency>
70+
<groupId>org.junit.jupiter</groupId>
71+
<artifactId>junit-jupiter</artifactId>
72+
<scope>test</scope>
73+
</dependency>
6974
</dependencies>
7075

7176
</project>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package com.xiaoyu.rpc.core.config;
2+
3+
import org.junit.jupiter.api.AfterEach;
4+
import org.junit.jupiter.api.BeforeEach;
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.api.DisplayName;
7+
8+
import java.lang.reflect.Field;
9+
10+
import static org.junit.jupiter.api.Assertions.*;
11+
12+
/**
13+
* RPC 配置单元测试
14+
*/
15+
@DisplayName("RpcConfig 配置测试")
16+
public class RpcConfigTest {
17+
18+
@BeforeEach
19+
void setUp() throws Exception {
20+
// 重置单例以便每个测试独立
21+
resetSingleton();
22+
// 清理测试用的系统属性
23+
System.clearProperty("rpc.registry");
24+
System.clearProperty("rpc.serializer");
25+
System.clearProperty("rpc.server-port");
26+
}
27+
28+
@AfterEach
29+
void tearDown() throws Exception {
30+
// 清理系统属性
31+
System.clearProperty("rpc.registry");
32+
System.clearProperty("rpc.serializer");
33+
System.clearProperty("rpc.server-port");
34+
// 重置单例
35+
resetSingleton();
36+
}
37+
38+
private void resetSingleton() throws Exception {
39+
Field instanceField = RpcConfig.class.getDeclaredField("instance");
40+
instanceField.setAccessible(true);
41+
instanceField.set(null, null);
42+
}
43+
44+
@Test
45+
@DisplayName("测试单例模式")
46+
void testSingletonPattern() {
47+
RpcConfig config1 = RpcConfig.getInstance();
48+
RpcConfig config2 = RpcConfig.getInstance();
49+
50+
assertSame(config1, config2, "RpcConfig should be singleton");
51+
}
52+
53+
@Test
54+
@DisplayName("测试默认配置值")
55+
void testDefaultConfigValues() {
56+
RpcConfig config = RpcConfig.getInstance();
57+
58+
assertNotNull(config.getSerializerType(), "Serializer type should not be null");
59+
assertNotNull(config.getServerHost(), "Server host should not be null");
60+
assertNotNull(config.getServerPort(), "Server port should not be null");
61+
assertNotNull(config.getProtocol(), "Protocol should not be null");
62+
}
63+
64+
@Test
65+
@DisplayName("测试系统属性覆盖 - 注册中心类型")
66+
void testSystemPropertyOverrideRegistry() throws Exception {
67+
System.setProperty("rpc.registry", "local");
68+
resetSingleton();
69+
70+
RpcConfig config = RpcConfig.getInstance();
71+
assertEquals("local", config.getRegistryType(), "Registry type should be overridden by system property");
72+
}
73+
74+
@Test
75+
@DisplayName("测试系统属性覆盖 - 序列化器")
76+
void testSystemPropertyOverrideSerializer() throws Exception {
77+
System.setProperty("rpc.serializer", "kryo");
78+
resetSingleton();
79+
80+
RpcConfig config = RpcConfig.getInstance();
81+
assertEquals("kryo", config.getSerializerType(), "Serializer should be overridden by system property");
82+
}
83+
84+
@Test
85+
@DisplayName("测试系统属性覆盖 - 服务端口")
86+
void testSystemPropertyOverridePort() throws Exception {
87+
System.setProperty("rpc.server-port", "9999");
88+
resetSingleton();
89+
90+
RpcConfig config = RpcConfig.getInstance();
91+
assertEquals(9999, config.getServerPort(), "Server port should be overridden by system property");
92+
}
93+
94+
@Test
95+
@DisplayName("测试 getSerializerCode 方法")
96+
void testGetSerializerCode() {
97+
System.setProperty("rpc.serializer", "kryo");
98+
RpcConfig config = RpcConfig.getInstance();
99+
100+
byte code = config.getSerializerCode();
101+
assertTrue(code > 0, "Serializer code should be positive");
102+
}
103+
104+
@Test
105+
@DisplayName("测试 toString 方法")
106+
void testToString() {
107+
RpcConfig config = RpcConfig.getInstance();
108+
String str = config.toString();
109+
110+
assertNotNull(str, "toString should not return null");
111+
assertTrue(str.contains("RpcConfig"), "toString should contain class name");
112+
assertTrue(str.contains("serializerType"), "toString should contain serializerType");
113+
assertTrue(str.contains("serverPort"), "toString should contain serverPort");
114+
}
115+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package com.xiaoyu.rpc.core.extension;
2+
3+
import com.xiaoyu.rpc.common.extension.ExtensionLoader;
4+
import com.xiaoyu.rpc.common.serialization.Serializer;
5+
import com.xiaoyu.rpc.core.loadbalancer.LoadBalancer;
6+
import com.xiaoyu.rpc.core.client.ProxyFactory;
7+
import com.xiaoyu.rpc.core.protocol.Protocol;
8+
import com.xiaoyu.rpc.core.registry.ServiceRegistry;
9+
import com.xiaoyu.rpc.core.registry.ServiceDiscovery;
10+
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.DisplayName;
13+
14+
import static org.junit.jupiter.api.Assertions.*;
15+
16+
/**
17+
* ExtensionLoader SPI 机制单元测试
18+
*/
19+
@DisplayName("SPI ExtensionLoader 测试")
20+
public class ExtensionLoaderTest {
21+
22+
@Test
23+
@DisplayName("测试加载 Serializer 扩展")
24+
void testLoadSerializerExtensions() {
25+
ExtensionLoader<Serializer> loader = ExtensionLoader.getExtensionLoader(Serializer.class);
26+
27+
// 测试所有支持的序列化器
28+
assertNotNull(loader.getExtension("java"), "Java serializer should be loaded");
29+
assertNotNull(loader.getExtension("kryo"), "Kryo serializer should be loaded");
30+
assertNotNull(loader.getExtension("protobuf"), "Protobuf serializer should be loaded");
31+
assertNotNull(loader.getExtension("json"), "JSON serializer should be loaded");
32+
}
33+
34+
@Test
35+
@DisplayName("测试获取所有支持扩展名")
36+
void testGetSupportedExtensions() {
37+
ExtensionLoader<Serializer> loader = ExtensionLoader.getExtensionLoader(Serializer.class);
38+
39+
var extensions = loader.getSupportedExtensions();
40+
assertTrue(extensions.contains("java"), "Should contain 'java' extension");
41+
assertTrue(extensions.contains("kryo"), "Should contain 'kryo' extension");
42+
assertTrue(extensions.contains("protobuf"), "Should contain 'protobuf' extension");
43+
assertTrue(extensions.contains("json"), "Should contain 'json' extension");
44+
assertEquals(4, extensions.size(), "Should have exactly 4 serializer extensions");
45+
}
46+
47+
@Test
48+
@DisplayName("测试扩展单例缓存")
49+
void testExtensionCaching() {
50+
ExtensionLoader<Serializer> loader = ExtensionLoader.getExtensionLoader(Serializer.class);
51+
52+
Serializer first = loader.getExtension("kryo");
53+
Serializer second = loader.getExtension("kryo");
54+
55+
assertSame(first, second, "Same extension should return same instance (singleton)");
56+
}
57+
58+
@Test
59+
@DisplayName("测试加载不存在扩展时抛出异常")
60+
void testLoadNonExistentExtension() {
61+
ExtensionLoader<Serializer> loader = ExtensionLoader.getExtensionLoader(Serializer.class);
62+
63+
assertThrows(RuntimeException.class, () -> {
64+
loader.getExtension("non_existent");
65+
}, "Loading non-existent extension should throw exception");
66+
}
67+
68+
@Test
69+
@DisplayName("测试 LoadBalancer 扩展加载")
70+
void testLoadBalancerExtensions() {
71+
ExtensionLoader<LoadBalancer> loader = ExtensionLoader.getExtensionLoader(LoadBalancer.class);
72+
73+
assertNotNull(loader.getExtension("random"), "Random load balancer should be loaded");
74+
assertNotNull(loader.getExtension("roundrobin"), "RoundRobin load balancer should be loaded");
75+
76+
var extensions = loader.getSupportedExtensions();
77+
assertEquals(2, extensions.size(), "Should have exactly 2 load balancer extensions");
78+
}
79+
80+
@Test
81+
@DisplayName("测试 Protocol 扩展加载")
82+
void testProtocolExtensions() {
83+
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
84+
85+
assertNotNull(loader.getExtension("netty"), "Netty protocol should be loaded");
86+
assertNotNull(loader.getExtension("http"), "HTTP protocol should be loaded");
87+
assertNotNull(loader.getExtension("http2"), "HTTP2 protocol should be loaded");
88+
assertNotNull(loader.getExtension("grpc"), "gRPC protocol should be loaded");
89+
90+
var extensions = loader.getSupportedExtensions();
91+
assertEquals(4, extensions.size(), "Should have exactly 4 protocol extensions");
92+
}
93+
94+
@Test
95+
@DisplayName("测试 ProxyFactory 扩展加载")
96+
void testProxyFactoryExtensions() {
97+
ExtensionLoader<ProxyFactory> loader = ExtensionLoader.getExtensionLoader(ProxyFactory.class);
98+
99+
assertNotNull(loader.getExtension("jdk"), "JDK proxy factory should be loaded");
100+
assertNotNull(loader.getExtension("bytebuddy"), "ByteBuddy proxy factory should be loaded");
101+
102+
var extensions = loader.getSupportedExtensions();
103+
assertEquals(2, extensions.size(), "Should have exactly 2 proxy factory extensions");
104+
}
105+
106+
@Test
107+
@DisplayName("测试 ServiceRegistry 扩展加载")
108+
void testServiceRegistryExtensions() {
109+
ExtensionLoader<ServiceRegistry> loader = ExtensionLoader.getExtensionLoader(ServiceRegistry.class);
110+
111+
// local registry should be loadable without external dependencies
112+
assertNotNull(loader.getExtension("local"), "Local service registry should be loaded");
113+
114+
var extensions = loader.getSupportedExtensions();
115+
assertTrue(extensions.contains("local"), "Should contain 'local' extension");
116+
assertTrue(extensions.contains("nacos"), "Should contain 'nacos' extension");
117+
}
118+
119+
@Test
120+
@DisplayName("测试 ServiceDiscovery 扩展加载")
121+
void testServiceDiscoveryExtensions() {
122+
ExtensionLoader<ServiceDiscovery> loader = ExtensionLoader.getExtensionLoader(ServiceDiscovery.class);
123+
124+
// local registry should be loadable without external dependencies
125+
assertNotNull(loader.getExtension("local"), "Local service discovery should be loaded");
126+
127+
var extensions = loader.getSupportedExtensions();
128+
assertTrue(extensions.contains("local"), "Should contain 'local' extension");
129+
assertTrue(extensions.contains("nacos"), "Should contain 'nacos' extension");
130+
}
131+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.xiaoyu.rpc.core.loadbalancer;
2+
3+
import com.xiaoyu.rpc.common.extension.ExtensionLoader;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.api.DisplayName;
6+
import org.junit.jupiter.api.RepeatedTest;
7+
8+
import java.util.Arrays;
9+
import java.util.HashSet;
10+
import java.util.List;
11+
import java.util.Set;
12+
13+
import static org.junit.jupiter.api.Assertions.*;
14+
15+
/**
16+
* 负载均衡器单元测试
17+
*/
18+
@DisplayName("LoadBalancer 负载均衡器测试")
19+
public class LoadBalancerTest {
20+
21+
private final List<String> servers = Arrays.asList(
22+
"127.0.0.1:8080",
23+
"127.0.0.1:8081",
24+
"127.0.0.1:8082");
25+
26+
@Test
27+
@DisplayName("测试 Random 负载均衡器加载")
28+
void testRandomLoadBalancerLoading() {
29+
LoadBalancer lb = ExtensionLoader.getExtensionLoader(LoadBalancer.class).getExtension("random");
30+
assertNotNull(lb, "Random load balancer should be loaded");
31+
assertTrue(lb instanceof RandomLoadBalancer, "Should be instance of RandomLoadBalancer");
32+
}
33+
34+
@Test
35+
@DisplayName("测试 RoundRobin 负载均衡器加载")
36+
void testRoundRobinLoadBalancerLoading() {
37+
LoadBalancer lb = ExtensionLoader.getExtensionLoader(LoadBalancer.class).getExtension("roundrobin");
38+
assertNotNull(lb, "RoundRobin load balancer should be loaded");
39+
assertTrue(lb instanceof RoundRobinLoadBalancer, "Should be instance of RoundRobinLoadBalancer");
40+
}
41+
42+
@Test
43+
@DisplayName("测试 Random 负载均衡器选择服务器")
44+
void testRandomLoadBalancerSelect() {
45+
LoadBalancer lb = ExtensionLoader.getExtensionLoader(LoadBalancer.class).getExtension("random");
46+
47+
// 多次选择确保都在列表中
48+
for (int i = 0; i < 10; i++) {
49+
String selected = lb.select(servers);
50+
assertNotNull(selected, "Selected server should not be null");
51+
assertTrue(servers.contains(selected), "Selected server should be in the list");
52+
}
53+
}
54+
55+
@Test
56+
@DisplayName("测试 RoundRobin 负载均衡器轮询")
57+
void testRoundRobinLoadBalancerSelect() {
58+
// 创建新的 RoundRobin 实例来确保从头开始
59+
LoadBalancer lb = new RoundRobinLoadBalancer();
60+
61+
// 测试轮询模式
62+
String first = lb.select(servers);
63+
String second = lb.select(servers);
64+
String third = lb.select(servers);
65+
String fourth = lb.select(servers); // 应该回到第一个
66+
67+
assertNotNull(first, "First selection should not be null");
68+
assertNotNull(second, "Second selection should not be null");
69+
assertNotNull(third, "Third selection should not be null");
70+
assertNotNull(fourth, "Fourth selection should not be null");
71+
72+
// 确保四次选择覆盖了所有服务器
73+
Set<String> selected = new HashSet<>(Arrays.asList(first, second, third));
74+
assertEquals(3, selected.size(), "RoundRobin should cycle through all 3 servers");
75+
76+
// 第四次选择应该与前三次之一相同(循环)
77+
assertTrue(servers.contains(fourth), "Fourth selection should be in server list");
78+
}
79+
80+
@Test
81+
@DisplayName("测试负载均衡器处理单节点列表")
82+
void testLoadBalancerWithSingleServer() {
83+
LoadBalancer randomLb = ExtensionLoader.getExtensionLoader(LoadBalancer.class).getExtension("random");
84+
LoadBalancer rrLb = ExtensionLoader.getExtensionLoader(LoadBalancer.class).getExtension("roundrobin");
85+
86+
List<String> singleServer = Arrays.asList("127.0.0.1:9999");
87+
88+
assertEquals("127.0.0.1:9999", randomLb.select(singleServer), "Random should return the only server");
89+
assertEquals("127.0.0.1:9999", rrLb.select(singleServer), "RoundRobin should return the only server");
90+
}
91+
92+
@RepeatedTest(5)
93+
@DisplayName("测试 Random 负载均衡器随机性")
94+
void testRandomnessOfRandomLoadBalancer() {
95+
LoadBalancer lb = ExtensionLoader.getExtensionLoader(LoadBalancer.class).getExtension("random");
96+
97+
Set<String> selections = new HashSet<>();
98+
// 多次选择,应该最终选中所有服务器
99+
for (int i = 0; i < 100; i++) {
100+
selections.add(lb.select(servers));
101+
}
102+
103+
// 在100次随机选择后,应该覆盖所有3个服务器
104+
assertEquals(3, selections.size(), "Random load balancer should eventually select all servers");
105+
}
106+
}

0 commit comments

Comments
 (0)