blob: 0f857470ee3443c7c8db9a1685665df72a2270c8 [file] [log] [blame]
#include "app.hpp"
#include "async_resp.hpp"
#include "http_request.hpp"
#include "http_response.hpp"
#include "snapshot_fixture.hpp"
#include "storage.hpp"
#include "test/g3/mock_managed_store.hpp"
#include <boost/beast/core/string_type.hpp>
#include <boost/beast/http/message.hpp>
#include <nlohmann/json.hpp>
#include <sdbusplus/test/sdbus_mock.hpp>
#include <system_error>
#include <unordered_set>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace redfish
{
namespace
{
using ::managedStore::KeyType;
using ::managedStore::ManagedType;
using ::managedStore::
SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction;
using ::managedStore::
SimulateFailedAsyncPostDbusCallThreadSafeWithMsgAndEmptyValueAction;
using ::managedStore::SimulateFailedAsyncSetPropertyDbusCallAction;
using ::managedStore::SimulateSuccessfulAsyncSetPropertyDbusCallAction;
using ::managedStore::ValueType;
using ::testing::_;
using ::testing::An;
using ::testing::Contains;
using ::testing::NotNull;
class StorgeSnapshotFixture : public SnapshotFixture
{
protected:
dbus::utility::MapperGetSubTreeResponse subtree = {
{"/drive_0", {{"connection", {}}}},
{"/drive_1", {}},
};
std::string path = "/xyz/openbmc_project/inventory/Board/device_1";
std::string connection = "xyz.test";
};
TEST_F(StorgeSnapshotFixture, SetResetTypeOk)
{
EXPECT_CALL(*managedStore::GetManagedObjectStore(),
setProperty(_, _, "xyz.openbmc_project.State.Drive",
"RequestedDriveTransition",
std::string("PowerCycle"), _))
.Times(1)
.WillOnce(SimulateSuccessfulAsyncSetPropertyDbusCallAction::
SimulateSuccessfulAsyncSetPropertyDbusCall());
setResetType(share_async_resp_, "drive_0", "PowerCycle", subtree);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(StorgeSnapshotFixture, SetResetTypeFailed)
{
EXPECT_CALL(*managedStore::GetManagedObjectStore(),
setProperty(_, _, "xyz.openbmc_project.State.Drive",
"RequestedDriveTransition",
std::string("PowerCycle"), _))
.Times(1)
.WillOnce(SimulateFailedAsyncSetPropertyDbusCallAction::
SimulateFailedAsyncSetPropertyDbusCall());
setResetType(share_async_resp_, "drive_0", "PowerCycle", subtree);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(StorgeSnapshotFixture, SetResetTypeInvalidDriveId)
{
setResetType(share_async_resp_, "drive_2", "PowerCycle", subtree);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::not_found);
}
TEST_F(StorgeSnapshotFixture, SetResetTypeInvalidConnection)
{
setResetType(share_async_resp_, "drive_1", "PowerCycle", subtree);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(StorgeSnapshotFixture, DriveServiceLabelOnlyResponse)
{
auto response = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = response->res.jsonValue;
/* Mock the Drive object*/
std::vector<std::string> interfaces = {
storage_utils::driveInterface,
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
};
// Insert interfaces getObject call
KeyType locationTypeKey(ManagedType::kManagedMapperObject, path, {});
dbus::utility::MapperGetObject locationTypeValue{{connection, interfaces}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationTypeKey,
mockLocationType)
.ok());
// Insert service label
std::string serviceLabel = "X2";
KeyType key(ManagedType::kManagedProperty, connection,
sdbusplus::message::object_path(path),
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"LocationCode");
std::shared_ptr<ValueType> mockServiceLabel =
managedStore::MockManagedStoreTest::CreateValueType(serviceLabel);
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key, mockServiceLabel)
.ok());
/* Mock an empty Drive assocation */
KeyType getAssociatedSubTreeKey(
ManagedType::kManagedAssociatedSubtree, path + "/chassis",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.Board"});
dbus::utility::MapperGetSubTreeResponse subtree = {};
std::shared_ptr<ValueType> mockSubtree =
managedStore::MockManagedStoreTest::CreateValueType(std::move(subtree));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(getAssociatedSubTreeKey,
mockSubtree)
.ok());
addAllDriveInfo(response, "", connection, path, interfaces, "");
RunIoUntilDone();
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["ServiceLabel"],
serviceLabel);
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["LocationType"],
nullptr);
EXPECT_EQ(json["PhysicalLocation"]["PartLocationContext"],
"PlaceHolderAndShouldNotBeUsed");
EXPECT_EQ(json["PhysicalLocation"]["Oem"]["Google"]["Devpath"], "/phys");
}
TEST_F(StorgeSnapshotFixture, DriveServiceLabelAndTypeResponse)
{
auto response = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = response->res.jsonValue;
/* Mock the Drive object*/
std::vector<std::string> interfaces = {
storage_utils::driveInterface,
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"xyz.openbmc_project.Inventory.Connector.Embedded",
};
// Insert interfaces getObject call
KeyType locationTypeKey(ManagedType::kManagedMapperObject, path, {});
dbus::utility::MapperGetObject locationTypeValue{{connection, interfaces}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationTypeKey,
mockLocationType)
.ok());
std::string serviceLabel = "X2";
KeyType key(ManagedType::kManagedProperty, connection,
sdbusplus::message::object_path(path),
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"LocationCode");
std::shared_ptr<ValueType> mockServiceLabel =
managedStore::MockManagedStoreTest::CreateValueType(serviceLabel);
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key, mockServiceLabel)
.ok());
/* Mock an empty Drive assocation */
KeyType getAssociatedSubTreeKey(
ManagedType::kManagedAssociatedSubtree, path + "/chassis",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.Board"});
dbus::utility::MapperGetSubTreeResponse subtree = {};
std::shared_ptr<ValueType> mockSubtree =
managedStore::MockManagedStoreTest::CreateValueType(std::move(subtree));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(getAssociatedSubTreeKey,
mockSubtree)
.ok());
addAllDriveInfo(response, "", connection, path, interfaces, "");
RunIoUntilDone();
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["ServiceLabel"], "X2");
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["LocationType"],
"Embedded");
EXPECT_EQ(json["PhysicalLocation"]["PartLocationContext"],
"PlaceHolderAndShouldNotBeUsed");
EXPECT_EQ(json["PhysicalLocation"]["Oem"]["Google"]["Devpath"],
"/phys:device:X2");
}
/**
* @brief: Mock a parent object that containing the target object
* @param[in] objectPath the current object path
* @param[in] objectType the current object type presented as dbus
interface
* @param[in] parentConnection service name for the parent object
* @param[in] parentPath parent object path; return empty list on empty
string
* @param[in] parentType parent type present as dbus interace
* @param[in] serviceLabel parent service_label/location_code property;
return
* ec on dbus read when empty string
*/
void mockParent(const std::string& objectPath, const std::string& objectType,
const std::string& parentConnection,
const std::string& parentPath, const std::string& parentType,
const std::string& serviceLabel,
const std::string& locationType = "Slot")
{
// define the assocation tags
std::string forwardTag = "contained_by";
std::string backwardTag = "containing";
if (objectType == storage_utils::driveInterface &&
parentType == storage_utils::chassisInterface)
{
forwardTag = "chassis";
backwardTag = "drive";
}
else if (objectType == storage_utils::storageInterface &&
parentType == storage_utils::driveInterface)
{
forwardTag = "drive";
backwardTag = "storage";
}
else if (objectType == storage_utils::controllerInterface &&
parentType == storage_utils::storageInterface)
{
forwardTag = "storage";
backwardTag = "storage_controller";
}
else if (objectType == storage_utils::volumeInterface &&
parentType == storage_utils::storageInterface)
{
forwardTag = "contained";
backwardTag = "containing";
}
// insert assocation mock
KeyType getAssociatedSubTreeKey(
ManagedType::kManagedAssociatedSubtree,
(std::filesystem::path(objectPath) / forwardTag).string(),
"/xyz/openbmc_project/inventory", 0, {parentType});
dbus::utility::MapperGetSubTreeResponse subtree =
parentPath.empty()
? dbus::utility::MapperGetSubTreeResponse{}
: dbus::utility::MapperGetSubTreeResponse{
{parentPath,
{{parentConnection,
{parentType,
{"xyz.openbmc_project.Inventory.Decorator.LocationCode"}}}}},
};
std::shared_ptr<ValueType> mockSubtree =
managedStore::MockManagedStoreTest::CreateValueType(std::move(subtree));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(getAssociatedSubTreeKey,
mockSubtree)
.ok());
// insert service label mock
KeyType parenetLocationKey(
ManagedType::kManagedProperty, parentConnection,
sdbusplus::message::object_path(parentPath),
"xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode");
std::shared_ptr<ValueType> mockServiceLabel =
serviceLabel.empty()
? managedStore::MockManagedStoreTest::CreateErrorValueType(
serviceLabel,
boost::system::error_code(boost::asio::error::not_found))
: managedStore::MockManagedStoreTest::CreateValueType(serviceLabel);
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(parenetLocationKey,
mockServiceLabel)
.ok());
// insert location type mock
KeyType parenetLocationTypeKey(ManagedType::kManagedMapperObject,
parentPath, {});
dbus::utility::MapperGetObject parentLocationTypeValue{
{parentConnection,
{{"xyz.openbmc_project.Inventory.Decorator.LocationCode"},
std::string{"xyz.openbmc_project.Inventory.Connector."} +
locationType}}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(parentLocationTypeValue));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(parenetLocationTypeKey,
mockLocationType)
.ok());
}
TEST_F(StorgeSnapshotFixture, DriveLocationContextOnlyResponse)
{
auto response = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = response->res.jsonValue;
std::vector<std::string> interfaces = {
storage_utils::driveInterface,
};
// Insert interfaces getObject call
KeyType locationTypeKey(ManagedType::kManagedMapperObject, path, {});
dbus::utility::MapperGetObject locationTypeValue{{connection, interfaces}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationTypeKey,
mockLocationType)
.ok());
// Parent of Drive
mockParent(path, storage_utils::driveInterface, "test.chassis.0",
"/xyz/openbmc_project/inventory/Board/chassis_0",
storage_utils::chassisInterface, "C");
// Parent of Chasis0
mockParent("/xyz/openbmc_project/inventory/Board/chassis_0",
storage_utils::chassisInterface, "test.chassis.1",
"/xyz/openbmc_project/inventory/Board/chassis_1",
storage_utils::chassisInterface, "A");
// Parent of Chasis1
mockParent("/xyz/openbmc_project/inventory/Board/chassis_1",
storage_utils::chassisInterface, "test.chassis.2",
"/xyz/openbmc_project/inventory/Board/chassis_2",
storage_utils::chassisInterface, "B");
// Mock empty parents of Chassis2
mockParent("/xyz/openbmc_project/inventory/Board/chassis_2",
storage_utils::chassisInterface, "", "",
storage_utils::chassisInterface, "");
addAllDriveInfo(response, "", connection, path, interfaces, "");
RunIoUntilDone();
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["ServiceLabel"],
nullptr);
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["LocationType"],
nullptr);
EXPECT_EQ(json["PhysicalLocation"]["PartLocationContext"],
"PlaceHolderAndShouldNotBeUsed");
EXPECT_EQ(json["PhysicalLocation"]["Oem"]["Google"]["Devpath"],
"/phys/B/A/C");
}
TEST_F(StorgeSnapshotFixture, DriveAllLocationResponse)
{
auto response = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = response->res.jsonValue;
std::vector<std::string> interfaces = {
storage_utils::driveInterface,
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"xyz.openbmc_project.Inventory.Connector.Embedded",
};
// Insert interfaces getObject call
KeyType locationTypeKey(ManagedType::kManagedMapperObject, path, {});
dbus::utility::MapperGetObject locationTypeValue{{connection, interfaces}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationTypeKey,
mockLocationType)
.ok());
std::string serviceLabel = "X2";
KeyType key(ManagedType::kManagedProperty, connection,
sdbusplus::message::object_path(path),
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"LocationCode");
std::shared_ptr<ValueType> mockServiceLabel =
managedStore::MockManagedStoreTest::CreateValueType(serviceLabel);
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key, mockServiceLabel)
.ok());
// Parent of Drive
mockParent(path, storage_utils::driveInterface, "test.chassis.0",
"/xyz/openbmc_project/inventory/Board/chassis_0",
storage_utils::chassisInterface, "C");
// Parent of Chasis0
mockParent("/xyz/openbmc_project/inventory/Board/chassis_0",
storage_utils::chassisInterface, "test.chassis.1",
"/xyz/openbmc_project/inventory/Board/chassis_1",
storage_utils::chassisInterface, "A");
// Parent of Chasis1
mockParent("/xyz/openbmc_project/inventory/Board/chassis_1",
storage_utils::chassisInterface, "test.chassis.2",
"/xyz/openbmc_project/inventory/Board/chassis_2",
storage_utils::chassisInterface, "B");
// Mock empty parents of Chassis2
mockParent("/xyz/openbmc_project/inventory/Board/chassis_2",
storage_utils::chassisInterface, "", "",
storage_utils::chassisInterface, "");
addAllDriveInfo(response, "", connection, path, interfaces, "");
RunIoUntilDone();
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["ServiceLabel"], "X2");
EXPECT_EQ(json["PhysicalLocation"]["PartLocation"]["LocationType"],
"Embedded");
EXPECT_EQ(json["PhysicalLocation"]["PartLocationContext"],
"PlaceHolderAndShouldNotBeUsed");
EXPECT_EQ(json["PhysicalLocation"]["Oem"]["Google"]["Devpath"],
"/phys/B/A/C:device:X2");
}
TEST_F(StorgeSnapshotFixture, StorageControllerAllLocationResponse)
{
auto response = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = response->res.jsonValue;
/* Mock a physical controller with LocationCode/LocationType */
std::vector<std::string> interfaces = {
storage_utils::controllerInterface,
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"xyz.openbmc_project.Inventory.Connector.Embedded",
};
// Insert interfaces getObject call
KeyType locationTypeKey(ManagedType::kManagedMapperObject,
path + "/storage_controller_0", {});
dbus::utility::MapperGetObject locationTypeValue{{connection, interfaces}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationTypeKey,
mockLocationType)
.ok());
std::string serviceLabel = "X2";
KeyType key(ManagedType::kManagedProperty, connection,
sdbusplus::message::object_path(path) / "storage_controller_0",
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"LocationCode");
std::shared_ptr<ValueType> mockServiceLabel =
managedStore::MockManagedStoreTest::CreateValueType(serviceLabel);
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key, mockServiceLabel)
.ok());
// Parent of Storage Controller
mockParent(path + "/storage_controller_0",
storage_utils::controllerInterface, "test.storage.0",
path + "/storage_0", storage_utils::storageInterface, "Storage");
// Parent of Storage
mockParent(path + "/storage_0", storage_utils::storageInterface,
"test.drive.0", path + "/drive_0", storage_utils::driveInterface,
"Drive");
// Parent of Drive
mockParent(path + "/drive_0", storage_utils::driveInterface,
"test.chassis.0", path, storage_utils::chassisInterface, "C");
// Parent of Chasis0
mockParent(path, storage_utils::chassisInterface, "test.chassis.1",
"/xyz/openbmc_project/inventory/Board/chassis_1",
storage_utils::chassisInterface, "A");
// Parent of Chasis1
mockParent("/xyz/openbmc_project/inventory/Board/chassis_1",
storage_utils::chassisInterface, "test.chassis.2",
"/xyz/openbmc_project/inventory/Board/chassis_2",
storage_utils::chassisInterface, "B");
// Mock empty parents of Chassis2
mockParent("/xyz/openbmc_project/inventory/Board/chassis_2",
storage_utils::chassisInterface, "", "",
storage_utils::chassisInterface, "");
storage_utils::tryGetLocation(
response, connection, path + "/storage_controller_0",
storage_utils::controllerInterface, interfaces);
RunIoUntilDone();
EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "X2");
EXPECT_EQ(json["Location"]["PartLocation"]["LocationType"], "Embedded");
EXPECT_EQ(json["Location"]["PartLocationContext"],
"PlaceHolderAndShouldNotBeUsed");
// storage should not be part of the location info
EXPECT_EQ(json["Location"]["Oem"]["Google"]["Devpath"],
"/phys/B/A/C/Drive:device:X2");
// None-NVMe controller should have no logic tag
EXPECT_EQ(json["Location"]["Oem"]["Google"]["EmbeddedLocationContext"],
nullptr);
json.clear();
/* Mock a logical NVMe controller w/o LocationType */
interfaces = {storage_utils::controllerInterface,
"xyz.openbmc_project.Inventory.Decorator.LocationCode",
"xyz.openbmc_project.NVMe.MetricStore"};
// Insert interfaces getObject call
dbus::utility::MapperGetObject locationTypeValue2{{connection, interfaces}};
std::shared_ptr<ValueType> mockLocationType2 =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue2));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationTypeKey,
mockLocationType2)
.ok());
storage_utils::tryGetLocation(
response, connection, path + "/storage_controller_0",
storage_utils::controllerInterface, interfaces);
RunIoUntilDone();
EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "X2");
EXPECT_EQ(json["Location"]["PartLocation"]["LocationType"], nullptr);
EXPECT_EQ(json["Location"]["PartLocationContext"],
"PlaceHolderAndShouldNotBeUsed");
// storage should not be part of the devpath
EXPECT_EQ(json["Location"]["Oem"]["Google"]["Devpath"],
"/phys/B/A/C/Drive");
// NVMe controller should have logic tag
EXPECT_EQ(json["Location"]["Oem"]["Google"]["EmbeddedLocationContext"],
"controller:storage_controller_0");
}
void mockStorageObject(std::string storageName, std::string& storagePath)
{
storagePath = "/xyz/openbmc_project/inventory/system/board/ParentStorage/" +
storageName;
KeyType key(ManagedType::kManagedSubtree, "/xyz/openbmc_project/inventory",
0, {"xyz.openbmc_project.Inventory.Item.Storage"});
dbus::utility::MapperGetSubTreeResponse mockSubtreeResponse{
{storagePath,
{{"xyz.openbmc_project.NVMe",
std::vector<std::string>{
"xyz.openbmc_project.Nvme.Storage",
"xyz.openbmc_project.Inventory.Item.Storage"}}}}};
std::shared_ptr<ValueType> subtree =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(mockSubtreeResponse));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key, subtree)
.ok());
KeyType key2(ManagedType::kManagedAssociatedSubtreePaths,
storagePath + "/contained_by",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> system({}); // empty means system
ASSERT_TRUE(
managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(
key2, managedStore::MockManagedStoreTest::CreateValueType(
std::move(system)))
.ok());
}
void addVolumeToMockStorage(std::string storagePath, std::string volumeName,
std::string& volumePath,
bool includeMetricStore = true)
{
std::vector<std::string> volIfaces(
{"xyz.openbmc_project.Inventory.Item.Volume",
"xyz.openbmc_project.Nvme.Volume"});
if (includeMetricStore)
{
volIfaces.push_back("xyz.openbmc_project.NVMe.MetricStore");
}
volumePath = storagePath + "/volumes/" + volumeName;
KeyType getAssociatedSubTreeKey(
ManagedType::kManagedAssociatedSubtree, storagePath + "/containing",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.Volume"});
dbus::utility::MapperGetSubTreeResponse mockSubtreeResponse{
{volumePath, {{"xyz.openbmc_project.NVMe", volIfaces}}}};
std::shared_ptr<ValueType> subtree =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(mockSubtreeResponse));
ASSERT_TRUE(
managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(getAssociatedSubTreeKey, subtree)
.ok());
}
void mockItemVolumeData(std::string volumePath)
{
KeyType key2(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NVMe",
volumePath, "xyz.openbmc_project.Inventory.Item.Volume");
dbus::utility::DBusPropertiesMap getAllItemVolumeMap{
{std::make_pair("BlockSize", 4096UL),
std::make_pair("Size", 3221225472000ULL)}};
std::shared_ptr<ValueType> getAllItemVolume =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(getAllItemVolumeMap));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key2, getAllItemVolume)
.ok());
}
void mockNvmeVolumeData(std::string volumePath)
{
KeyType key3(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.NVMe",
volumePath, "xyz.openbmc_project.Nvme.Volume");
dbus::utility::DBusPropertiesMap getAllVolumeMap{
{std::make_pair("NamespaceId", 1U), std::make_pair("LBAFormat", 0UL)}};
std::shared_ptr<ValueType> getAllVolume =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(getAllVolumeMap));
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key3, getAllVolume)
.ok());
}
void mockAvoidLocationCheckForVolume(std::string volumePath)
{
// adding empty object to avoid location check
KeyType locationKey(ManagedType::kManagedMapperObject, volumePath, {});
dbus::utility::MapperGetObject locationTypeValue{{}};
std::shared_ptr<ValueType> mockLocationType =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(locationTypeValue));
ASSERT_TRUE(
managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(locationKey, mockLocationType)
.ok());
// create empty storage reverse association to avoid storage check
KeyType getAssociatedSubTreeKey(
ManagedType::kManagedAssociatedSubtree, volumePath + "/contained",
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.Storage"});
dbus::utility::MapperGetSubTreeResponse mockSubtreeResponse{};
std::shared_ptr<ValueType> subtree =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(mockSubtreeResponse));
ASSERT_TRUE(
managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(getAssociatedSubTreeKey, subtree)
.ok());
}
void mockMetricStore(std::string volumePath, bool failed = false)
{
KeyType key(ManagedType::kManagedProperty, "xyz.openbmc_project.NVMe",
volumePath, "xyz.openbmc_project.NVMe.MetricStore",
"MetricCollection");
if (failed)
{
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->evictMockObjectFromManagedStore(key)
.ok());
}
else
{
std::shared_ptr<ValueType> metricCollection =
managedStore::MockManagedStoreTest::CreateValueType<
dbus::utility::DbusVariantType>(std::move(
std::vector<std::string>({"FirstMetric", "SecondMetric"})));
ASSERT_TRUE(
managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(key, metricCollection)
.ok());
}
}
void checkGenericVolumeMockData(nlohmann::json& json)
{
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1");
EXPECT_EQ(json["@odata.type"], "#Volume.v1_9_0.Volume");
EXPECT_EQ(json["BlockSizeBytes"], 4096);
EXPECT_EQ(json["Capacity"]["Data"]["ProvisionedBytes"], 3221225472000);
EXPECT_EQ(json["Id"], "1");
EXPECT_EQ(json["NVMeNamespaceProperties"]["LBAFormat"]["LBADataSizeBytes"],
4096);
EXPECT_EQ(json["NVMeNamespaceProperties"]["LBAFormat"]["LBAFormatType"],
"LBAFormat0");
EXPECT_EQ(json["NVMeNamespaceProperties"]["NamespaceId"], "0x00000001");
EXPECT_EQ(json["Name"], "Namespace 1");
}
TEST_F(StorgeSnapshotFixture, StorageVolumeHandlerCheck)
{
std::string storageName = "storage_nvme";
std::string volumeName = "1";
std::string storagePath;
mockStorageObject(storageName, storagePath);
std::string volumePath;
addVolumeToMockStorage(storagePath, volumeName, volumePath);
mockItemVolumeData(volumePath);
mockNvmeVolumeData(volumePath);
mockMetricStore(volumePath);
// Skip location check due to it's complexity and
// since this test is targeting Metrics
mockAvoidLocationCheckForVolume(volumePath);
storageVolumeHandler(app_, CreateRequest(), share_async_resp_, "system",
storageName, volumeName);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
nlohmann::json& json = share_async_resp_->res.jsonValue;
checkGenericVolumeMockData(json);
EXPECT_EQ(
json["Oem"]["Google"]["FirstMetric"]["DataUri"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1/Oem/Google/Metrics/FirstMetric");
EXPECT_EQ(
json["Oem"]["Google"]["SecondMetric"]["DataUri"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1/Oem/Google/Metrics/SecondMetric");
}
TEST_F(StorgeSnapshotFixture, StorageVolumeHandlerCheckWithoutItemVolume)
{
std::string storageName = "storage_nvme";
std::string volumeName = "1";
std::string storagePath;
mockStorageObject(storageName, storagePath);
std::string volumePath;
addVolumeToMockStorage(storagePath, volumeName, volumePath);
mockNvmeVolumeData(volumePath);
mockMetricStore(volumePath);
// remove item volume from store
// previous testcases can affect this, hence removing
KeyType itemVolumeKey(ManagedType::kManagedPropertyMap,
"xyz.openbmc_project.NVMe", volumePath,
"xyz.openbmc_project.Inventory.Item.Volume");
ASSERT_TRUE(managedStore::GetManagedObjectStore()
->evictMockObjectFromManagedStore(itemVolumeKey)
.ok());
// Skip location check due to it's complexity and
// since this test is targeting Metrics
mockAvoidLocationCheckForVolume(volumePath);
storageVolumeHandler(app_, CreateRequest(), share_async_resp_, "system",
storageName, volumeName);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1");
EXPECT_EQ(json["@odata.type"], "#Volume.v1_9_0.Volume");
EXPECT_FALSE(json.contains("BlockSizeBytes"));
EXPECT_FALSE(json.contains("Capacity"));
EXPECT_FALSE(json.contains("NVMeNamespaceProperties"));
EXPECT_EQ(json["Id"], "1");
EXPECT_EQ(json["Name"], std::string("Volume ") + volumeName);
EXPECT_EQ(
json["Oem"]["Google"]["FirstMetric"]["DataUri"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1/Oem/Google/Metrics/FirstMetric");
EXPECT_EQ(
json["Oem"]["Google"]["SecondMetric"]["DataUri"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1/Oem/Google/Metrics/SecondMetric");
}
TEST_F(StorgeSnapshotFixture, StorageVolumeHandlerCheckWithoutMetricStore)
{
std::string storageName = "storage_nvme";
std::string volumeName = "1";
std::string storagePath;
mockStorageObject(storageName, storagePath);
std::string volumePath;
addVolumeToMockStorage(storagePath, volumeName, volumePath, false);
mockItemVolumeData(volumePath);
mockNvmeVolumeData(volumePath);
// Skip location check due to it's complexity and
// since this test is targeting Metrics
mockAvoidLocationCheckForVolume(volumePath);
storageVolumeHandler(app_, CreateRequest(), share_async_resp_, "system",
storageName, volumeName);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
nlohmann::json& json = share_async_resp_->res.jsonValue;
checkGenericVolumeMockData(json);
EXPECT_FALSE(json["Oem"]["Google"].contains("FirstMetric"));
}
TEST_F(StorgeSnapshotFixture, StorageVolumeHandlerCheckWithMetricStoreError)
{
std::string storageName = "storage_nvme";
std::string volumeName = "1";
std::string storagePath;
mockStorageObject(storageName, storagePath);
std::string volumePath;
addVolumeToMockStorage(storagePath, volumeName, volumePath);
mockItemVolumeData(volumePath);
mockNvmeVolumeData(volumePath);
mockMetricStore(volumePath, true);
// Skip location check due to it's complexity and
// since this test is targeting Metrics
mockAvoidLocationCheckForVolume(volumePath);
storageVolumeHandler(app_, CreateRequest(), share_async_resp_, "system",
storageName, volumeName);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
nlohmann::json& json = share_async_resp_->res.jsonValue;
checkGenericVolumeMockData(json);
EXPECT_FALSE(json["Oem"]["Google"].contains("FirstMetric"));
}
TEST_F(StorgeSnapshotFixture, StorageVolumeGetMetricError)
{
std::string storageName = "storage_nvme";
std::string volumeName = "1";
std::string storagePath;
mockStorageObject(storageName, storagePath);
std::string volumePath;
addVolumeToMockStorage(storagePath, volumeName, volumePath);
mockMetricStore(volumePath);
std::string metricId = "FirstMetric";
testing::StrictMock<sdbusplus::SdBusMock> sdbus;
EXPECT_CALL(sdbus,
sd_bus_message_new_method_call(testing::_, testing::_, nullptr,
nullptr, nullptr, nullptr))
.WillRepeatedly(testing::Return(0));
sd_bus_error err;
err.name = "xyz.openbmc_project.Common.Error.Unavailable";
EXPECT_CALL(sdbus, sd_bus_message_get_error(testing::_))
.WillRepeatedly(testing::Return(&err));
// intentionally failing
// want to test only properties not the metric data since there is no
// existing model to mock fd
sdbusplus::message_t msg =
sdbusplus::get_mocked_new(&sdbus).new_method_call(nullptr, nullptr,
nullptr, nullptr);
EXPECT_CALL(
*managedStore::GetManagedObjectStore(),
PostDbusCallToIoContextThreadSafe(
_,
An<absl::AnyInvocable<void(
const boost::system::error_code&, const sdbusplus::message_t&,
const sdbusplus::message::unix_fd&)>&&>(),
"xyz.openbmc_project.NVMe", volumePath,
"xyz.openbmc_project.NVMe.MetricStore", "GetMetric", metricId))
.Times(testing::AtMost(1))
.WillOnce(
SimulateFailedAsyncPostDbusCallThreadSafeWithMsgAndEmptyValueAction::
SimulateFailedAsyncPostDbusCallWithMsgAndEmptyValue(msg));
handleStorageVolumeMetricGet(share_async_resp_, "system", storageName,
volumeName, metricId);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(
json["@odata.id"],
"/redfish/v1/Systems/system/Storage/storage_nvme/Volumes/1/Oem/Google/Metrics/FirstMetric");
EXPECT_EQ(json["Name"], "FirstMetric");
}
} // namespace
} // namespace redfish