Skip to content

Commit fa9d4e1

Browse files
committed
集成测试支持自动启动本地 RocketMQ 并硬失败
新增 RocketMQ 下载/启动/关闭流程,测试环境自包含。所有依赖 RocketMQ 的测试统一硬失败处理,提升问题发现及时性。Producer/Consumer 测试断言增强,校验消息状态与路由信息。优化 RocketMQ 配置,允许磁盘 100% 使用率,提升稳定性。测试类结构调整,便于维护。
1 parent 4800b86 commit fa9d4e1

9 files changed

Lines changed: 106 additions & 22 deletions

File tree

.github/workflows/test.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ jobs:
1313

1414
steps:
1515
- uses: actions/checkout@v4
16+
17+
- name: Setup Java
18+
uses: actions/setup-java@v4
19+
with:
20+
distribution: 'temurin'
21+
java-version: '17'
22+
1623
- name: Setup dotNET
1724
uses: actions/setup-dotnet@v4
1825
with:
@@ -22,6 +29,56 @@ jobs:
2229
8.x
2330
9.x
2431
10.x
32+
33+
- name: Download & Start RocketMQ
34+
run: |
35+
RMQ_VERSION="5.3.1"
36+
wget -q "https://mirrors.tuna.tsinghua.edu.cn/apache/rocketmq/${RMQ_VERSION}/rocketmq-all-${RMQ_VERSION}-bin-release.zip" -O /tmp/rocketmq.zip
37+
unzip -q /tmp/rocketmq.zip -d /tmp/
38+
mv /tmp/rocketmq-all-${RMQ_VERSION}-bin-release /tmp/rocketmq
39+
40+
# 创建 broker.conf
41+
cat > /tmp/rocketmq/conf/broker_test.conf << 'CONF'
42+
brokerClusterName=DefaultCluster
43+
brokerName=broker-a
44+
brokerId=0
45+
deleteWhen=04
46+
fileReservedTime=48
47+
brokerRole=ASYNC_MASTER
48+
flushDiskType=ASYNC_FLUSH
49+
autoCreateTopicEnable=true
50+
listenPort=10911
51+
storePathRootDir=/tmp/rocketmq/store
52+
brokerIP1=127.0.0.1
53+
diskMaxUsedSpaceRatio=100
54+
diskSpaceWarningLevelRatio=100
55+
CONF
56+
57+
# 启动 NameServer
58+
nohup /tmp/rocketmq/bin/mqnamesrv > /tmp/namesrv.log 2>&1 &
59+
echo "等待 NameServer 启动..."
60+
timeout 30 sh -c 'while ! grep -q "boot success" /tmp/namesrv.log 2>/dev/null; do sleep 1; done'
61+
echo "NameServer 已启动"
62+
63+
# 启动 Broker
64+
nohup /tmp/rocketmq/bin/mqbroker -c /tmp/rocketmq/conf/broker_test.conf -n 127.0.0.1:9876 > /tmp/broker.log 2>&1 &
65+
echo "等待 Broker 启动..."
66+
timeout 40 sh -c 'while ! grep -q "boot success" /tmp/broker.log 2>/dev/null; do sleep 1; done'
67+
echo "Broker 已启动"
68+
2569
- name: Build
2670
run: |
2771
dotnet build -c Release
72+
73+
- name: Test
74+
env:
75+
ROCKETMQ_NAMESERVER: "127.0.0.1:9876"
76+
run: |
77+
dotnet test XUnitTestRocketMQ/XUnitTest.csproj -c Release --no-build -v n
78+
79+
- name: Stop RocketMQ
80+
if: always()
81+
run: |
82+
# 清理 RocketMQ 进程
83+
pkill -f mqbroker 2>/dev/null || true
84+
pkill -f mqnamesrv 2>/dev/null || true

XUnitTestRocketMQ/Cloud/SupportApacheAclTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using NewLife.RocketMQ;
77
using NewLife.RocketMQ.Protocol;
88
using Xunit;
9+
using XUnitTest.Integration;
910

1011
namespace XUnitTest.Cloud;
1112

