#include "MCTPEndpoint.hpp" #include "MCTPReactor.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include class MockMCTPDevice : public MCTPDevice { public: ~MockMCTPDevice() override = default; MOCK_METHOD(void, setup, (std::function& ep)> && added), (override)); MOCK_METHOD(void, remove, (), (override)); MOCK_METHOD(std::string, describe, (), (const, override)); }; class MockMCTPEndpoint : public MCTPEndpoint { public: ~MockMCTPEndpoint() override = default; MOCK_METHOD(int, network, (), (const, override)); MOCK_METHOD(uint8_t, eid, (), (const, override)); MOCK_METHOD(void, subscribe, (Event && degraded, Event&& available, Event&& removed), (override)); MOCK_METHOD(void, remove, (), (override)); MOCK_METHOD(std::string, describe, (), (const, override)); MOCK_METHOD(std::shared_ptr, device, (), (const, override)); }; class MockAssociationServer : public AssociationServer { public: ~MockAssociationServer() override = default; MOCK_METHOD(void, associate, (const std::string& path, const std::vector& associations), (override)); MOCK_METHOD(void, disassociate, (const std::string& path), (override)); }; class MCTPReactorFixture : public testing::Test { protected: void SetUp() override { reactor = std::make_shared(assoc); device = std::make_shared(); EXPECT_CALL(*device, describe()) .WillRepeatedly(testing::Return("mock device")); endpoint = std::make_shared(); EXPECT_CALL(*endpoint, device()) .WillRepeatedly(testing::Return(device)); EXPECT_CALL(*endpoint, describe()) .WillRepeatedly(testing::Return("mock endpoint")); EXPECT_CALL(*endpoint, eid()).WillRepeatedly(testing::Return(9)); EXPECT_CALL(*endpoint, network()).WillRepeatedly(testing::Return(1)); } void TearDown() override { // https://stackoverflow.com/a/10289205 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(endpoint.get())); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(device.get())); } MockAssociationServer assoc; std::shared_ptr reactor; std::shared_ptr device; std::shared_ptr endpoint; }; TEST_F(MCTPReactorFixture, manageNullDevice) { reactor->manageMCTPDevice("/test", {}); reactor->unmanageMCTPDevice("/test"); } TEST_F(MCTPReactorFixture, manageMockDeviceSetupFailure) { EXPECT_CALL(*device, remove()); EXPECT_CALL(*device, setup(testing::_)) .WillOnce(testing::InvokeArgument<0>( std::make_error_code(std::errc::permission_denied), endpoint)); reactor->manageMCTPDevice("/test", device); reactor->unmanageMCTPDevice("/test"); } TEST_F(MCTPReactorFixture, manageMockDevice) { std::function& ep)> removeHandler; std::vector requiredAssociation{ {"configured_by", "configures", "/test"}}; EXPECT_CALL(assoc, associate("/xyz/openbmc_project/mctp/1/9", requiredAssociation)); EXPECT_CALL(assoc, disassociate("/xyz/openbmc_project/mctp/1/9")); EXPECT_CALL(*endpoint, remove()).WillOnce(testing::Invoke([&]() { removeHandler(endpoint); })); EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_)) .WillOnce(testing::SaveArg<2>(&removeHandler)); EXPECT_CALL(*device, remove()).WillOnce(testing::Invoke([&]() { endpoint->remove(); })); EXPECT_CALL(*device, setup(testing::_)) .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint)); reactor->manageMCTPDevice("/test", device); reactor->unmanageMCTPDevice("/test"); } TEST_F(MCTPReactorFixture, manageMockDeviceDeferredSetup) { std::function& ep)> removeHandler; std::vector requiredAssociation{ {"configured_by", "configures", "/test"}}; EXPECT_CALL(assoc, associate("/xyz/openbmc_project/mctp/1/9", requiredAssociation)); EXPECT_CALL(assoc, disassociate("/xyz/openbmc_project/mctp/1/9")); EXPECT_CALL(*endpoint, remove()).WillOnce(testing::Invoke([&]() { removeHandler(endpoint); })); EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_)) .WillOnce(testing::SaveArg<2>(&removeHandler)); EXPECT_CALL(*device, remove()).WillOnce(testing::Invoke([&]() { endpoint->remove(); })); EXPECT_CALL(*device, setup(testing::_)) .WillOnce(testing::InvokeArgument<0>( std::make_error_code(std::errc::permission_denied), endpoint)) .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint)); reactor->manageMCTPDevice("/test", device); reactor->tick(); reactor->unmanageMCTPDevice("/test"); } TEST_F(MCTPReactorFixture, manageMockDeviceRemoved) { std::function& ep)> removeHandler; std::vector requiredAssociation{ {"configured_by", "configures", "/test"}}; EXPECT_CALL(assoc, associate("/xyz/openbmc_project/mctp/1/9", requiredAssociation)) .Times(2); EXPECT_CALL(assoc, disassociate("/xyz/openbmc_project/mctp/1/9")).Times(2); EXPECT_CALL(*endpoint, remove()).WillOnce(testing::Invoke([&]() { removeHandler(endpoint); })); EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_)) .Times(2) .WillRepeatedly(testing::SaveArg<2>(&removeHandler)); EXPECT_CALL(*device, remove()).WillOnce(testing::Invoke([&]() { endpoint->remove(); })); EXPECT_CALL(*device, setup(testing::_)) .Times(2) .WillRepeatedly( testing::InvokeArgument<0>(std::error_code(), endpoint)); reactor->manageMCTPDevice("/test", device); removeHandler(endpoint); reactor->tick(); reactor->unmanageMCTPDevice("/test"); } TEST(MCTPReactor, replaceConfiguration) { MockAssociationServer assoc{}; auto reactor = std::make_shared(assoc); std::function& ep)> removeHandler; std::vector requiredAssociation{ {"configured_by", "configures", "/test"}}; EXPECT_CALL(assoc, associate("/xyz/openbmc_project/mctp/1/9", requiredAssociation)) .Times(2); EXPECT_CALL(assoc, disassociate("/xyz/openbmc_project/mctp/1/9")).Times(2); auto endpoint = std::make_shared(); EXPECT_CALL(*endpoint, describe()) .WillRepeatedly(testing::Return("mock endpoint")); EXPECT_CALL(*endpoint, eid()).WillRepeatedly(testing::Return(9)); EXPECT_CALL(*endpoint, network()).WillRepeatedly(testing::Return(1)); EXPECT_CALL(*endpoint, remove()) .Times(2) .WillRepeatedly(testing::Invoke([&]() { removeHandler(endpoint); })); EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_)) .Times(2) .WillRepeatedly(testing::SaveArg<2>(&removeHandler)); auto initial = std::make_shared(); EXPECT_CALL(*initial, describe()) .WillRepeatedly(testing::Return("mock device: initial")); EXPECT_CALL(*initial, setup(testing::_)) .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint)); EXPECT_CALL(*initial, remove()).WillOnce(testing::Invoke([&]() { endpoint->remove(); })); auto replacement = std::make_shared(); EXPECT_CALL(*replacement, describe()) .WillRepeatedly(testing::Return("mock device: replacement")); EXPECT_CALL(*replacement, setup(testing::_)) .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint)); EXPECT_CALL(*replacement, remove()).WillOnce(testing::Invoke([&]() { endpoint->remove(); })); EXPECT_CALL(*endpoint, device()) .WillOnce(testing::Return(initial)) .WillOnce(testing::Return(initial)) .WillOnce(testing::Return(replacement)) .WillOnce(testing::Return(replacement)); reactor->manageMCTPDevice("/test", initial); reactor->manageMCTPDevice("/test", replacement); reactor->tick(); reactor->unmanageMCTPDevice("/test"); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(initial.get())); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(replacement.get())); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(endpoint.get())); }