906 lines
32 KiB
C++
906 lines
32 KiB
C++
#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");
|
||
}
|
||
}
|