blob: 065f9b2723f79e54098cdccb05588962c569e790 [file]
#include "redfish-core/lib/nvme_features.hpp"
#include <cstdint>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/functional/any_invocable.h"
#include "boost/asio/post.hpp" // NOLINT
#include "http_request.hpp"
#include "http_response.hpp"
#include "dbus_utility.hpp"
#include "test/redfish-core/lib/snapshot_fixture.hpp"
#include <nlohmann/json_fwd.hpp>
#include "managed_store.hpp"
#include "managed_store_types.hpp"
#include "test/g3/mock_managed_store.hpp"
#include "test/g3/mock_managed_store_test.hpp"
#include "sdbusplus/message.hpp"
#include "sdbusplus/message/native_types.hpp"
namespace redfish {
namespace {
using ::dbus::utility::DBusInteracesMap;
using ::dbus::utility::DBusPropertiesMap;
using ::dbus::utility::DbusVariantType;
using ::dbus::utility::ManagedObjectType;
using ::dbus::utility::MapperGetSubTreePathsResponse;
using ::dbus::utility::MapperGetSubTreeResponse;
using ::managedStore::KeyType;
using ::managedStore::ManagedType;
using ::managedStore::ValueType;
using ::testing::Contains;
using FeatureCollectionType =
std::vector<std::tuple<std::string, std::string, std::string>>;
MapperGetSubTreeResponse CreateMockStorageSubTree() {
return MapperGetSubTreeResponse(
{{"/xyz/openbmc_project/inventory/system/storage/storage0",
{{"xyz.openbmc_project.StorageService",
{"xyz.openbmc_project.Inventory.Item.Storage"}}}}});
}
MapperGetSubTreeResponse CreateMockControllerSubTree() {
return MapperGetSubTreeResponse(
{{"/xyz/openbmc_project/inventory/system/storage/storage0/"
"storage_controller/controller0",
{{"xyz.openbmc_project.NVMe.FeatureStore",
{"xyz.openbmc_project.Inventory.Item.StorageController",
"xyz.openbmc_project.NVMe.FeatureStore"}}}}});
}
MapperGetSubTreePathsResponse CreateMockStorageForControllerPaths() {
return MapperGetSubTreePathsResponse(
{"/xyz/openbmc_project/inventory/system/storage/storage0"});
}
void InjectMocks(managedStore::MockSerializedManagedObjectStore* mockStore) {
KeyType storageKey(ManagedType::kManagedSubtree,
"/xyz/openbmc_project/inventory", 0,
{"xyz.openbmc_project.Inventory.Item.Storage"});
std::shared_ptr<ValueType> mockStorageSubTreeResponse =
managedStore::MockManagedStoreTest::CreateValueType(
CreateMockStorageSubTree());
EXPECT_TRUE(mockStore
->upsertMockObjectIntoManagedStore(storageKey,
mockStorageSubTreeResponse)
.ok());
KeyType controllerKey(
ManagedType::kManagedAssociatedSubtree,
sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/"
"storage/storage0/storage_controller"),
sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
{"xyz.openbmc_project.Inventory.Item.StorageController"});
std::shared_ptr<ValueType> mockControllerSubTreeResponse =
managedStore::MockManagedStoreTest::CreateValueType(
CreateMockControllerSubTree());
EXPECT_TRUE(mockStore
->upsertMockObjectIntoManagedStore(
controllerKey, mockControllerSubTreeResponse)
.ok());
KeyType storageForControllerKey(
ManagedType::kManagedAssociatedSubtreePaths,
sdbusplus::message::object_path(
"/xyz/openbmc_project/inventory/system/storage/storage0/"
"storage_controller/controller0/storage"),
sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
{"xyz.openbmc_project.Inventory.Item.Storage"});
std::shared_ptr<ValueType> mockStorageForControllerPathsResponse =
managedStore::MockManagedStoreTest::CreateValueType(
CreateMockStorageForControllerPaths());
EXPECT_TRUE(
mockStore
->upsertMockObjectIntoManagedStore(
storageForControllerKey, mockStorageForControllerPathsResponse)
.ok());
}
TEST_F(SnapshotFixture, GetNvmeFeaturesCollectionReturnsCorrectResponse) {
auto mockStoreRaw =
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore());
ASSERT_TRUE(mockStoreRaw != nullptr);
InjectMocks(mockStoreRaw);
FeatureCollectionType col = {{"feature1", "0x01", "class1"},
{"feature2", "0x02", "class2"}};
KeyType propKey(ManagedType::kManagedProperty,
"xyz.openbmc_project.NVMe.FeatureStore",
sdbusplus::message::object_path(
"/xyz/openbmc_project/inventory/system/storage/storage0/"
"storage_controller/controller0"),
"xyz.openbmc_project.NVMe.FeatureStore", "FeatureCollection");
auto mockPropResp = managedStore::MockManagedStoreTest::CreateValueType(col);
EXPECT_TRUE(
mockStoreRaw->upsertMockObjectIntoManagedStore(propKey, mockPropResp)
.ok());
crow::Request req = CreateRequest();
handleControllerNvmeFeaturesCollectionGet(
app_, req, share_async_resp_, "system", "storage0", "controller0");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/Systems/system/Storage/storage0/Controllers/"
"controller0/Oem/Google/Features");
EXPECT_EQ(json["@odata.type"],
"#GoogleNvmeFeatureCollection.GoogleNvmeFeatureCollection");
EXPECT_EQ(json["Name"], "NVMe Features Collection");
EXPECT_EQ(json["Members@odata.count"], 2);
EXPECT_THAT(json["Members"],
Contains(nlohmann::json(
{{"@odata.id",
"/redfish/v1/Systems/system/Storage/storage0/Controllers/"
"controller0/Oem/Google/Features/feature1"}})));
EXPECT_THAT(json["Members"],
Contains(nlohmann::json(
{{"@odata.id",
"/redfish/v1/Systems/system/Storage/storage0/Controllers/"
"controller0/Oem/Google/Features/feature2"}})));
}
TEST_F(SnapshotFixture, GetNvmeFeatureReturnsCorrectResponse) {
auto mockStoreRaw =
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore());
ASSERT_TRUE(mockStoreRaw != nullptr);
InjectMocks(mockStoreRaw);
FeatureCollectionType col = {{"feature1_select1", "0x01", "class1"}};
std::vector<std::pair<std::string, DbusVariantType>> props;
props.push_back({"ProtoLibraryVersion", std::string("1.2")});
props.push_back({"FeatureCollection", col});
KeyType allPropsKey(ManagedType::kManagedPropertyMap,
"xyz.openbmc_project.NVMe.FeatureStore",
sdbusplus::message::object_path(
"/xyz/openbmc_project/inventory/system/storage/"
"storage0/storage_controller/controller0"),
"xyz.openbmc_project.NVMe.FeatureStore");
auto mockAllPropsResp =
managedStore::MockManagedStoreTest::CreateValueType(props);
EXPECT_TRUE(
mockStoreRaw
->upsertMockObjectIntoManagedStore(allPropsKey, mockAllPropsResp)
.ok());
std::vector<uint8_t> payload = {1, 2, 3};
EXPECT_CALL(
*mockStoreRaw,
PostDbusCallToIoContextThreadSafe(
testing::_,
testing::An<absl::AnyInvocable<void(
const boost::system::error_code&, const sdbusplus::message_t&,
const std::vector<uint8_t>&)>&&>(),
testing::TypedEq<const std::string&>(
"xyz.openbmc_project.NVMe.FeatureStore"),
testing::TypedEq<const std::string&>(
"/xyz/openbmc_project/inventory/system/storage/storage0/"
"storage_controller/controller0"),
testing::TypedEq<const std::string&>(
"xyz.openbmc_project.NVMe.FeatureStore"),
testing::TypedEq<const std::string&>("GetFeature"),
testing::TypedEq<const std::string&>("feature1_select1")))
.WillOnce(
[payload](
const std::shared_ptr<boost::asio::io_context::strand>&,
absl::AnyInvocable<void(const boost::system::error_code&,
const sdbusplus::message_t&,
const std::vector<uint8_t>&)>&& callback,
const std::string&, const std::string&, const std::string&,
const std::string&, const std::string&) {
boost::asio::post(
managedStore::MockManagedStoreTest::GetStaticIoContext(),
[payload, callback = std::move(callback)]() mutable {
sdbusplus::message_t msg;
callback(boost::system::errc::make_error_code(
boost::system::errc::success),
msg, payload);
});
});
crow::Request req = CreateRequest();
handleControllerNvmeFeatureGet(app_, req, share_async_resp_, "system",
"storage0", "controller0", "feature1_select1");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/Systems/system/Storage/storage0/Controllers/"
"controller0/Oem/Google/Features/feature1_select1");
EXPECT_EQ(json["@odata.type"], "#GoogleNvmeFeature.v1_0_0.GoogleNvmeFeature");
EXPECT_EQ(json["Id"], "feature1_select1");
EXPECT_EQ(json["Name"], "feature1_select1");
EXPECT_EQ(json["FeatureId"], "0x01");
EXPECT_EQ(json["Select"], "select1");
EXPECT_EQ(json["DataProto"]["ClassName"], "class1");
EXPECT_EQ(json["DataProto"]["Revision"], "1.2");
}
TEST(ParseNvmeFeaturePropertiesTest, Success) {
FeatureCollectionType col = {{"feature1", "0x01", "class1"}};
std::vector<std::pair<std::string, DbusVariantType>> properties = {
{"ProtoLibraryVersion", std::string("1.0")}, {"FeatureCollection", col}};
std::string revision;
std::string featureIdStr;
std::string className;
crow::Response res;
bool result = parseNvmeFeatureProperties(properties, "feature1", revision,
featureIdStr, className, res);
EXPECT_TRUE(result);
EXPECT_EQ(revision, "1.0");
EXPECT_EQ(featureIdStr, "0x01");
EXPECT_EQ(className, "class1");
}
TEST(ParseNvmeFeaturePropertiesTest, MissingRevision) {
FeatureCollectionType col = {{"feature1", "0x01", "class1"}};
std::vector<std::pair<std::string, DbusVariantType>> properties = {
{"FeatureCollection", col}};
std::string revision;
std::string featureIdStr;
std::string className;
crow::Response res;
bool result = parseNvmeFeatureProperties(properties, "feature1", revision,
featureIdStr, className, res);
EXPECT_FALSE(result);
EXPECT_EQ(res.result(), boost::beast::http::status::internal_server_error);
}
TEST(ParseNvmeFeaturePropertiesTest, MissingFeatureCollection) {
std::vector<std::pair<std::string, DbusVariantType>> properties = {
{"ProtoLibraryVersion", std::string("1.0")}};
std::string revision;
std::string featureIdStr;
std::string className;
crow::Response res;
bool result = parseNvmeFeatureProperties(properties, "feature1", revision,
featureIdStr, className, res);
EXPECT_FALSE(result);
EXPECT_EQ(res.result(), boost::beast::http::status::internal_server_error);
}
TEST(ParseNvmeFeaturePropertiesTest, FeatureNotFound) {
FeatureCollectionType col = {{"feature2", "0x01", "class1"}};
std::vector<std::pair<std::string, DbusVariantType>> properties = {
{"ProtoLibraryVersion", std::string("1.0")}, {"FeatureCollection", col}};
std::string revision;
std::string featureIdStr;
std::string className;
crow::Response res;
bool result = parseNvmeFeatureProperties(properties, "feature1", revision,
featureIdStr, className, res);
EXPECT_FALSE(result);
EXPECT_EQ(res.result(), boost::beast::http::status::not_found);
}
} // namespace
} // namespace redfish