CollisionAvoidance/tests/DataCollectorTest.cpp

499 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}