Activation: check compatiblity of uploaded software
Before activation, check if the PSU inventory's manufacturer and model
matches the uploaded software, to make sure the software is not updated
to a incompatible PSU.
The model check is mandatory, and if the PSU manufacturer is empty,
ignore the manufacturer check.
Tested: Upload a dummy tarball with incompatible model, verify the
activation fails;
Upload a dummy tarball with compatible model, verify the
activation succeeds with a dummy update service.
Also added unit tests for several cases:
* Update on a PSU that model is incompatible;
* Update on a PSU that the manufacture is incompatible;
* Update on a PSU that the menufacture is empty;
* Update on 4 PSUs that the second one is incompatible.
Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: Ia1b6a3fa6c98cdea1ea93c917c0938d4a60f0911
diff --git a/test/test_activation.cpp b/test/test_activation.cpp
index 891cdb6..0c40d97 100644
--- a/test/test_activation.cpp
+++ b/test/test_activation.cpp
@@ -11,16 +11,25 @@
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()
{
@@ -38,13 +47,18 @@
{
return activation->activationProgress->progress();
}
+ const auto& getPsuQueue()
+ {
+ return activation->psuQueue;
+ }
+
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 = "Some Ext Version";
+ std::string extVersion = "manufacturer=TestManu,model=TestModel";
std::string dBusPath = std::string(SOFTWARE_OBJPATH) + "/" + versionId;
Status status = Status::Ready;
AssociationList associations;
@@ -195,3 +209,97 @@
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);
+ 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);
+ 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);
+ 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);
+ 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());
+}
diff --git a/test/test_version.cpp b/test/test_version.cpp
index cba599f..8481952 100644
--- a/test/test_version.cpp
+++ b/test/test_version.cpp
@@ -65,3 +65,16 @@
EXPECT_EQ("psu-dummy-test.v0.1", version);
EXPECT_EQ("model=dummy_model,manufacture=dummy_manufacture", extVersion);
}
+
+TEST_F(TestVersion, getExtVersionInfo)
+{
+ std::string extVersion = "";
+ auto ret = Version::getExtVersionInfo(extVersion);
+ EXPECT_TRUE(ret.empty());
+
+ extVersion = "manufacturer=TestManu,model=TestModel";
+ ret = Version::getExtVersionInfo(extVersion);
+ EXPECT_EQ(2u, ret.size());
+ EXPECT_EQ("TestManu", ret["manufacturer"]);
+ EXPECT_EQ("TestModel", ret["model"]);
+}