QDAirPortTestSystemBackend/tests/DataCollectorTest.cpp
2026-01-27 15:24:05 +08:00

906 lines
32 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 "config/AirportBounds.h"
#include "spatial/CoordinateConverter.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&));
};
// 创建测试专用的 AirportBounds 类
class TestAirportBounds : public AirportBounds {
public:
using AirportBounds::AirportBounds; // 继承构造函数
void setBounds(const Bounds& bounds) {
this->airportBounds_ = bounds;
}
void setReferencePoint(const Vector2D& point) {
this->referencePoint_ = point;
}
void setRotationAngle(double angle) {
this->rotationAngle_ = angle * M_PI / 180.0; // 转换为弧度
}
protected:
using AirportBounds::airportBounds_;
using AirportBounds::referencePoint_;
using AirportBounds::rotationAngle_;
};
class DataCollectorTest : public ::testing::Test {
protected:
void SetUp() override {
// 设置日志级别
Logger::setLogLevel(LogLevel::DEBUG);
// 初始化系统配置
SystemConfig::instance().load("config/system_config.json");
// 创建测试实例
bounds_ = std::make_unique<TestAirportBounds>();
// 设置机场边界参数
bounds_->setReferencePoint(Vector2D{0, 0}); // 世界坐标系中的参考点
bounds_->setRotationAngle(68.53); // 与 airport_bounds.json 保持一致
bounds_->setBounds(Bounds(-100, -200, 800, 400)); // 与 airport_bounds.json 保持一致
// 初始化坐标转换器
const auto& refPoint = SystemConfig::instance().airport.reference_point;
CoordinateConverter::instance().setReferencePoint(refPoint.latitude, refPoint.longitude);
collector = std::make_unique<DataCollector>(*bounds_);
mockSource = std::make_shared<::testing::NiceMock<MockDataSource>>();
collector->setDataSource(mockSource);
// 初始化配置
dataSourceConfig_.position.refresh_interval_ms = 100;
dataSourceConfig_.position.timeout_ms = 5000; // 添加连接超时配置
dataSourceConfig_.position.read_timeout_ms = 2000; // 添加读取超时配置
dataSourceConfig_.vehicle.refresh_interval_ms = 100;
dataSourceConfig_.vehicle.timeout_ms = 5000;
dataSourceConfig_.vehicle.read_timeout_ms = 2000;
dataSourceConfig_.traffic_light.refresh_interval_ms = 100;
dataSourceConfig_.traffic_light.timeout_ms = 5000;
dataSourceConfig_.traffic_light.read_timeout_ms = 2000;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 500; // 设置警告间隔
EXPECT_TRUE(collector->initialize(dataSourceConfig_, warnConfig));
}
void TearDown() override {
collector.reset();
}
// 创建测试用的航空器
Aircraft createTestAircraft(const std::string& id, double lat, double lon) {
Aircraft aircraft;
aircraft.id = id;
aircraft.flightNo = id;
aircraft.geo.latitude = lat;
aircraft.geo.longitude = lon;
aircraft.timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
return aircraft;
}
// 创建测试用的车辆
Vehicle createTestVehicle(const std::string& id, double lat, double lon) {
Vehicle vehicle;
vehicle.id = id;
vehicle.vehicleNo = id;
vehicle.geo.latitude = lat;
vehicle.geo.longitude = lon;
vehicle.timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
return vehicle;
}
// 创建测试用的红绿灯信号
TrafficLightSignal createTestTrafficLight(const std::string& id, int state) {
TrafficLightSignal signal;
signal.trafficLightId = id;
signal.ns_status = static_cast<SignalStatus>(state);
signal.ew_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;
}
// 创建边界内的航空器
Aircraft createOutOfBoundsAircraft(const std::string& id) {
// 计算偏移量,考虑机场旋转角度
double angle = 68.53 * M_PI / 180.0; // 转换为弧度
double offset = 0.027; // 约 3km
double lat_offset = offset * std::cos(angle);
double lon_offset = offset * std::sin(angle);
const auto& refPoint = SystemConfig::instance().airport.reference_point;
return createTestAircraft(id, refPoint.latitude + lat_offset, refPoint.longitude + lon_offset);
}
// 创建边界内的车辆
Vehicle createOutOfBoundsVehicle(const std::string& id) {
// 计算偏移量,考虑机场旋转角度
double angle = 68.53 * M_PI / 180.0; // 转换为弧度
double offset = 0.0225; // 约 2.5km
double lat_offset = -offset * std::cos(angle); // 负值表示向相反方向偏移
double lon_offset = -offset * std::sin(angle);
const auto& refPoint = SystemConfig::instance().airport.reference_point;
return createTestVehicle(id, refPoint.latitude + lat_offset, refPoint.longitude + lon_offset);
}
std::unique_ptr<DataCollector> collector;
std::shared_ptr<MockDataSource> mockSource;
std::unique_ptr<TestAirportBounds> bounds_;
std::unique_ptr<CoordinateConverter> converter_;
DataSourceConfig dataSourceConfig_;
};
// 修改初始化测试用例
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 = 2000;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 1000;
warnConfig.log_interval_ms = 2000;
EXPECT_TRUE(collector->initialize(dataSourceConfig, warnConfig));
}
// 测试数据采集
TEST_F(DataCollectorTest, DataCollectionTest) {
// 设置数据源配置
DataSourceConfig config;
// 设置位置数据配置
config.position.host = "localhost";
config.position.port = 8080;
config.position.refresh_interval_ms = 100;
config.position.timeout_ms = 1000;
config.position.read_timeout_ms = 500;
// 设置无人车数据配置
config.vehicle.host = "localhost";
config.vehicle.port = 8081;
config.vehicle.refresh_interval_ms = 100;
config.vehicle.timeout_ms = 1000;
config.vehicle.read_timeout_ms = 500;
// 设置红绿灯数据配置
config.traffic_light.host = "localhost";
config.traffic_light.port = 8082;
config.traffic_light.refresh_interval_ms = 100;
config.traffic_light.timeout_ms = 1000;
config.traffic_light.read_timeout_ms = 500;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 200;
collector->initialize(config, warnConfig);
std::vector<Aircraft> testAircraft = {
createTestAircraft("TEST1", 36.354483470, 120.08502054), // 参考点,转换后是 (0, 0)
createTestAircraft("TEST2", 36.354483470 + 0.0002 * std::cos(68.53 * M_PI / 180.0),
120.08502054 + 0.0002 * std::sin(68.53 * M_PI / 180.0)) // 沿机场方向偏移约 20m
};
std::vector<Vehicle> testVehicles = {
createTestVehicle("VEH1", 36.354483470, 120.08502054), // 参考点,转换后是 (0, 0)
createTestVehicle("VEH2", 36.354483470 - 0.0002 * std::cos(68.53 * M_PI / 180.0),
120.08502054 - 0.0002 * std::sin(68.53 * M_PI / 180.0)) // 沿机场方向反向偏移约 20m
};
std::vector<TrafficLightSignal> testSignals = {
createTestTrafficLight("TL001", 0),
createTestTrafficLight("TL002", 1)
};
// 设置 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)
));
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testSignals),
::testing::Return(true)
));
std::string testStatus = "NORMAL";
EXPECT_CALL(*mockSource, fetchUnmannedVehicleStatus(::testing::_, ::testing::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<1>(testStatus),
::testing::Return(true)
));
// 启动数据采集
collector->start();
// 等待数据更新(至少 1000ms确保数据被采集
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// 获取最新数据
auto [aircraft, vehicles, traffic_lights] = collector->getLatestData();
auto [aircraft_ts, vehicle_ts, traffic_light_ts] = collector->getLastUpdateTimestamps();
// 验证数据
EXPECT_EQ(aircraft.size(), 2);
if (!aircraft.empty()) {
EXPECT_EQ(aircraft[0].flightNo, "TEST1");
EXPECT_EQ(aircraft[1].flightNo, "TEST2");
}
EXPECT_EQ(vehicles.size(), 2);
if (!vehicles.empty()) {
EXPECT_EQ(vehicles[0].vehicleNo, "VEH1");
EXPECT_EQ(vehicles[1].vehicleNo, "VEH2");
}
EXPECT_EQ(traffic_lights.size(), 2);
if (!traffic_lights.empty()) {
EXPECT_EQ(traffic_lights[0].trafficLightId, "TL001");
EXPECT_EQ(traffic_lights[1].trafficLightId, "TL002");
}
// 验证时间戳
EXPECT_GT(aircraft_ts, 0);
EXPECT_GT(vehicle_ts, 0);
EXPECT_GT(traffic_light_ts, 0);
// 停止数据采集
collector->stop();
}
// 测试数据采集循环
TEST_F(DataCollectorTest, DataCollectionLoop) {
std::vector<Aircraft> testAircraft = {
createTestAircraft("TEST1", 36.354483470, 120.08502054) // 参考点
};
std::vector<Vehicle> testVehicles = {
createTestVehicle("VEH1", 36.354483470, 120.08502054) // 参考点
};
// 设置 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::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.WillRepeatedly(::testing::Return(false));
// 启动数据采集
collector->start();
// 等待数据更新(至少三个采集周期)
std::this_thread::sleep_for(std::chrono::milliseconds(
dataSourceConfig_.position.refresh_interval_ms * 3));
// 获取最新数据
auto [aircraft, vehicles, traffic_lights] = collector->getLatestData();
// 验证数据为空
EXPECT_TRUE(aircraft.empty());
EXPECT_TRUE(vehicles.empty());
// 停止数据采集
collector->stop();
}
// 测试红绿灯信号获取
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::_))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testSignals),
::testing::Return(true)
));
// 启动数据采集
collector->start();
// 等待数据更新(至少三个采集周期)
std::this_thread::sleep_for(std::chrono::milliseconds(
dataSourceConfig_.position.refresh_interval_ms * 3));
// 验证数据
auto signals = collector->getTrafficLightSignals();
EXPECT_EQ(signals.size(), 3);
if (signals.size() >= 3) {
EXPECT_EQ(signals[0].trafficLightId, "TL001");
EXPECT_EQ(signals[0].ns_status, SignalStatus::RED); // RED = 0
EXPECT_EQ(signals[1].trafficLightId, "TL002");
EXPECT_EQ(signals[1].ns_status, SignalStatus::GREEN); // GREEN = 1
}
// 停止数据采集
collector->stop();
}
// 测试红绿灯信号错误处理
TEST_F(DataCollectorTest, TrafficLightSignalsErrorTest) {
// 设置 Mock 返回错误
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillRepeatedly(::testing::Return(false));
// 启动数据采集
collector->start();
// 等待数据更新(至少三个采集周期)
std::this_thread::sleep_for(std::chrono::milliseconds(
dataSourceConfig_.position.refresh_interval_ms * 3));
// 验证数据为空
auto signals = collector->getTrafficLightSignals();
EXPECT_TRUE(signals.empty());
// 停止数据采集
collector->stop();
}
// 测试连接健康检查和超时告警
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 = 100;
config.position.timeout_ms = 1000;
config.position.read_timeout_ms = 500;
// 设置无人车数据配置
config.vehicle.host = "localhost";
config.vehicle.port = 8081;
config.vehicle.refresh_interval_ms = 100;
config.vehicle.timeout_ms = 1000;
config.vehicle.read_timeout_ms = 500;
// 设置红绿灯数据配置
config.traffic_light.host = "localhost";
config.traffic_light.port = 8082;
config.traffic_light.refresh_interval_ms = 100;
config.traffic_light.timeout_ms = 1000;
config.traffic_light.read_timeout_ms = 500;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 200;
collector->initialize(config, warnConfig);
std::vector<Aircraft> testAircraft = {
createTestAircraft("TEST1", 36.354483470, 120.08502054) // 参考点
};
// 设置 Mock 行为: 前两次失败,然后成功
EXPECT_CALL(*mockSource, fetchPositionAircraftData(::testing::_))
.WillOnce(::testing::Return(false))
.WillOnce(::testing::Return(false))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testAircraft),
::testing::Return(true)
));
// 添加车辆数据的 mock 行为
std::vector<Vehicle> testVehicles;
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.WillOnce(::testing::Return(false))
.WillOnce(::testing::Return(false))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testVehicles),
::testing::Return(true)
));
// 设置无人车数据 Mock 行为
std::string testStatus = "NORMAL";
EXPECT_CALL(*mockSource, fetchUnmannedVehicleStatus(::testing::_, ::testing::_))
.WillOnce(::testing::Return(false))
.WillOnce(::testing::Return(false))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<1>(testStatus),
::testing::Return(true)
));
// 设置红绿灯数据 Mock 行为
std::vector<TrafficLightSignal> testSignals = {
createTestTrafficLight("TL001", 0)
};
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillOnce(::testing::Return(false))
.WillOnce(::testing::Return(false))
.WillRepeatedly(::testing::DoAll(
::testing::SetArgReferee<0>(testSignals),
::testing::Return(true)
));
// 启动数据采集
collector->start();
// 等待足够长的时间以确保连接恢复
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// 获取最新数据
auto [aircraft, vehicles, traffic_lights] = collector->getLatestData();
// 验证数据
EXPECT_EQ(aircraft.size(), 1);
if (!aircraft.empty()) {
EXPECT_EQ(aircraft[0].flightNo, "TEST1");
}
// 验证红绿灯数据
EXPECT_EQ(traffic_lights.size(), 1);
if (!traffic_lights.empty()) {
EXPECT_EQ(traffic_lights[0].trafficLightId, "TL001");
}
// 停止数据采集
collector->stop();
}
// 测试长连接下的数据获取
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.354483470, 120.08502054), // 参考点,转换后是 (0, 0)
createTestAircraft("TEST2", 36.354483470 + 0.0002 * std::cos(68.53 * M_PI / 180.0),
120.08502054 + 0.0002 * std::sin(68.53 * M_PI / 180.0)) // 沿机场方向偏移约 20m
};
std::vector<Vehicle> testVehicles = {
createTestVehicle("VEH1", 36.354483470, 120.08502054), // 参考点,转换后是 (0, 0)
createTestVehicle("VEH2", 36.354483470 - 0.0002 * std::cos(68.53 * M_PI / 180.0),
120.08502054 - 0.0002 * std::sin(68.53 * M_PI / 180.0)) // 沿机场方向反向偏移约 20m
};
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 = 1000; // 连接超时 1000ms
config.position.read_timeout_ms = 500; // 读取超时 500ms
config.position.refresh_interval_ms = 100;
// 设置无人车数据配置
config.vehicle.host = "localhost";
config.vehicle.port = 8081;
config.vehicle.timeout_ms = 1000;
config.vehicle.read_timeout_ms = 500;
config.vehicle.refresh_interval_ms = 100;
// 设置红绿灯数据配置
config.traffic_light.host = "localhost";
config.traffic_light.port = 8082;
config.traffic_light.timeout_ms = 1000;
config.traffic_light.read_timeout_ms = 500;
config.traffic_light.refresh_interval_ms = 100;
WarnConfig warnConfig;
warnConfig.warning_interval_ms = 200; // 警告间隔 200ms
// 创建一个计数器来记录收到的警告数量
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::Return(false));
EXPECT_CALL(*mockSource, fetchPositionVehicleData(::testing::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchTrafficLightSignals(::testing::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(*mockSource, fetchUnmannedVehicleStatus(::testing::_, ::testing::_))
.WillRepeatedly(::testing::Return(false));
// 等待足够长的时间以确保警告被发送
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
// 停止采集器
collector->stop();
// 验证是否收到了警告
EXPECT_GT(warningCount, 0);
}
// 添加新的测试用例:测试边界外数据过滤
TEST_F(DataCollectorTest, OutOfBoundsDataFiltering) {
DataSourceConfig dataSourceConfig;
WarnConfig warnConfig;
EXPECT_TRUE(collector->initialize(dataSourceConfig, warnConfig));
// 创建测试数据:混合边界内外的数据
const auto& refPoint = SystemConfig::instance().airport.reference_point;
// 创建边界内的航空器
std::vector<Aircraft> testAircraft = {
createTestAircraft("IN_BOUNDS_1", refPoint.latitude, refPoint.longitude), // 参考点
createTestAircraft("IN_BOUNDS_2",
refPoint.latitude + 0.001 * std::cos(68.53 * M_PI / 180.0), // 沿机场方向偏移约 100m
refPoint.longitude + 0.001 * std::sin(68.53 * M_PI / 180.0)),
createOutOfBoundsAircraft("OUT_BOUNDS_1"), // 边界外偏移约 3km
createOutOfBoundsAircraft("OUT_BOUNDS_2") // 边界外偏移约 3km
};
// 创建边界内的车辆
std::vector<Vehicle> testVehicles = {
createTestVehicle("VEH_IN_1", refPoint.latitude, refPoint.longitude), // 参考点
createTestVehicle("VEH_IN_2",
refPoint.latitude + 0.001 * std::cos(68.53 * M_PI / 180.0), // 沿机场方向偏移约 100m
refPoint.longitude + 0.001 * std::sin(68.53 * M_PI / 180.0)),
createOutOfBoundsVehicle("VEH_OUT_1"), // 边界外偏移约 2.5km
createOutOfBoundsVehicle("VEH_OUT_2") // 边界外偏移约 2.5km
};
// 设置 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->fetchPositionData();
// 验证过滤结果
const auto& filteredAircraft = collector->getAircraftData();
const auto& filteredVehicles = collector->getVehicleData();
// 检查过滤后的数量
EXPECT_EQ(filteredAircraft.size(), 2) << "应该只保留2架在边界内的航空器";
EXPECT_EQ(filteredVehicles.size(), 2) << "应该只保留2辆在边界内的车辆";
// 检查保留的是正确的航空器
if (filteredAircraft.size() >= 2) {
EXPECT_EQ(filteredAircraft[0].flightNo, "IN_BOUNDS_1");
EXPECT_EQ(filteredAircraft[1].flightNo, "IN_BOUNDS_2");
}
// 检查保留的是正确的车辆
if (filteredVehicles.size() >= 2) {
EXPECT_EQ(filteredVehicles[0].vehicleNo, "VEH_IN_1");
EXPECT_EQ(filteredVehicles[1].vehicleNo, "VEH_IN_2");
}
}