419 lines
14 KiB
C++
419 lines
14 KiB
C++
#include <gtest/gtest.h>
|
|
#include <gmock/gmock.h>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
|
|
// ==================== 模拟数据结构 ====================
|
|
|
|
enum class PortType { SC, LC, FC, ST };
|
|
|
|
struct RackCreate {
|
|
std::string rack_name;
|
|
std::string location;
|
|
};
|
|
|
|
struct UnitCreate {
|
|
int unit_number;
|
|
std::string unit_name;
|
|
int position;
|
|
int port_count;
|
|
PortType port_type;
|
|
};
|
|
|
|
struct ConnectionCreate {
|
|
std::string port_a_id;
|
|
std::string port_b_id;
|
|
double fiber_length;
|
|
std::string remark;
|
|
};
|
|
|
|
struct RackListResponse {
|
|
std::string rack_id;
|
|
std::string rack_name;
|
|
int unit_count;
|
|
};
|
|
|
|
struct PortResponse {
|
|
std::string port_id;
|
|
int port_number;
|
|
PortType port_type;
|
|
std::string status;
|
|
};
|
|
|
|
struct UnitResponse {
|
|
std::string unit_id;
|
|
int unit_number;
|
|
std::string unit_name;
|
|
int position;
|
|
std::vector<PortResponse> ports;
|
|
};
|
|
|
|
struct RackResponse {
|
|
std::string rack_id;
|
|
std::string rack_name;
|
|
std::string location;
|
|
std::vector<UnitResponse> units;
|
|
};
|
|
|
|
struct FreePortResponse {
|
|
std::string port_id;
|
|
std::string rack_id;
|
|
int unit_number;
|
|
int port_number;
|
|
PortType port_type;
|
|
};
|
|
|
|
struct PortDetail {
|
|
std::string port_id;
|
|
int port_number;
|
|
PortType port_type;
|
|
std::string status;
|
|
std::string unit_id;
|
|
std::string rack_id;
|
|
};
|
|
|
|
struct ConnectionResponse {
|
|
std::string connection_id;
|
|
std::string port_a_id;
|
|
std::string port_b_id;
|
|
double fiber_length;
|
|
std::string remark;
|
|
};
|
|
|
|
// ==================== 被测服务类(模拟实现) ====================
|
|
|
|
class ODFService {
|
|
public:
|
|
virtual ~ODFService() = default;
|
|
|
|
virtual std::vector<RackListResponse> list_racks() = 0;
|
|
virtual std::optional<RackResponse> get_rack(const std::string& rack_id) = 0;
|
|
virtual RackResponse create_rack(const RackCreate& body) = 0;
|
|
virtual bool delete_rack(const std::string& rack_id) = 0;
|
|
virtual std::optional<UnitResponse> create_unit(const std::string& rack_id, const UnitCreate& body) = 0;
|
|
virtual bool delete_unit(const std::string& unit_id) = 0;
|
|
virtual std::vector<FreePortResponse> get_free_ports(const std::optional<std::string>& rack_id) = 0;
|
|
virtual std::optional<PortDetail> get_port_detail(const std::string& port_id) = 0;
|
|
virtual std::vector<ConnectionResponse> list_connections() = 0;
|
|
virtual std::optional<ConnectionResponse> create_connection(const ConnectionCreate& body) = 0;
|
|
virtual bool delete_connection(const std::string& connection_id) = 0;
|
|
virtual std::optional<std::string> get_port_path(const std::string& port_id) = 0;
|
|
virtual std::string health_check() = 0;
|
|
};
|
|
|
|
// 模拟实现(用于测试基类)
|
|
class MockODFService : public ODFService {
|
|
public:
|
|
MOCK_METHOD(std::vector<RackListResponse>, list_racks, (), (override));
|
|
MOCK_METHOD(std::optional<RackResponse>, get_rack, (const std::string& rack_id), (override));
|
|
MOCK_METHOD(RackResponse, create_rack, (const RackCreate& body), (override));
|
|
MOCK_METHOD(bool, delete_rack, (const std::string& rack_id), (override));
|
|
MOCK_METHOD(std::optional<UnitResponse>, create_unit, (const std::string& rack_id, const UnitCreate& body), (override));
|
|
MOCK_METHOD(bool, delete_unit, (const std::string& unit_id), (override));
|
|
MOCK_METHOD(std::vector<FreePortResponse>, get_free_ports, (const std::optional<std::string>& rack_id), (override));
|
|
MOCK_METHOD(std::optional<PortDetail>, get_port_detail, (const std::string& port_id), (override));
|
|
MOCK_METHOD(std::vector<ConnectionResponse>, list_connections, (), (override));
|
|
MOCK_METHOD(std::optional<ConnectionResponse>, create_connection, (const ConnectionCreate& body), (override));
|
|
MOCK_METHOD(bool, delete_connection, (const std::string& connection_id), (override));
|
|
MOCK_METHOD(std::optional<std::string>, get_port_path, (const std::string& port_id), (override));
|
|
MOCK_METHOD(std::string, health_check, (), (override));
|
|
};
|
|
|
|
// ==================== 测试夹具 ====================
|
|
|
|
class ODFServiceTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
mock_service = std::make_shared<MockODFService>();
|
|
}
|
|
|
|
void TearDown() override {
|
|
mock_service.reset();
|
|
}
|
|
|
|
std::shared_ptr<MockODFService> mock_service;
|
|
};
|
|
|
|
// ==================== 机架 API 测试 ====================
|
|
|
|
TEST_F(ODFServiceTest, testListRacksNormal) {
|
|
std::vector<RackListResponse> expected = {
|
|
{"rack1", "Rack A", 3},
|
|
{"rack2", "Rack B", 0}
|
|
};
|
|
EXPECT_CALL(*mock_service, list_racks())
|
|
.WillOnce(::testing::Return(expected));
|
|
|
|
auto result = mock_service->list_racks();
|
|
ASSERT_EQ(result.size(), 2);
|
|
EXPECT_EQ(result[0].rack_id, "rack1");
|
|
EXPECT_EQ(result[1].unit_count, 0);
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testListRacksEmpty) {
|
|
EXPECT_CALL(*mock_service, list_racks())
|
|
.WillOnce(::testing::Return(std::vector<RackListResponse>{}));
|
|
|
|
auto result = mock_service->list_racks();
|
|
EXPECT_TRUE(result.empty());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetRackExists) {
|
|
RackResponse rack;
|
|
rack.rack_id = "rack1";
|
|
rack.rack_name = "Main Rack";
|
|
EXPECT_CALL(*mock_service, get_rack("rack1"))
|
|
.WillOnce(::testing::Return(std::optional<RackResponse>(rack)));
|
|
|
|
auto result = mock_service->get_rack("rack1");
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_EQ(result->rack_id, "rack1");
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetRackNotFound) {
|
|
EXPECT_CALL(*mock_service, get_rack("invalid"))
|
|
.WillOnce(::testing::Return(std::nullopt));
|
|
|
|
auto result = mock_service->get_rack("invalid");
|
|
EXPECT_FALSE(result.has_value());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateRackNormal) {
|
|
RackCreate body{"New Rack", "Room 101"};
|
|
RackResponse expected;
|
|
expected.rack_id = "rack_new";
|
|
expected.rack_name = "New Rack";
|
|
expected.location = "Room 101";
|
|
|
|
EXPECT_CALL(*mock_service, create_rack(body))
|
|
.WillOnce(::testing::Return(expected));
|
|
|
|
auto result = mock_service->create_rack(body);
|
|
EXPECT_EQ(result.rack_name, "New Rack");
|
|
EXPECT_EQ(result.location, "Room 101");
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateRackEmptyName) {
|
|
RackCreate body{"", "Location"};
|
|
EXPECT_CALL(*mock_service, create_rack(body))
|
|
.WillOnce(::testing::Throw(std::invalid_argument("rack_name cannot be empty")));
|
|
|
|
EXPECT_THROW(mock_service->create_rack(body), std::invalid_argument);
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testDeleteRackSuccess) {
|
|
EXPECT_CALL(*mock_service, delete_rack("rack1"))
|
|
.WillOnce(::testing::Return(true));
|
|
|
|
EXPECT_TRUE(mock_service->delete_rack("rack1"));
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testDeleteRackNotFound) {
|
|
EXPECT_CALL(*mock_service, delete_rack("ghost"))
|
|
.WillOnce(::testing::Return(false));
|
|
|
|
EXPECT_FALSE(mock_service->delete_rack("ghost"));
|
|
}
|
|
|
|
// ==================== 配线单元 API 测试 ====================
|
|
|
|
TEST_F(ODFServiceTest, testCreateUnitNormal) {
|
|
UnitCreate body{1, "Unit 1", 1, 12, PortType::SC};
|
|
UnitResponse unit;
|
|
unit.unit_id = "unit1";
|
|
unit.unit_number = 1;
|
|
unit.unit_name = "Unit 1";
|
|
unit.position = 1;
|
|
unit.ports = std::vector<PortResponse>(12);
|
|
|
|
EXPECT_CALL(*mock_service, create_unit("rack1", body))
|
|
.WillOnce(::testing::Return(std::optional<UnitResponse>(unit)));
|
|
|
|
auto result = mock_service->create_unit("rack1", body);
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_EQ(result->unit_number, 1);
|
|
EXPECT_EQ(result->ports.size(), 12);
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateUnitRackNotFound) {
|
|
UnitCreate body{1, "Unit 1", 1, 12, PortType::LC};
|
|
EXPECT_CALL(*mock_service, create_unit("bad_rack", body))
|
|
.WillOnce(::testing::Return(std::nullopt));
|
|
|
|
auto result = mock_service->create_unit("bad_rack", body);
|
|
EXPECT_FALSE(result.has_value());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateUnitInvalidPortCount) {
|
|
UnitCreate body{1, "Unit 1", 1, 0, PortType::FC};
|
|
EXPECT_CALL(*mock_service, create_unit("rack1", body))
|
|
.WillOnce(::testing::Throw(std::invalid_argument("port_count must be positive")));
|
|
|
|
EXPECT_THROW(mock_service->create_unit("rack1", body), std::invalid_argument);
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testDeleteUnitSuccess) {
|
|
EXPECT_CALL(*mock_service, delete_unit("unit1"))
|
|
.WillOnce(::testing::Return(true));
|
|
|
|
EXPECT_TRUE(mock_service->delete_unit("unit1"));
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testDeleteUnitNotFound) {
|
|
EXPECT_CALL(*mock_service, delete_unit("unknown"))
|
|
.WillOnce(::testing::Return(false));
|
|
|
|
EXPECT_FALSE(mock_service->delete_unit("unknown"));
|
|
}
|
|
|
|
// ==================== 端口 API 测试 ====================
|
|
|
|
TEST_F(ODFServiceTest, testGetFreePortsAll) {
|
|
std::vector<FreePortResponse> ports = {
|
|
{"port1", "rack1", 1, 1, PortType::SC},
|
|
{"port2", "rack1", 1, 2, PortType::SC}
|
|
};
|
|
EXPECT_CALL(*mock_service, get_free_ports(std::nullopt))
|
|
.WillOnce(::testing::Return(ports));
|
|
|
|
auto result = mock_service->get_free_ports(std::nullopt);
|
|
ASSERT_EQ(result.size(), 2);
|
|
EXPECT_EQ(result[0].port_id, "port1");
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetFreePortsFilterByRack) {
|
|
std::vector<FreePortResponse> ports = {
|
|
{"port3", "rack2", 2, 1, PortType::LC}
|
|
};
|
|
EXPECT_CALL(*mock_service, get_free_ports(std::optional<std::string>("rack2")))
|
|
.WillOnce(::testing::Return(ports));
|
|
|
|
auto result = mock_service->get_free_ports("rack2");
|
|
ASSERT_EQ(result.size(), 1);
|
|
EXPECT_EQ(result[0].rack_id, "rack2");
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetFreePortsRackNotFound) {
|
|
EXPECT_CALL(*mock_service, get_free_ports(std::optional<std::string>("ghost")))
|
|
.WillOnce(::testing::Return(std::vector<FreePortResponse>{}));
|
|
|
|
auto result = mock_service->get_free_ports("ghost");
|
|
EXPECT_TRUE(result.empty());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetPortDetailExists) {
|
|
PortDetail detail{"port1", 1, PortType::SC, "FREE", "unit1", "rack1"};
|
|
EXPECT_CALL(*mock_service, get_port_detail("port1"))
|
|
.WillOnce(::testing::Return(std::optional<PortDetail>(detail)));
|
|
|
|
auto result = mock_service->get_port_detail("port1");
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_EQ(result->status, "FREE");
|
|
EXPECT_EQ(result->rack_id, "rack1");
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetPortDetailNotFound) {
|
|
EXPECT_CALL(*mock_service, get_port_detail("bad_port"))
|
|
.WillOnce(::testing::Return(std::nullopt));
|
|
|
|
auto result = mock_service->get_port_detail("bad_port");
|
|
EXPECT_FALSE(result.has_value());
|
|
}
|
|
|
|
// ==================== 跳接连接 API 测试 ====================
|
|
|
|
TEST_F(ODFServiceTest, testListConnectionsNormal) {
|
|
std::vector<ConnectionResponse> conns = {
|
|
{"conn1", "port1", "port2", 10.5, "test"}
|
|
};
|
|
EXPECT_CALL(*mock_service, list_connections())
|
|
.WillOnce(::testing::Return(conns));
|
|
|
|
auto result = mock_service->list_connections();
|
|
ASSERT_EQ(result.size(), 1);
|
|
EXPECT_EQ(result[0].connection_id, "conn1");
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testListConnectionsEmpty) {
|
|
EXPECT_CALL(*mock_service, list_connections())
|
|
.WillOnce(::testing::Return(std::vector<ConnectionResponse>{}));
|
|
|
|
auto result = mock_service->list_connections();
|
|
EXPECT_TRUE(result.empty());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateConnectionNormal) {
|
|
ConnectionCreate body{"port1", "port2", 5.0, "link"};
|
|
ConnectionResponse conn{"conn1", "port1", "port2", 5.0, "link"};
|
|
EXPECT_CALL(*mock_service, create_connection(body))
|
|
.WillOnce(::testing::Return(std::optional<ConnectionResponse>(conn)));
|
|
|
|
auto result = mock_service->create_connection(body);
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_EQ(result->fiber_length, 5.0);
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateConnectionSamePort) {
|
|
ConnectionCreate body{"port1", "port1", 1.0, ""};
|
|
EXPECT_CALL(*mock_service, create_connection(body))
|
|
.WillOnce(::testing::Return(std::nullopt));
|
|
|
|
auto result = mock_service->create_connection(body);
|
|
EXPECT_FALSE(result.has_value());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testCreateConnectionPortNotFree) {
|
|
ConnectionCreate body{"port1", "port3", 2.0, ""};
|
|
EXPECT_CALL(*mock_service, create_connection(body))
|
|
.WillOnce(::testing::Return(std::nullopt));
|
|
|
|
auto result = mock_service->create_connection(body);
|
|
EXPECT_FALSE(result.has_value());
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testDeleteConnectionSuccess) {
|
|
EXPECT_CALL(*mock_service, delete_connection("conn1"))
|
|
.WillOnce(::testing::Return(true));
|
|
|
|
EXPECT_TRUE(mock_service->delete_connection("conn1"));
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testDeleteConnectionNotFound) {
|
|
EXPECT_CALL(*mock_service, delete_connection("bad_conn"))
|
|
.WillOnce(::testing::Return(false));
|
|
|
|
EXPECT_FALSE(mock_service->delete_connection("bad_conn"));
|
|
}
|
|
|
|
// ==================== 路径查询 API 测试 ====================
|
|
|
|
TEST_F(ODFServiceTest, testGetPortPathExists) {
|
|
std::string path_info = "port1 -> conn1 -> port2";
|
|
EXPECT_CALL(*mock_service, get_port_path("port1"))
|
|
.WillOnce(::testing::Return(std::optional<std::string>(path_info)));
|
|
|
|
auto result = mock_service->get_port_path("port1");
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_EQ(*result, path_info);
|
|
}
|
|
|
|
TEST_F(ODFServiceTest, testGetPortPathNotFound) {
|
|
EXPECT_CALL(*mock_service, get_port_path("unknown"))
|
|
.WillOnce(::testing::Return(std::nullopt));
|
|
|
|
auto result = mock_service->get_port_path("unknown");
|
|
EXPECT_FALSE(result.has_value());
|
|
}
|
|
|
|
// ==================== 健康检查 API 测试 ====================
|
|
|
|
TEST_F(ODFServiceTest, testHealthCheck) {
|
|
EXPECT_CALL(*mock_service, health_check())
|
|
.WillOnce(::testing::Return("{\"status\": \"ok\"}"));
|
|
|
|
auto result = mock_service->health_check();
|
|
EXPECT_NE(result.find("ok"), std::string::npos);
|
|
}
|