RASCSI/cpp/test/protobuf_util_test.cpp
Uwe Seimet 7bbcf59c76
scsictl shall accept generic key/value pairs for options that take parameters (#1240) (#1274)
* scsictl accepts generic key/value pairs for options that take parameters
2023-10-31 09:02:28 +01:00

245 lines
6.6 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/protobuf_util.h"
#include "shared/piscsi_exceptions.h"
#include "generated/piscsi_interface.pb.h"
#include <filesystem>
using namespace piscsi_interface;
using namespace protobuf_util;
void TestSpecialDevice(const string& name)
{
PbDeviceDefinition device;
ParseParameters(device, name);
EXPECT_EQ(name, GetParam(device, "file"));
EXPECT_EQ("", GetParam(device, "interfaces"));
}
TEST(ProtobufUtil, GetSetParam)
{
// The implementation is a function template, testing one possible T is sufficient
PbCommand command;
SetParam(command, "key", "value");
EXPECT_EQ("value", GetParam(command, "key"));
EXPECT_EQ("", GetParam(command, "xyz"));
EXPECT_EQ("", GetParam(command, ""));
}
TEST(ProtobufUtil, ParseParameters)
{
PbDeviceDefinition device1;
ParseParameters(device1, "a=b:c=d:e");
EXPECT_EQ("b", GetParam(device1, "a"));
EXPECT_EQ("d", GetParam(device1, "c"));
EXPECT_EQ("", GetParam(device1, "e"));
// Old style parameter
PbDeviceDefinition device2;
ParseParameters(device2, "a");
EXPECT_EQ("a", GetParam(device2, "file"));
TestSpecialDevice("bridge");
TestSpecialDevice("daynaport");
TestSpecialDevice("printer");
TestSpecialDevice("services");
}
TEST(ProtobufUtil, SetCommandParams)
{
PbCommand command1;
SetCommandParams(command1, "file");
EXPECT_EQ("", GetParam(command1, "folder_pattern"));
EXPECT_EQ("file", GetParam(command1, "file_pattern"));
PbCommand command2;
SetCommandParams(command2, ":file");
EXPECT_EQ("", GetParam(command2, "folder_pattern"));
EXPECT_EQ("file", GetParam(command2, "file_pattern"));
PbCommand command3;
SetCommandParams(command3, "file:");
EXPECT_EQ("file", GetParam(command3, "file_pattern"));
EXPECT_EQ("", GetParam(command3, "folder_pattern"));
PbCommand command4;
SetCommandParams(command4, "folder:file");
EXPECT_EQ("folder", GetParam(command4, "folder_pattern"));
EXPECT_EQ("file", GetParam(command4, "file_pattern"));
PbCommand command5;
SetCommandParams(command5, "folder:file:");
EXPECT_EQ("folder", GetParam(command5, "folder_pattern"));
EXPECT_EQ("file", GetParam(command5, "file_pattern"));
PbCommand command6;
SetCommandParams(command6, "folder:file:operations");
EXPECT_EQ("folder", GetParam(command6, "folder_pattern"));
EXPECT_EQ("file", GetParam(command6, "file_pattern"));
EXPECT_EQ("operations", GetParam(command6, "operations"));
}
TEST(ProtobufUtil, SetFromGenericParams)
{
PbCommand command1;
EXPECT_TRUE(SetFromGenericParams(command1, "operations=mapping_info:folder_pattern=pattern").empty());
EXPECT_EQ("mapping_info", GetParam(command1, "operations"));
EXPECT_EQ("pattern", GetParam(command1, "folder_pattern"));
PbCommand command2;
EXPECT_FALSE(SetFromGenericParams(command2, "=mapping_info").empty());
PbCommand command3;
EXPECT_FALSE(SetFromGenericParams(command3, "=").empty());
}
TEST(ProtobufUtil, ListDevices)
{
vector<PbDevice> devices;
EXPECT_FALSE(ListDevices(devices).empty());
PbDevice device;
device.set_type(SCHD);
devices.push_back(device);
device.set_type(SCBR);
devices.push_back(device);
device.set_type(SCDP);
devices.push_back(device);
device.set_type(SCHS);
devices.push_back(device);
device.set_type(SCLP);
devices.push_back(device);
const string device_list = ListDevices(devices);
EXPECT_FALSE(device_list.empty());
EXPECT_NE(string::npos, device_list.find("X68000 HOST BRIDGE"));
EXPECT_NE(string::npos, device_list.find("DaynaPort SCSI/Link"));
EXPECT_NE(string::npos, device_list.find("Host Services"));
EXPECT_NE(string::npos, device_list.find("SCSI Printer"));
}
TEST(ProtobufUtil, SetProductData)
{
PbDeviceDefinition device;
SetProductData(device, "");
EXPECT_EQ("", device.vendor());
EXPECT_EQ("", device.product());
EXPECT_EQ("", device.revision());
SetProductData(device, "vendor");
EXPECT_EQ("vendor", device.vendor());
EXPECT_EQ("", device.product());
EXPECT_EQ("", device.revision());
SetProductData(device, "vendor:product");
EXPECT_EQ("vendor", device.vendor());
EXPECT_EQ("product", device.product());
EXPECT_EQ("", device.revision());
SetProductData(device, "vendor:product:revision");
EXPECT_EQ("vendor", device.vendor());
EXPECT_EQ("product", device.product());
EXPECT_EQ("revision", device.revision());
}
TEST(ProtobufUtil, SetIdAndLun)
{
PbDeviceDefinition device;
EXPECT_NE("", SetIdAndLun(device, ""));
EXPECT_EQ("", SetIdAndLun(device, "1"));
EXPECT_EQ(1, device.id());
EXPECT_EQ("", SetIdAndLun(device, "2:0"));
EXPECT_EQ(2, device.id());
EXPECT_EQ(0, device.unit());
}
TEST(ProtobufUtil, SerializeMessage)
{
PbResult result;
const int fd = open("/dev/null", O_WRONLY);
ASSERT_NE(-1, fd);
SerializeMessage(fd, result);
close(fd);
EXPECT_THROW(SerializeMessage(-1, result), io_exception) << "Writing a message must fail";
}
TEST(ProtobufUtil, DeserializeMessage)
{
PbResult result;
vector<byte> buf(1);
int fd = open("/dev/null", O_RDONLY);
ASSERT_NE(-1, fd);
EXPECT_THROW(DeserializeMessage(fd, result), io_exception) << "Reading the message header must fail";
close(fd);
auto [fd1, filename1] = OpenTempFile();
// Data size -1
buf = { byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff} };
EXPECT_EQ(buf.size(), write(fd1, buf.data(), buf.size()));
close(fd1);
fd1 = open(filename1.c_str(), O_RDONLY);
ASSERT_NE(-1, fd1);
EXPECT_THROW(DeserializeMessage(fd1, result), io_exception) << "Invalid header was not rejected";
remove(filename1);
auto [fd2, filename2] = OpenTempFile();
// Data size 2
buf = { byte{0x02}, byte{0x00}, byte{0x00}, byte{0x00} };
EXPECT_EQ(buf.size(), write(fd2, buf.data(), buf.size()));
close(fd2);
fd2 = open(filename2.c_str(), O_RDONLY);
EXPECT_NE(-1, fd2);
EXPECT_THROW(DeserializeMessage(fd2, result), io_exception) << "Invalid data were not rejected";
remove(filename2);
}
TEST(ProtobufUtil, SerializeDeserializeMessage)
{
PbResult result;
result.set_status(true);
auto [fd, filename] = OpenTempFile();
ASSERT_NE(-1, fd);
SerializeMessage(fd, result);
close(fd);
result.set_status(false);
fd = open(filename.c_str(), O_RDONLY);
ASSERT_NE(-1, fd);
DeserializeMessage(fd, result);
close(fd);
remove(filename);
EXPECT_TRUE(result.status());
}
TEST(ProtobufUtil, ReadBytes)
{
vector<byte> buf1(1);
vector<byte> buf2;
int fd = open("/dev/null", O_RDONLY);
ASSERT_NE(-1, fd);
EXPECT_EQ(0, ReadBytes(fd, buf1));
EXPECT_EQ(0, ReadBytes(fd, buf2));
close(fd);
fd = open("/dev/zero", O_RDONLY);
ASSERT_NE(-1, fd);
EXPECT_EQ(1, ReadBytes(fd, buf1));
EXPECT_EQ(0, ReadBytes(fd, buf2));
close(fd);
}