226 lines
6.8 KiB
C++
226 lines
6.8 KiB
C++
|
|
#include <gtest/gtest.h>
|
|||
|
|
#include <gmock/gmock.h>
|
|||
|
|
#include "core/message_bus.hpp"
|
|||
|
|
|
|||
|
|
using namespace battlefield;
|
|||
|
|
|
|||
|
|
// ==================== Singleton ====================
|
|||
|
|
TEST(MessageBusTest, InstanceReturnsSame) {
|
|||
|
|
MessageBus& bus1 = MessageBus::Instance();
|
|||
|
|
MessageBus& bus2 = MessageBus::Instance();
|
|||
|
|
EXPECT_EQ(&bus1, &bus2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Subscribe / Publish ====================
|
|||
|
|
TEST(MessageBusTest, SubscribeAndPublish) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
bool wasCalled = false;
|
|||
|
|
int subId = bus.Subscribe("test.topic", [&wasCalled](const BusMessage& msg) {
|
|||
|
|
wasCalled = true;
|
|||
|
|
EXPECT_EQ(msg.topic, "test.topic");
|
|||
|
|
EXPECT_EQ(msg.sender, "sender1");
|
|||
|
|
EXPECT_EQ(msg.payload["key"], "value");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
bus.Publish("test.topic", "sender1", nlohmann::json::object({{"key", "value"}}));
|
|||
|
|
EXPECT_TRUE(wasCalled);
|
|||
|
|
bus.Unsubscribe(subId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Unsubscribe ====================
|
|||
|
|
TEST(MessageBusTest, UnsubscribeStopsDelivery) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
int callCount = 0;
|
|||
|
|
int subId = bus.Subscribe("topic.unsub", [&callCount](const BusMessage&) {
|
|||
|
|
++callCount;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
bus.Publish("topic.unsub", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(callCount, 1);
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(subId);
|
|||
|
|
|
|||
|
|
bus.Publish("topic.unsub", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(callCount, 1); // 不再增长
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Multiple Subscribers ====================
|
|||
|
|
TEST(MessageBusTest, MultipleSubscribers) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
int count = 0;
|
|||
|
|
int s1 = bus.Subscribe("multi", [&count](const BusMessage&) { ++count; });
|
|||
|
|
int s2 = bus.Subscribe("multi", [&count](const BusMessage&) { ++count; });
|
|||
|
|
int s3 = bus.Subscribe("multi", [&count](const BusMessage&) { ++count; });
|
|||
|
|
|
|||
|
|
bus.Publish("multi", "sender", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(count, 3);
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(s1);
|
|||
|
|
bus.Unsubscribe(s2);
|
|||
|
|
bus.Unsubscribe(s3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Wildcard Subscriber ====================
|
|||
|
|
TEST(MessageBusTest, WildcardSubscription) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
int wildcardCount = 0;
|
|||
|
|
int specificCount = 0;
|
|||
|
|
|
|||
|
|
int wildcard = bus.Subscribe("*", [&wildcardCount](const BusMessage&) {
|
|||
|
|
++wildcardCount;
|
|||
|
|
});
|
|||
|
|
int specific = bus.Subscribe("specific", [&specificCount](const BusMessage&) {
|
|||
|
|
++specificCount;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
bus.Publish("specific", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(wildcardCount, 1);
|
|||
|
|
EXPECT_EQ(specificCount, 1);
|
|||
|
|
|
|||
|
|
bus.Publish("other", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(wildcardCount, 2);
|
|||
|
|
EXPECT_EQ(specificCount, 1); // 不变
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(wildcard);
|
|||
|
|
bus.Unsubscribe(specific);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== PublishString ====================
|
|||
|
|
TEST(MessageBusTest, PublishString) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
std::string receivedMessage;
|
|||
|
|
int sub = bus.Subscribe("string.topic", [&receivedMessage](const BusMessage& msg) {
|
|||
|
|
receivedMessage = msg.payload["message"];
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
bus.PublishString("string.topic", "string_sender", "Hello World!");
|
|||
|
|
EXPECT_EQ(receivedMessage, "Hello World!");
|
|||
|
|
bus.Unsubscribe(sub);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== SubscriberCount ====================
|
|||
|
|
TEST(MessageBusTest, SubscriberCount) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
EXPECT_EQ(bus.SubscriberCount("count.topic"), 0u);
|
|||
|
|
|
|||
|
|
int s1 = bus.Subscribe("count.topic", [](const BusMessage&) {});
|
|||
|
|
EXPECT_EQ(bus.SubscriberCount("count.topic"), 1u);
|
|||
|
|
|
|||
|
|
int s2 = bus.Subscribe("count.topic", [](const BusMessage&) {});
|
|||
|
|
EXPECT_EQ(bus.SubscriberCount("count.topic"), 2u);
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(s1);
|
|||
|
|
EXPECT_EQ(bus.SubscriberCount("count.topic"), 1u);
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(s2);
|
|||
|
|
EXPECT_EQ(bus.SubscriberCount("count.topic"), 0u);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== History ====================
|
|||
|
|
TEST(MessageBusTest, HistoryCount) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
size_t before = bus.HistoryCount();
|
|||
|
|
|
|||
|
|
bus.Publish("history.topic", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_GT(bus.HistoryCount(), before);
|
|||
|
|
|
|||
|
|
bus.PublishString("history.topic2", "test", "msg");
|
|||
|
|
EXPECT_GT(bus.HistoryCount(), before + 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Exception Safety ====================
|
|||
|
|
TEST(MessageBusTest, ExceptionInHandlerDoesNotCrash) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
int normalCount = 0;
|
|||
|
|
int badSub = bus.Subscribe("error.topic", [](const BusMessage&) {
|
|||
|
|
throw std::runtime_error("handler error");
|
|||
|
|
});
|
|||
|
|
int goodSub = bus.Subscribe("error.topic", [&normalCount](const BusMessage&) {
|
|||
|
|
++normalCount;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 不应崩溃
|
|||
|
|
bus.Publish("error.topic", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(normalCount, 1);
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(badSub);
|
|||
|
|
bus.Unsubscribe(goodSub);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Multiple Topics ====================
|
|||
|
|
TEST(MessageBusTest, DifferentTopicsIndependent) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
int topicACount = 0;
|
|||
|
|
int topicBCount = 0;
|
|||
|
|
|
|||
|
|
int sa = bus.Subscribe("topicA", [&topicACount](const BusMessage&) { ++topicACount; });
|
|||
|
|
int sb = bus.Subscribe("topicB", [&topicBCount](const BusMessage&) { ++topicBCount; });
|
|||
|
|
|
|||
|
|
bus.Publish("topicA", "", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(topicACount, 1);
|
|||
|
|
EXPECT_EQ(topicBCount, 0);
|
|||
|
|
|
|||
|
|
bus.Publish("topicB", "", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(topicACount, 1);
|
|||
|
|
EXPECT_EQ(topicBCount, 1);
|
|||
|
|
|
|||
|
|
bus.Publish("topicC", "", nlohmann::json::object());
|
|||
|
|
EXPECT_EQ(topicACount, 1);
|
|||
|
|
EXPECT_EQ(topicBCount, 1);
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(sa);
|
|||
|
|
bus.Unsubscribe(sb);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== Timestamp ====================
|
|||
|
|
TEST(MessageBusTest, MessageHasTimestamp) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
std::string ts;
|
|||
|
|
int sub = bus.Subscribe("ts.topic", [&ts](const BusMessage& msg) {
|
|||
|
|
ts = msg.timestamp;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
bus.Publish("ts.topic", "test", nlohmann::json::object());
|
|||
|
|
EXPECT_FALSE(ts.empty());
|
|||
|
|
// 验证时间戳格式:YYYY-MM-DDTHH:MM:SS.mmmZ
|
|||
|
|
EXPECT_GE(ts.length(), 20u);
|
|||
|
|
EXPECT_THAT(ts, testing::HasSubstr("T"));
|
|||
|
|
EXPECT_THAT(ts, testing::HasSubstr("Z"));
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(sub);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== BusMessage Fields ====================
|
|||
|
|
TEST(MessageBusTest, BusMessageAllFields) {
|
|||
|
|
auto& bus = MessageBus::Instance();
|
|||
|
|
|
|||
|
|
std::string rcvTopic, rcvSender, rcvTs;
|
|||
|
|
nlohmann::json rcvPayload;
|
|||
|
|
int sub = bus.Subscribe("full.topic", [&](const BusMessage& msg) {
|
|||
|
|
rcvTopic = msg.topic;
|
|||
|
|
rcvSender = msg.sender;
|
|||
|
|
rcvPayload = msg.payload;
|
|||
|
|
rcvTs = msg.timestamp;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
nlohmann::json payload = {{"a", 1}, {"b", "text"}, {"c", nlohmann::json::array({1,2,3})}};
|
|||
|
|
bus.Publish("full.topic", "module_x", payload);
|
|||
|
|
|
|||
|
|
EXPECT_EQ(rcvTopic, "full.topic");
|
|||
|
|
EXPECT_EQ(rcvSender, "module_x");
|
|||
|
|
EXPECT_EQ(rcvPayload["a"], 1);
|
|||
|
|
EXPECT_EQ(rcvPayload["b"], "text");
|
|||
|
|
EXPECT_FALSE(rcvTs.empty());
|
|||
|
|
|
|||
|
|
bus.Unsubscribe(sub);
|
|||
|
|
}
|