blob: a402758793e286c7e285c768b4128c317a95c498 [file] [log] [blame]
#include "activation.hpp"
#include "mocked_association_interface.hpp"
#include "mocked_utils.hpp"
#include <sdbusplus/test/sdbus_mock.hpp>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace phosphor::software::updater;
using ::testing::_;
using ::testing::Return;
using ::testing::StrEq;
using std::experimental::any;
class TestActivation : public ::testing::Test
{
public:
using PropertyType = utils::UtilsInterface::PropertyType;
using Status = Activation::Status;
using RequestedStatus = Activation::RequestedActivations;
TestActivation() :
mockedUtils(
reinterpret_cast<const utils::MockedUtils&>(utils::getUtils()))
{
// By default make it compatible with the test software
ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MANUFACTURER)))
.WillByDefault(Return(any(PropertyType(std::string("TestManu")))));
ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MODEL)))
.WillByDefault(Return(any(PropertyType(std::string("TestModel")))));
}
~TestActivation()
{
utils::freeUtils();
}
void onUpdateDone()
{
activation->onUpdateDone();
}
void onUpdateFailed()
{
activation->onUpdateFailed();
}
int getProgress()
{
return activation->activationProgress->progress();
}
const auto& getPsuQueue()
{
return activation->psuQueue;
}
std::string getUpdateService(const std::string& psuInventoryPath)
{
return activation->getUpdateService(psuInventoryPath);
}
sdbusplus::SdBusMock sdbusMock;
sdbusplus::bus::bus mockedBus = sdbusplus::get_mocked_new(&sdbusMock);
const utils::MockedUtils& mockedUtils;
MockedAssociationInterface mockedAssociationInterface;
std::unique_ptr<Activation> activation;
std::string versionId = "abcdefgh";
std::string extVersion = "manufacturer=TestManu,model=TestModel";
std::string filePath = "";
std::string dBusPath = std::string(SOFTWARE_OBJPATH) + "/" + versionId;
Status status = Status::Ready;
AssociationList associations;
};
TEST_F(TestActivation, ctordtor)
{
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
}
TEST_F(TestActivation, ctorWithInvalidExtVersion)
{
extVersion = "invalid text";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
}
TEST_F(TestActivation, getUpdateService)
{
std::string psuInventoryPath = "/com/example/inventory/powersupply1";
std::string toCompare = "psu-update@-com-example-inventory-"
"powersupply1\\x20-tmp-images-12345678.service";
versionId = "12345678";
filePath = "/tmp/images/12345678";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
auto service = getUpdateService(psuInventoryPath);
EXPECT_EQ(toCompare, service);
}
TEST_F(TestActivation, doUpdateWhenNoPSU)
{
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({}))); // No PSU inventory
activation->requestedActivation(RequestedStatus::Active);
EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
.Times(0);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(0);
EXPECT_EQ(Status::Failed, activation->activation());
}
TEST_F(TestActivation, doUpdateOnePSUOK)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({psu0}))); // One PSU inventory
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
.Times(1);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(1);
onUpdateDone();
EXPECT_EQ(Status::Active, activation->activation());
}
TEST_F(TestActivation, doUpdateFourPSUsOK)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
constexpr auto psu1 = "/com/example/inventory/psu1";
constexpr auto psu2 = "/com/example/inventory/psu2";
constexpr auto psu3 = "/com/example/inventory/psu3";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(
std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(10, getProgress());
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(30, getProgress());
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(50, getProgress());
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(70, getProgress());
EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
.Times(1);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(1);
onUpdateDone();
EXPECT_EQ(Status::Active, activation->activation());
}
TEST_F(TestActivation, doUpdateFourPSUsFailonSecond)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
constexpr auto psu1 = "/com/example/inventory/psu1";
constexpr auto psu2 = "/com/example/inventory/psu2";
constexpr auto psu3 = "/com/example/inventory/psu3";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(
std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(10, getProgress());
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(30, getProgress());
EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
.Times(0);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(0);
onUpdateFailed();
EXPECT_EQ(Status::Failed, activation->activation());
}
TEST_F(TestActivation, doUpdateOnExceptionFromDbus)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({psu0}))); // One PSU inventory
ON_CALL(sdbusMock, sd_bus_call(_, _, _, _, nullptr))
.WillByDefault(Return(-1)); // Make sdbus call failure
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Failed, activation->activation());
}
TEST_F(TestActivation, doUpdateOnePSUModelNotCompatible)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
extVersion = "manufacturer=TestManu,model=DifferentModel";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(std::vector<std::string>({psu0})));
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Failed, activation->activation());
}
TEST_F(TestActivation, doUpdateOnePSUManufactureNotCompatible)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
extVersion = "manufacturer=DifferentManu,model=TestModel";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(std::vector<std::string>({psu0})));
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Failed, activation->activation());
}
TEST_F(TestActivation, doUpdateOnePSUSelfManufactureIsEmpty)
{
ON_CALL(mockedUtils, getPropertyImpl(_, _, _, _, StrEq(MANUFACTURER)))
.WillByDefault(Return(any(PropertyType(std::string("")))));
extVersion = "manufacturer=AnyManu,model=TestModel";
// Below is the same as doUpdateOnePSUOK case
constexpr auto psu0 = "/com/example/inventory/psu0";
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(
Return(std::vector<std::string>({psu0}))); // One PSU inventory
activation->requestedActivation(RequestedStatus::Active);
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
.Times(1);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(1);
onUpdateDone();
EXPECT_EQ(Status::Active, activation->activation());
}
TEST_F(TestActivation, doUpdateFourPSUsSecondPSUNotCompatible)
{
constexpr auto psu0 = "/com/example/inventory/psu0";
constexpr auto psu1 = "/com/example/inventory/psu1";
constexpr auto psu2 = "/com/example/inventory/psu2";
constexpr auto psu3 = "/com/example/inventory/psu3";
ON_CALL(mockedUtils, getPropertyImpl(_, _, StrEq(psu1), _, StrEq(MODEL)))
.WillByDefault(
Return(any(PropertyType(std::string("DifferentModel")))));
activation = std::make_unique<Activation>(
mockedBus, dBusPath, versionId, extVersion, status, associations,
&mockedAssociationInterface, filePath);
ON_CALL(mockedUtils, getPSUInventoryPath(_))
.WillByDefault(Return(
std::vector<std::string>({psu0, psu1, psu2, psu3}))); // 4 PSUs
activation->requestedActivation(RequestedStatus::Active);
const auto& psuQueue = getPsuQueue();
EXPECT_EQ(3u, psuQueue.size());
// Only 3 PSUs shall be updated, and psu1 shall be skipped
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(10, getProgress());
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(36, getProgress());
onUpdateDone();
EXPECT_EQ(Status::Activating, activation->activation());
EXPECT_EQ(62, getProgress());
EXPECT_CALL(mockedAssociationInterface, createActiveAssociation(dBusPath))
.Times(1);
EXPECT_CALL(mockedAssociationInterface, addFunctionalAssociation(dBusPath))
.Times(1);
onUpdateDone();
EXPECT_EQ(Status::Active, activation->activation());
}