499 lines
16 KiB
C++
499 lines
16 KiB
C++
#include <gtest/gtest.h>
|
||
#include <gmock/gmock.h>
|
||
#include "collector/DataCollector.h"
|
||
#include "utils/Logger.h"
|
||
#include "network/MessageTypes.h"
|
||
#include "core/System.h"
|
||
|
||
// 创建一个 Mock DataSource 类
|
||
class MockDataSource : public DataSource {
|
||
public:
|
||
MOCK_METHOD(bool, connect, (), (override));
|
||
MOCK_METHOD(void, disconnect, (), (override));
|
||
MOCK_METHOD(bool, isAvailable, (), (const, override));
|
||
MOCK_METHOD(bool, fetchAircraftData, (std::vector<Aircraft>&), (override));
|
||
MOCK_METHOD(bool, fetchVehicleData, (std::vector<Vehicle>&), (override));
|
||
MOCK_METHOD(bool, fetchTrafficLightSignals, (std::vector<TrafficLightSignal>&), (override));
|
||
};
|
||
|
||
class DataCollectorTest : public ::testing::Test {
|
||
protected:
|
||
void SetUp() override {
|
||
collector = std::make_unique<DataCollector>();
|
||
mockSource = std::make_shared<::testing::NiceMock<MockDataSource>>();
|
||
collector->setDataSource(mockSource);
|
||
}
|
||
|
||
void TearDown() override {
|
||
collector.reset();
|
||
}
|
||
|
||
// 创建测试数据
|
||
Aircraft createTestAircraft(const std::string& id, double lat, double lon) {
|
||
Aircraft a;
|
||
a.id = id;
|
||
a.flightNo = id;
|
||
a.trackNumber = "TN" + id;
|
||
a.geo.latitude = lat;
|
||
a.geo.longitude = lon;
|
||
a.altitude = 5.0;
|
||
a.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
|
||
return a;
|
||
}
|
||
|
||
Vehicle createTestVehicle(const std::string& id, double lat, double lon) {
|
||
Vehicle v;
|
||
v.id = id;
|
||
v.vehicleNo = id;
|
||
v.geo.latitude = lat;
|
||
v.geo.longitude = lon;
|
||
v.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
|
||
return v;
|
||
}
|
||
|
||
// 创建测试用的红绿灯信号
|
||
TrafficLightSignal createTestTrafficLight(const std::string& id, int state) {
|
||
TrafficLightSignal signal;
|
||
signal.trafficLightId = id;
|
||
signal.status = static_cast<SignalStatus>(state);
|
||
signal.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
|
||
return signal;
|
||
}
|
||
|
||
std::unique_ptr<DataCollector> collector;
|
||
std::shared_ptr<MockDataSource> mockSource;
|
||
};
|
||
|
||
// 测试初始化
|
||
TEST_F(DataCollectorTest, Initialization) {
|
||
DataSourceConfig dataSourceConfig;
|
||
dataSourceConfig.host = "localhost";
|
||
dataSourceConfig.port = 8080;
|
||
dataSourceConfig.aircraft_path = "/api/getCurrentFlightPositions";
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 1000;
|
||
warnConfig.log_interval_ms = 2000;
|
||
|
||
EXPECT_TRUE(collector->initialize(dataSourceConfig, warnConfig));
|
||
}
|
||
|
||
// 测试刷新方法
|
||
TEST_F(DataCollectorTest, RefreshTest) {
|
||
std::vector<Aircraft> testAircraft = {
|
||
createTestAircraft("TEST1", 36.36, 120.08),
|
||
createTestAircraft("TEST2", 36.37, 120.09)
|
||
};
|
||
|
||
std::vector<Vehicle> testVehicles = {
|
||
createTestVehicle("VEH1", 36.36, 120.08),
|
||
createTestVehicle("VEH2", 36.37, 120.09)
|
||
};
|
||
|
||
// 设置 Mock 数据返回
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillOnce(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testAircraft),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
EXPECT_CALL(*mockSource, fetchVehicleData)
|
||
.WillOnce(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testVehicles),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
// 执行刷新
|
||
collector->refresh();
|
||
|
||
// 验证数据
|
||
auto aircraft = collector->getAircraftData();
|
||
EXPECT_EQ(aircraft.size(), 2);
|
||
if (!aircraft.empty()) {
|
||
EXPECT_EQ(aircraft[0].flightNo, "TEST1");
|
||
EXPECT_EQ(aircraft[1].flightNo, "TEST2");
|
||
}
|
||
|
||
auto vehicles = collector->getVehicleData();
|
||
EXPECT_EQ(vehicles.size(), 2);
|
||
if (!vehicles.empty()) {
|
||
EXPECT_EQ(vehicles[0].vehicleNo, "VEH1");
|
||
EXPECT_EQ(vehicles[1].vehicleNo, "VEH2");
|
||
}
|
||
}
|
||
|
||
// 测试数据采集循环
|
||
TEST_F(DataCollectorTest, DataCollectionLoop) {
|
||
std::vector<Aircraft> testAircraft = {
|
||
createTestAircraft("TEST1", 36.36, 120.08)
|
||
};
|
||
|
||
std::vector<Vehicle> testVehicles = {
|
||
createTestVehicle("VEH1", 36.36, 120.08)
|
||
};
|
||
|
||
// 设置 Mock 数据返回
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillRepeatedly(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testAircraft),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
EXPECT_CALL(*mockSource, fetchVehicleData)
|
||
.WillRepeatedly(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testVehicles),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
// 启动采集
|
||
collector->start();
|
||
|
||
// 等待数据采集
|
||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||
|
||
// 停止采集
|
||
collector->stop();
|
||
|
||
// 验证数据
|
||
auto aircraft = collector->getAircraftData();
|
||
EXPECT_EQ(aircraft.size(), 1);
|
||
|
||
auto vehicles = collector->getVehicleData();
|
||
EXPECT_EQ(vehicles.size(), 1);
|
||
}
|
||
|
||
// 测试错误处理
|
||
TEST_F(DataCollectorTest, ErrorHandling) {
|
||
// 设置 Mock 返回错误
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillOnce(::testing::Return(false));
|
||
EXPECT_CALL(*mockSource, fetchVehicleData)
|
||
.WillOnce(::testing::Return(false));
|
||
|
||
// 执行刷新
|
||
collector->refresh();
|
||
|
||
// 验证数据为空
|
||
auto aircraft = collector->getAircraftData();
|
||
EXPECT_TRUE(aircraft.empty());
|
||
|
||
auto vehicles = collector->getVehicleData();
|
||
EXPECT_TRUE(vehicles.empty());
|
||
}
|
||
|
||
// 测试红绿灯信号获取
|
||
TEST_F(DataCollectorTest, TrafficLightSignalsTest) {
|
||
std::vector<TrafficLightSignal> testSignals = {
|
||
createTestTrafficLight("TL001", 0), // RED = 0
|
||
createTestTrafficLight("TL002", 1), // GREEN = 1
|
||
createTestTrafficLight("TL003", 2) // YELLOW = 2
|
||
};
|
||
|
||
// 设置 Mock 数据返回
|
||
EXPECT_CALL(*mockSource, fetchTrafficLightSignals)
|
||
.WillOnce(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testSignals),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
// 执行刷新
|
||
collector->refresh();
|
||
|
||
// 验证数据
|
||
auto signals = collector->getTrafficLightSignals();
|
||
EXPECT_EQ(signals.size(), 3);
|
||
if (signals.size() >= 3) {
|
||
EXPECT_EQ(signals[0].trafficLightId, "TL001");
|
||
EXPECT_EQ(signals[0].status, SignalStatus::RED); // RED = 0
|
||
EXPECT_EQ(signals[1].trafficLightId, "TL002");
|
||
EXPECT_EQ(signals[1].status, SignalStatus::GREEN); // GREEN = 1
|
||
}
|
||
}
|
||
|
||
// 测试红绿灯信号错误处理
|
||
TEST_F(DataCollectorTest, TrafficLightSignalsErrorTest) {
|
||
// 设置 Mock 返回错误
|
||
EXPECT_CALL(*mockSource, fetchTrafficLightSignals)
|
||
.WillOnce(::testing::Return(false));
|
||
|
||
// 执行刷新
|
||
collector->refresh();
|
||
|
||
// 验证数据为空
|
||
auto signals = collector->getTrafficLightSignals();
|
||
EXPECT_TRUE(signals.empty());
|
||
}
|
||
|
||
// 测试连接健康检查和超时告警
|
||
TEST_F(DataCollectorTest, ConnectionHealthAndTimeout) {
|
||
DataSourceConfig dataSourceConfig;
|
||
dataSourceConfig.host = "localhost";
|
||
dataSourceConfig.port = 8080;
|
||
dataSourceConfig.timeout_ms = 1000; // 1秒超时
|
||
dataSourceConfig.refresh_interval_ms = 100; // 100ms刷新间隔
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 500; // 500ms告警间隔
|
||
|
||
collector->initialize(dataSourceConfig, warnConfig);
|
||
|
||
// 模拟连接健康检查失败
|
||
EXPECT_CALL(*mockSource, isAvailable())
|
||
.WillRepeatedly(::testing::Return(false));
|
||
|
||
// 模据<E6A8A1><E68DAE>取失败
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillRepeatedly(::testing::Return(false));
|
||
EXPECT_CALL(*mockSource, fetchVehicleData)
|
||
.WillRepeatedly(::testing::Return(false));
|
||
|
||
// 启动采集
|
||
collector->start();
|
||
|
||
// 等待超过超时时间
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
|
||
|
||
// 停止采集
|
||
collector->stop();
|
||
|
||
// 验证数据为空
|
||
auto aircraft = collector->getAircraftData();
|
||
EXPECT_TRUE(aircraft.empty());
|
||
auto vehicles = collector->getVehicleData();
|
||
EXPECT_TRUE(vehicles.empty());
|
||
}
|
||
|
||
// 测试连接恢复
|
||
TEST_F(DataCollectorTest, ConnectionRecovery) {
|
||
DataSourceConfig config;
|
||
config.host = "localhost";
|
||
config.port = 8080;
|
||
config.refresh_interval_ms = 10;
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 20;
|
||
|
||
collector->initialize(config, warnConfig);
|
||
|
||
std::vector<Aircraft> testAircraft = {
|
||
createTestAircraft("TEST1", 36.36, 120.08)
|
||
};
|
||
|
||
// 移除 InSequence,直接设置期望
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillOnce(::testing::Return(false))
|
||
.WillOnce(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testAircraft),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
// <20><><EFBFBD>行两次刷新
|
||
collector->refresh(); // 第一次失败
|
||
collector->refresh(); // 第二次成功
|
||
|
||
// 验证数据
|
||
auto aircraft = collector->getAircraftData();
|
||
EXPECT_EQ(aircraft.size(), 1);
|
||
if (!aircraft.empty()) {
|
||
EXPECT_EQ(aircraft[0].flightNo, "TEST1");
|
||
}
|
||
}
|
||
|
||
// 测试长连接下的数据获取
|
||
TEST_F(DataCollectorTest, LongConnectionDataFetch) {
|
||
DataSourceConfig dataSourceConfig;
|
||
dataSourceConfig.host = "localhost";
|
||
dataSourceConfig.port = 8080;
|
||
dataSourceConfig.refresh_interval_ms = 100;
|
||
|
||
collector->initialize(dataSourceConfig, WarnConfig{});
|
||
|
||
std::vector<Aircraft> testAircraft = {
|
||
createTestAircraft("TEST1", 36.36, 120.08)
|
||
};
|
||
|
||
// 模拟连接保持可用
|
||
EXPECT_CALL(*mockSource, isAvailable())
|
||
.WillRepeatedly(::testing::Return(true));
|
||
|
||
// 模拟多次成功获取数据
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.Times(::testing::AtLeast(3))
|
||
.WillRepeatedly(::testing::DoAll(
|
||
::testing::SetArgReferee<0>(testAircraft),
|
||
::testing::Return(true)
|
||
));
|
||
|
||
// 启动采集
|
||
collector->start();
|
||
|
||
// 等待多个刷新周期
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(350)); // 应该执行至少3次获取
|
||
|
||
// 验证数据
|
||
auto aircraft = collector->getAircraftData();
|
||
EXPECT_FALSE(aircraft.empty());
|
||
if (!aircraft.empty()) {
|
||
EXPECT_EQ(aircraft[0].flightNo, "TEST1");
|
||
}
|
||
|
||
// 停止采集
|
||
collector->stop();
|
||
}
|
||
|
||
TEST_F(DataCollectorTest, InitializeWithTimeoutConfig) {
|
||
DataSourceConfig config;
|
||
config.host = "localhost";
|
||
config.port = 8080;
|
||
config.timeout_ms = 5000; // 连接超时 5 秒
|
||
config.read_timeout_ms = 2000; // 读取超时 2 秒
|
||
config.refresh_interval_ms = 100;
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 500;
|
||
|
||
EXPECT_NO_THROW(collector->initialize(config, warnConfig));
|
||
}
|
||
|
||
TEST_F(DataCollectorTest, TimeoutWarningTest) {
|
||
DataSourceConfig config;
|
||
config.host = "localhost";
|
||
config.port = 8080;
|
||
config.timeout_ms = 1000; // 连接超时 1 秒
|
||
config.read_timeout_ms = 500; // 读取超时 0.5 秒
|
||
config.refresh_interval_ms = 100;
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 200; // 警告间隔 0.2 秒
|
||
|
||
collector->initialize(config, warnConfig);
|
||
|
||
// 模拟连接成功但读取超时
|
||
EXPECT_CALL(*mockSource, isAvailable())
|
||
.WillRepeatedly(::testing::Return(true));
|
||
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillRepeatedly(::testing::Return(false)); // 持续读取超时
|
||
|
||
// 启动采集
|
||
collector->start();
|
||
|
||
// 等待足够长的时间以触发多次警告
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||
|
||
// 停止采集
|
||
collector->stop();
|
||
}
|
||
|
||
// 测试超时警告机制
|
||
TEST_F(DataCollectorTest, TimeoutWarningMechanism) {
|
||
DataSourceConfig config;
|
||
config.host = "localhost";
|
||
config.port = 8080;
|
||
config.timeout_ms = 200; // 连接超时 200ms
|
||
config.read_timeout_ms = 100; // 读取超时 100ms
|
||
config.refresh_interval_ms = 10;
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 50; // 警告间隔 50ms
|
||
|
||
// 创建一个计数器来记录收到的警告数量
|
||
int warningCount = 0;
|
||
|
||
// 创建一个 mock System 来捕获警告
|
||
class MockSystem : public System {
|
||
public:
|
||
MOCK_METHOD(void, broadcastTimeoutWarning, (const network::TimeoutWarningMessage&), (override));
|
||
};
|
||
|
||
auto mockSystem = std::make_shared<MockSystem>();
|
||
|
||
// 设置期望接收到超时警告
|
||
EXPECT_CALL(*mockSystem, broadcastTimeoutWarning)
|
||
.WillRepeatedly(::testing::Invoke([&warningCount](const network::TimeoutWarningMessage& warning) {
|
||
warningCount++;
|
||
// 验证警告消息的内容
|
||
EXPECT_EQ(warning.source, "data_source");
|
||
EXPECT_GT(warning.elapsed_ms, 0);
|
||
// 不检查具体的超时类型,因为这取决于实际的时间流逝
|
||
}));
|
||
|
||
// 设置 mock system 到 collector
|
||
collector->setSystem(mockSystem);
|
||
collector->initialize(config, warnConfig);
|
||
|
||
// 启动采集器
|
||
collector->start();
|
||
|
||
// 模拟数据获取失败
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillRepeatedly(::testing::Return(false));
|
||
|
||
// 等待足够长的时间以确保警告被发送
|
||
// 等待时间应该超过 refresh_interval_ms + timeout_ms + warning_interval_ms
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||
|
||
// 停止采集器
|
||
collector->stop();
|
||
|
||
// 验证是否收到了警告
|
||
EXPECT_GT(warningCount, 0);
|
||
}
|
||
|
||
// 测试读取超时机制
|
||
TEST_F(DataCollectorTest, ReadTimeoutMechanism) {
|
||
DataSourceConfig config;
|
||
config.host = "localhost";
|
||
config.port = 8080;
|
||
config.timeout_ms = 100; // 连接超时 100ms
|
||
config.read_timeout_ms = 50; // 读取超时 50ms
|
||
config.refresh_interval_ms = 10;
|
||
|
||
WarnConfig warnConfig;
|
||
warnConfig.warning_interval_ms = 20; // 警告间隔 20ms
|
||
|
||
// 创建一个计数器来记录收到的警告数量
|
||
int warningCount = 0;
|
||
|
||
// 创建一个 mock System 来捕获警告
|
||
class MockSystem : public System {
|
||
public:
|
||
MOCK_METHOD(void, broadcastTimeoutWarning, (const network::TimeoutWarningMessage&), (override));
|
||
};
|
||
|
||
auto mockSystem = std::make_shared<MockSystem>();
|
||
|
||
// 设置期望接收到超时警告
|
||
EXPECT_CALL(*mockSystem, broadcastTimeoutWarning)
|
||
.WillRepeatedly(::testing::Invoke([&warningCount](const network::TimeoutWarningMessage& warning) {
|
||
warningCount++;
|
||
// 验证警告消息的内容
|
||
EXPECT_EQ(warning.source, "data_source");
|
||
EXPECT_GT(warning.elapsed_ms, 0);
|
||
EXPECT_TRUE(warning.is_read_timeout); // 标记为读取超时
|
||
}));
|
||
|
||
// 设置 mock system 到 collector
|
||
collector->setSystem(mockSystem);
|
||
collector->initialize(config, warnConfig);
|
||
|
||
// 启动采集器
|
||
collector->start();
|
||
|
||
// 模拟读取超时
|
||
EXPECT_CALL(*mockSource, fetchAircraftData)
|
||
.WillRepeatedly(::testing::Invoke([](std::vector<Aircraft>& aircraft) {
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(60)); // 睡眠超过读取超时时间但小于连接超时
|
||
return false;
|
||
}));
|
||
|
||
// 等待足够长的时间以确保警告被发送
|
||
// 等待时间应该超过 refresh_interval_ms + read_timeout_ms + warning_interval_ms
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||
|
||
// 停止采集器
|
||
collector->stop();
|
||
|
||
// 验证是否收到了警告
|
||
EXPECT_GT(warningCount, 0);
|
||
}
|