@@ -24,6 +25,7 @@ public class SupportApacheAclTest
2425
[Fact]
2526
public void CreateTopicTest()
2627
{
28+
BasicTest.EnsureAvailable();
2729
using var producer = CreateProducerInstance(DefaultSysTopic);
2830
producer.Start();
2931
producer.CreateTopic(TestTopic, 2);
@@ -33,6 +35,7 @@ public void CreateTopicTest()
3335
[Fact]
3436
public void PublishMessageTest()
3537
{
38+
BasicTest.EnsureAvailable();
3639
using var producer = CreateProducerInstance(TestTopic);
3740
producer.Start();
3841

XUnitTestRocketMQ/Consumers/ConsumerTests.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ namespace XUnitTest.Consumers;
1212

1313
public class ConsumerTests
1414
{
15-
private static Consumer _consumer;
15+
private Consumer _consumer;
1616

1717
[Fact]
18-
[System.ComponentModel.DisplayName("Consumer集成测试_拉取消息不抛异常")]
19-
public static void ConsumeTest()
18+
[System.ComponentModel.DisplayName("Consumer集成测试_启动消费不抛异常_并获取路由信息")]
19+
public void ConsumeTest()
2020
{
21+
BasicTest.EnsureAvailable();
22+
2123
var set = BasicTest.GetConfig();
2224
var consumer = new Consumer
2325
{
@@ -36,15 +38,21 @@ public static void ConsumeTest()
3638

3739
_consumer = consumer;
3840

41+
// 等待 Rebalance 后验证路由信息
3942
Thread.Sleep(3000);
43+
44+
// 验证消费者已获取到 Broker 路由信息
45+
Assert.NotNull(consumer.Brokers);
46+
Assert.NotEmpty(consumer.Brokers);
47+
XTrace.WriteLine("Consumer 获取到 {0} 个 Broker", consumer.Brokers.Count);
4048
//foreach (var item in consumer.Clients)
4149
//{
4250
// var rs = item.GetRuntimeInfo();
4351
// Console.WriteLine("{0}\t{1}", item.Name, rs["brokerVersionDesc"]);
4452
//}
4553
}
4654

47-
private static Boolean OnConsume(MessageQueue q, MessageExt[] ms)
55+
private Boolean OnConsume(MessageQueue q, MessageExt[] ms)
4856
{
4957
Console.WriteLine("[{0}@{1}]收到消息[{2}]", q.BrokerName, q.QueueId, ms.Length);
5058

XUnitTestRocketMQ/Integration/BasicTest.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class BasicTest
1414
{
1515
private static MqSetting _config;
1616

17-
/// <summary>获取 RocketMQ 配置</summary>
17+
/// <summary>获取 RocketMQ 配置并验证 NameServer 可达。不可达时硬失败。</summary>
1818
public static MqSetting GetConfig()
1919
{
2020
if (_config != null) return _config;
@@ -32,20 +32,26 @@ public static MqSetting GetConfig()
3232

3333
XTrace.WriteLine("RocketMQ配置:{0}", set.NameServer);
3434

35-
return _config = set;
35+
_config = set;
3636
}
37+
38+
// 首次获取配置时检查连通性,不可达直接硬失败
39+
EnsureAvailable();
40+
41+
return _config;
3742
}
3843

39-
/// <summary> NameServer 不可达则跳过当前测试。适合不使用 RocketMqFixture 的集成测试方法。</summary>
40-
public static void SkipIfUnavailable()
44+
/// <summary>确保 NameServer 可达,不可达时抛出异常(硬失败)。</summary>
45+
public static void EnsureAvailable()
4146
{
4247
var addr = Environment.GetEnvironmentVariable("ROCKETMQ_NAMESERVER");
4348
if (String.IsNullOrEmpty(addr)) addr = GetConfig().NameServer;
4449

45-
Skip.If(!IsReachable(addr),
46-
$"无法连接 RocketMQ NameServer [{addr}],跳过集成测试。\n" +
47-
"请检查 Config/RocketMQ.xml 配置或通过 ROCKETMQ_NAMESERVER 环境变量指定地址。\n" +
48-
"启动本机 RocketMQ:dotnet run --file scripts/RocketMqSetup.cs");
50+
if (!IsReachable(addr))
51+
throw new InvalidOperationException(
52+
$"无法连接 RocketMQ NameServer [{addr}]。\n" +
53+
"请确认 RocketMQ 服务已启动,或通过 ROCKETMQ_NAMESERVER 环境变量指定地址。\n" +
54+
"启动本机 RocketMQ:dotnet run --file scripts/RocketMqSetup.cs");
4955
}
5056

5157
/// <summary>TCP 连通性检测</summary>

XUnitTestRocketMQ/Integration/RocketMqFixture.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,11 @@ public sealed class RocketMqFixture : IAsyncLifetime
2626

2727
private Exception? _initException;
2828

29-
/// <summary> NameServer 不可达则跳过当前测试</summary>
30-
public void SkipIfUnavailable()
29+
/// <summary>确保 NameServer 可达,不可达时抛出异常(硬失败)</summary>
30+
public void EnsureAvailable()
3131
{
3232
if (_initException != null)
33-
Skip.If(true,
34-
$"无法连接 RocketMQ:{_initException.Message}\n" +
35-
"请检查 Config/RocketMQ.xml 中的 NameServer 配置,并确认 RocketMQ 服务已启动。\n" +
36-
"启动本机 RocketMQ:dotnet run --file scripts/RocketMqSetup.cs");
33+
throw _initException;
3734
}
3835

3936
/// <inheritdoc/>
@@ -45,6 +42,8 @@ public Task InitializeAsync()
4542

4643
NameServerAddress = addr ?? String.Empty;
4744
_initException = VerifyConnection(NameServerAddress);
45+
// 不可达直接硬失败,不做静默跳过
46+
if (_initException != null) throw _initException;
4847
return Task.CompletedTask;
4948
}
5049

XUnitTestRocketMQ/Integration/RocketMqIntegrationTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace XUnitTest.Integration;
1717
/// <remarks>初始化</remarks>
1818
/// <param name="fixture">RocketMQ Fixture</param>
1919
[Collection("RocketMQ")]
20-
public class ProducerIntegrationTests(RocketMqFixture fixture) : IClassFixture<RocketMqFixture>
20+
public class ProducerIntegrationTests(RocketMqFixture fixture)
2121
{
2222
[Fact]
2323
[DisplayName("发送普通消息_返回SendOK")]
@@ -87,7 +87,7 @@ public async Task PublishMessagesParallel_AllSucceed()
8787
/// <remarks>初始化</remarks>
8888
/// <param name="fixture">RocketMQ Fixture</param>
8989
[Collection("RocketMQ")]
90-
public class ConsumerIntegrationTests(RocketMqFixture fixture) : IClassFixture<RocketMqFixture>
90+
public class ConsumerIntegrationTests(RocketMqFixture fixture)
9191
{
9292
[Fact]
9393
[DisplayName("先发再消费_能收到消息")]

XUnitTestRocketMQ/Producers/ProducerTests.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using NewLife.Log;
22
using NewLife.RocketMQ;
3+
using NewLife.RocketMQ.Protocol;
34
using Xunit;
45
using XUnitTest.Integration;
56

@@ -11,6 +12,7 @@ public class ProducerTests
1112
[System.ComponentModel.DisplayName("Producer_创建主题_返回队列数")]
1213
public void CreateTopic()
1314
{
15+
BasicTest.EnsureAvailable();
1416
var set = BasicTest.GetConfig();
1517
var mq = new Producer
1618
{
@@ -30,9 +32,11 @@ public void CreateTopic()
3032
}
3133

3234
[Fact]
33-
[System.ComponentModel.DisplayName("Producer_发送消息_不抛异常")]
34-
public static void ProduceTest()
35+
[System.ComponentModel.DisplayName("Producer_发送消息_全部返回SendOK")]
36+
public void ProduceTest()
3537
{
38+
BasicTest.EnsureAvailable();
39+
3640
var set = BasicTest.GetConfig();
3741
using var mq = new Producer
3842
{
@@ -50,6 +54,7 @@ public static void ProduceTest()
5054
//var str = Rand.NextString(1337);
5155

5256
var sr = mq.Publish(str, "TagA", null);
57+
Assert.Equal(SendStatus.SendOK, sr.Status);
5358
}
5459
}
5560
}

XUnitTestRocketMQ/Trace/MessageTraceTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using NewLife.RocketMQ;
66
using NewLife.RocketMQ.Protocol;
77
using Xunit;
8+
using XUnitTest.Integration;
89

910
namespace XUnitTest.Trace;
1011

@@ -17,6 +18,7 @@ public class MessageTraceTests
1718
[Fact]
1819
public void Producer_And_Consumer_With_Trace_Enabled_Should_Work()
1920
{
21+
BasicTest.EnsureAvailable();
2022
// 使用 ManualResetEvent 来同步测试的完成
2123
var mre = new ManualResetEvent(false);
2224

scripts/RocketMqSetup.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ static void WriteBrokerConf()
221221
listenPort=10911
222222
storePathRootDir={StoreDir.Replace('\\', '/')}
223223
brokerIP1=127.0.0.1
224+
# 允许磁盘使用率到 100%,避免因磁盘满拒绝写入(测试环境)
225+
diskMaxUsedSpaceRatio=100
226+
diskSpaceWarningLevelRatio=100
227+
logicalDiskSpaceCleanForciblyThreshold=1.0
224228
""";
225229

226230
File.WriteAllText(BrokerConf, conf, new UTF8Encoding(false));

0 commit comments

Comments
 (0)