CollisionAvoidance/tests/DataCollectorTest.cpp

592 lines
19 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_METHOD0(connect, bool());
MOCK_METHOD0(disconnect, void());
MOCK_CONST_METHOD0(isAvailable, bool());
MOCK_METHOD1(fetchPositionAircraftData, bool(std::vector<Aircraft>&));
MOCK_METHOD1(fetchPositionVehicleData, bool(std::vector<Vehicle>&));
MOCK_METHOD1(fetchTrafficLightSignals, bool(std::vector<TrafficLightSignal>&));
MOCK_METHOD2(sendUnmannedVehicleCommand, bool(const std::string&, const VehicleCommand&));
MOCK_METHOD2(fetchUnmannedVehicleStatus, bool(const std::string&, std::string&));
};
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::duration_cast<std::chrono::milliseconds>(
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::duration_cast<std::chrono::milliseconds>(
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::duration_cast<std::chrono::milliseconds>(
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.position.host = "localhost";
dataSourceConfig.position.port = 8080;
dataSourceConfig.position.aircraft_path = "/api/getCurrentFlightPositions";
dataSourceConfig.position.refresh_interval_ms = 1000;
dataSourceConfig.position.timeout_ms = 5000;
dataSourceConfig.position.read_timeout_ms = 1000;
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, fetchPositionAircraftData(::testing::_))
.WillOnce(::testing::DoAll(
::testing::SetArgReferee<0>(testAircraft),
::testing::Return(true)
));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.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, fetchPositionAircraftData(::testing::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testAircraft),
::testing::Return(true)
));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.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, fetchPositionAircraftData(::testing::_))
.WillOnce(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.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(::testing::_))
.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(::testing::_))
.WillOnce(::testing::Return(false));
// 执行刷新
collector->refresh();
// 验证数据为空
auto signals = collector->getTrafficLightSignals();
EXPECT_TRUE(signals.empty());
}
// 测试连接健康检查和超时告警
TEST_F(DataCollectorTest, ConnectionHealthAndTimeout) {
DataSourceConfig dataSourceConfig;
// 设置位置数据配置
dataSourceConfig.position.host = "localhost";
dataSourceConfig.position.port = 8080;
dataSourceConfig.position.timeout_ms = 1000; // 1秒超时
dataSourceConfig.position.read_timeout_ms = 500; // 0.5秒读取超时
dataSourceConfig.position.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));
// 模拟数据获取失败
EXPECT_CALL(*mockSource, fetchPositionAircraftData(::testing::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.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.position.host = "localhost";
config.position.port = 8080;
config.position.refresh_interval_ms = 10;
config.position.timeout_ms = 1000;
config.position.read_timeout_ms = 500;
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, fetchPositionAircraftData(::testing::_))
.WillOnce(::testing::Return(false))
.WillOnce(::testing::DoAll(
::testing::SetArgReferee<0>(testAircraft),
::testing::Return(true)
));
// 执行两次刷新
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.position.host = "localhost";
dataSourceConfig.position.port = 8080;
dataSourceConfig.position.refresh_interval_ms = 100;
dataSourceConfig.position.timeout_ms = 1000;
dataSourceConfig.position.read_timeout_ms = 500;
collector->initialize(dataSourceConfig, WarnConfig{});
std::vector<Aircraft> testAircraft = {
createTestAircraft("TEST1", 36.36, 120.08)
};
std::vector<Vehicle> testVehicles = {
createTestVehicle("VEH1", 36.36, 120.08)
};
std::vector<TrafficLightSignal> testSignals = {
createTestTrafficLight("TL001", 0)
};
// 模拟连接保持可用
EXPECT_CALL(*mockSource, isAvailable())
.WillRepeatedly(::testing::Return(true));
// 模拟多次成功获取数据
EXPECT_CALL(*mockSource, fetchPositionAircraftData(::testing::_))
.Times(::testing::AtLeast(3))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testAircraft),
::testing::Return(true)
));
// 添加其他数据源的 mock 行为
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testVehicles),
::testing::Return(true)
));
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testSignals),
::testing::Return(true)
));
// 添加无人车状态获取的 mock 行为
std::string testStatus = "NORMAL";
EXPECT_CALL(*mockSource, fetchUnmannedVehicleStatus(::testing::_, ::testing::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<1>(testStatus),
::testing::Return(true)
));
// 启动采集
collector->start();
// 等待多个刷新周期
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 增加等待时间确保执行次数
// 验证数据
auto aircraft = collector->getAircraftData();
EXPECT_FALSE(aircraft.empty());
if (!aircraft.empty()) {
EXPECT_EQ(aircraft[0].flightNo, "TEST1");
}
auto vehicles = collector->getVehicleData();
EXPECT_FALSE(vehicles.empty());
if (!vehicles.empty()) {
EXPECT_EQ(vehicles[0].vehicleNo, "VEH1");
}
auto signals = collector->getTrafficLightSignals();
EXPECT_FALSE(signals.empty());
if (!signals.empty()) {
EXPECT_EQ(signals[0].trafficLightId, "TL001");
}
// 停止采集
collector->stop();
}
TEST_F(DataCollectorTest, InitializeWithTimeoutConfig) {
DataSourceConfig config;
// 设置位置数据配置
config.position.host = "localhost";
config.position.port = 8080;
config.position.timeout_ms = 5000; // 连接超时 5 秒
config.position.read_timeout_ms = 2000; // 读取超时 2 秒
config.position.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.position.host = "localhost";
config.position.port = 8080;
config.position.timeout_ms = 1000; // 连接超时 1 秒
config.position.read_timeout_ms = 500; // 读取超时 0.5 秒
config.position.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, fetchPositionAircraftData(::testing::_))
.WillRepeatedly(::testing::Return(false)); // 持续读取超时
// 启动采集
collector->start();
// 等待足够长的时间以触发多次警告
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// 停止采集
collector->stop();
}
// 测试超时警告机制
TEST_F(DataCollectorTest, TimeoutWarningMechanism) {
DataSourceConfig config;
// 设置位置数据配置
config.position.host = "localhost";
config.position.port = 8080;
config.position.timeout_ms = 200; // 连接超时 200ms
config.position.read_timeout_ms = 100; // 读取超时 100ms
config.position.refresh_interval_ms = 10;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 50; // 警告间隔 50ms
// 创建一个计数器来记录收到的警告数量
int warningCount = 0;
// 创建一个 mock System 来捕获警告
class MockSystem : public System {
public:
MOCK_METHOD1(broadcastTimeoutWarning, void(const network::TimeoutWarningMessage&));
};
auto mockSystem = std::make_shared<MockSystem>();
// 设置期望接收到超时警告
EXPECT_CALL(*mockSystem, broadcastTimeoutWarning(::testing::_))
.WillRepeatedly(::testing::Invoke([&warningCount](const network::TimeoutWarningMessage& warning) {
warningCount++;
// 验证警告消息的内容
EXPECT_THAT(warning.source, ::testing::AnyOf(
::testing::StrEq("position"),
::testing::StrEq("unmanned"),
::testing::StrEq("traffic_light")
));
EXPECT_GT(warning.elapsed_ms, 0);
}));
// 设置 mock system 到 collector
collector->setSystem(mockSystem);
collector->initialize(config, warnConfig);
// 启动采集器
collector->start();
// 模拟所有数据源获取失败
EXPECT_CALL(*mockSource, fetchPositionAircraftData(::testing::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillRepeatedly(::testing::Return(false));
// 等待足够长的时间以确保警告被发送
std::this_thread::sleep_for(std::chrono::milliseconds(300));
// 停止采集器
collector->stop();
// 验证是否收到了警告
EXPECT_GT(warningCount, 0);
}
// 测试读取超时机制
TEST_F(DataCollectorTest, ReadTimeoutMechanism) {
DataSourceConfig config;
// 设置位置数据配置
config.position.host = "localhost";
config.position.port = 8080;
config.position.timeout_ms = 100; // 连接超时 100ms
config.position.read_timeout_ms = 50; // 读取超时 50ms
config.position.refresh_interval_ms = 10;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 20; // 警告间隔 20ms
// 创建一个计数器来记录收到的警告数量
int warningCount = 0;
// 创建一个 mock System 来捕获警告
class MockSystem : public System {
public:
MOCK_METHOD1(broadcastTimeoutWarning, void(const network::TimeoutWarningMessage&));
};
auto mockSystem = std::make_shared<MockSystem>();
// 设置期望接收到超时警告
EXPECT_CALL(*mockSystem, broadcastTimeoutWarning(::testing::_))
.WillRepeatedly(::testing::Invoke([&warningCount](const network::TimeoutWarningMessage& warning) {
warningCount++;
// 验证警告消息的内容
EXPECT_THAT(warning.source, ::testing::AnyOf(
::testing::StrEq("position"),
::testing::StrEq("unmanned"),
::testing::StrEq("traffic_light")
));
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, fetchPositionAircraftData(::testing::_))
.WillRepeatedly(::testing::Invoke([](std::vector<Aircraft>& aircraft) {
std::this_thread::sleep_for(std::chrono::milliseconds(60)); // 睡眠超过读取超时时间但小于连接超时
return false;
}));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.WillRepeatedly(::testing::Invoke([](std::vector<Vehicle>& vehicles) {
std::this_thread::sleep_for(std::chrono::milliseconds(60));
return false;
}));
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillRepeatedly(::testing::Invoke([](std::vector<TrafficLightSignal>& signals) {
std::this_thread::sleep_for(std::chrono::milliseconds(60));
return false;
}));
// 等待足够长的时间以确保警告被发送
std::this_thread::sleep_for(std::chrono::milliseconds(300));
// 停止采集器
collector->stop();
// 验证是否收到了警告
EXPECT_GT(warningCount, 0);
}