Issues 1179 and 1182 (#1232)

* Update logging

* Remove duplicate code

* Update unit tests

* Clean up includes

* Merge ProtobufSerializer into protobuf_util namespace

* Precompile regex

* Add const

* Add Split() convenience method, update log level/ID parsing

* Move log.h to legacy folder

* Elimininate gotos

* Fixes for gcc 13

* Update compiler flags

* Update default folder handling

* Use references instead of pointers

* Move code for better encapsulation

* Move code

* Remove unused method argument

* Move device logger

* Remove redundant to_string

* Rename for consistency

* Update handling of protobuf pointers

* Simplify protobuf usage

* Memory handling update

* Add hasher
This commit is contained in:
Uwe Seimet
2023-10-15 08:38:15 +02:00
committed by GitHub
parent c1f6f3ffea
commit 41bdcd4aed
161 changed files with 4767 additions and 5150 deletions
+27 -123
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -15,9 +15,7 @@ using namespace scsi_defs;
TEST(AbstractControllerTest, AllocateCmd)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
EXPECT_EQ(16, controller.GetCmd().size());
controller.AllocateCmd(1234);
@@ -26,9 +24,7 @@ TEST(AbstractControllerTest, AllocateCmd)
TEST(AbstractControllerTest, AllocateBuffer)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.AllocateBuffer(1);
EXPECT_LE(1, controller.GetBuffer().size());
@@ -39,25 +35,23 @@ TEST(AbstractControllerTest, AllocateBuffer)
TEST(AbstractControllerTest, Reset)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>(bus, 0);
auto device = make_shared<MockPrimaryDevice>(0);
controller->AddDevice(device);
controller->SetPhase(phase_t::status);
EXPECT_EQ(phase_t::status, controller->GetPhase());
EXPECT_CALL(*bus, Reset());
controller->Reset();
EXPECT_TRUE(controller->IsBusFree());
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
EXPECT_EQ(0, controller->GetLength());
}
TEST(AbstractControllerTest, Next)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.SetNext(0x1234);
EXPECT_EQ(0x1234, controller.GetNext());
@@ -67,9 +61,7 @@ TEST(AbstractControllerTest, Next)
TEST(AbstractControllerTest, Message)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.SetMessage(0x12);
EXPECT_EQ(0x12, controller.GetMessage());
@@ -77,9 +69,7 @@ TEST(AbstractControllerTest, Message)
TEST(AbstractControllerTest, ByteTransfer)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.SetByteTransfer(false);
EXPECT_FALSE(controller.IsByteTransfer());
@@ -89,9 +79,7 @@ TEST(AbstractControllerTest, ByteTransfer)
TEST(AbstractControllerTest, BytesToTransfer)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.SetBytesToTransfer(0x1234);
EXPECT_EQ(0x1234, controller.GetBytesToTransfer());
@@ -101,70 +89,17 @@ TEST(AbstractControllerTest, BytesToTransfer)
TEST(AbstractControllerTest, GetMaxLuns)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
EXPECT_EQ(32, controller.GetMaxLuns());
}
TEST(AbstractControllerTest, Status)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.SetStatus(status::RESERVATION_CONFLICT);
EXPECT_EQ(status::RESERVATION_CONFLICT, controller.GetStatus());
}
TEST(AbstractControllerTest, ProcessPhase)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
controller.SetPhase(phase_t::selection);
EXPECT_CALL(controller, Selection);
controller.ProcessPhase();
controller.SetPhase(phase_t::busfree);
EXPECT_CALL(controller, BusFree);
controller.ProcessPhase();
controller.SetPhase(phase_t::datain);
EXPECT_CALL(controller, DataIn);
controller.ProcessPhase();
controller.SetPhase(phase_t::dataout);
EXPECT_CALL(controller, DataOut);
controller.ProcessPhase();
controller.SetPhase(phase_t::command);
EXPECT_CALL(controller, Command);
controller.ProcessPhase();
controller.SetPhase(phase_t::status);
EXPECT_CALL(controller, Status);
controller.ProcessPhase();
controller.SetPhase(phase_t::msgin);
EXPECT_CALL(controller, MsgIn);
controller.ProcessPhase();
controller.SetPhase(phase_t::msgout);
EXPECT_CALL(controller, MsgOut);
controller.ProcessPhase();
controller.SetPhase(phase_t::reselection);
EXPECT_THAT([&] { controller.ProcessPhase(); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))));
controller.SetPhase(phase_t::reserved);
EXPECT_THAT([&] { controller.ProcessPhase(); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))));
controller.SetStatus(status::reservation_conflict);
EXPECT_EQ(status::reservation_conflict, controller.GetStatus());
}
TEST(AbstractControllerTest, DeviceLunLifeCycle)
@@ -172,9 +107,7 @@ TEST(AbstractControllerTest, DeviceLunLifeCycle)
const int ID = 1;
const int LUN = 4;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, ID);
auto controller = make_shared<NiceMock<MockAbstractController>>(ID);
auto device1 = make_shared<MockPrimaryDevice>(LUN);
auto device2 = make_shared<MockPrimaryDevice>(32);
@@ -190,33 +123,16 @@ TEST(AbstractControllerTest, DeviceLunLifeCycle)
EXPECT_FALSE(controller->HasDeviceForLun(0));
EXPECT_NE(nullptr, controller->GetDeviceForLun(LUN));
EXPECT_EQ(nullptr, controller->GetDeviceForLun(0));
EXPECT_TRUE(controller->RemoveDevice(device1));
EXPECT_TRUE(controller->RemoveDevice(*device1));
EXPECT_EQ(0, controller->GetLunCount());
EXPECT_FALSE(controller->RemoveDevice(device1));
}
TEST(AbstractControllerTest, ExtractInitiatorId)
{
const int ID = 1;
const int INITIATOR_ID = 7;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, ID);
EXPECT_EQ(INITIATOR_ID, controller.ExtractInitiatorId((1 << INITIATOR_ID) | ( 1 << ID)));
EXPECT_EQ(AbstractController::UNKNOWN_INITIATOR_ID, controller.ExtractInitiatorId(1 << ID));
EXPECT_FALSE(controller->RemoveDevice(*device1));
}
TEST(AbstractControllerTest, GetOpcode)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
auto& cmd = controller.GetCmd();
cmd[0] = static_cast<int>(scsi_command::eCmdInquiry);
controller.SetCmdByte(0, static_cast<int>(scsi_command::eCmdInquiry));
EXPECT_EQ(scsi_command::eCmdInquiry, controller.GetOpcode());
}
@@ -224,33 +140,25 @@ TEST(AbstractControllerTest, GetLun)
{
const int LUN = 3;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
auto& cmd = controller.GetCmd();
cmd[1] = LUN << 5;
controller.SetCmdByte(1, LUN << 5);
EXPECT_EQ(LUN, controller.GetLun());
}
TEST(AbstractControllerTest, Blocks)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.SetBlocks(1);
EXPECT_EQ(1, controller.GetBlocks());
EXPECT_TRUE(controller.HasBlocks());
controller.DecrementBlocks();
EXPECT_EQ(0, controller.GetBlocks());
EXPECT_FALSE(controller.HasBlocks());
}
TEST(AbstractControllerTest, Length)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
EXPECT_FALSE(controller.HasValidLength());
@@ -261,9 +169,7 @@ TEST(AbstractControllerTest, Length)
TEST(AbstractControllerTest, UpdateOffsetAndLength)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
EXPECT_FALSE(controller.HasValidLength());
@@ -273,9 +179,7 @@ TEST(AbstractControllerTest, UpdateOffsetAndLength)
TEST(AbstractControllerTest, Offset)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
MockAbstractController controller;
controller.ResetOffset();
EXPECT_EQ(0, controller.GetOffset());
+117 -20
View File
@@ -3,52 +3,149 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <gtest/gtest.h>
#include "test/test_shared.h"
#include "shared/piscsi_exceptions.h"
#include "shared/protobuf_util.h"
#include "piscsi/command_context.h"
#include <fcntl.h>
#include <unistd.h>
TEST(CommandContext, GetSerializer)
using namespace protobuf_util;
TEST(CommandContext, SetGetDefaultFolder)
{
CommandContext context("", -1);
PbCommand command;
CommandContext context(command, "folder1", "");
// There is nothing more that can be tested
context.GetSerializer();
EXPECT_EQ("folder1", context.GetDefaultFolder());
context.SetDefaultFolder("folder2");
EXPECT_EQ("folder2", context.GetDefaultFolder());
}
TEST(CommandContext, IsValid)
TEST(CommandContext, ReadCommand)
{
CommandContext context("", -1);
int fd = open(CreateTempFile(0).string().c_str(), O_RDONLY);
CommandContext context1(fd);
EXPECT_FALSE(context1.ReadCommand());
close(fd);
EXPECT_FALSE(context.IsValid());
// Invalid magic with wrong length
vector data = { byte{'1'}, byte{'2'}, byte{'3'} };
fd = open(CreateTempFileWithData(data).string().c_str(), O_RDONLY);
CommandContext context2(fd);
EXPECT_THROW(context2.ReadCommand(), io_exception);
close(fd);
context.SetFd(1);
EXPECT_TRUE(context.IsValid());
// Invalid magic with right length
data = { byte{'1'}, byte{'2'}, byte{'3'}, byte{'4'}, byte{'5'}, byte{'6'} };
fd = open(CreateTempFileWithData(data).string().c_str(), O_RDONLY);
CommandContext context3(fd);
EXPECT_THROW(context3.ReadCommand(), io_exception);
close(fd);
data = { byte{'R'}, byte{'A'}, byte{'S'}, byte{'C'}, byte{'S'}, byte{'I'}, byte{'1'} };
// Valid magic but invalid command
fd = open(CreateTempFileWithData(data).string().c_str(), O_RDONLY);
CommandContext context4(fd);
EXPECT_THROW(context4.ReadCommand(), io_exception);
close(fd);
data = { byte{'R'}, byte{'A'}, byte{'S'}, byte{'C'}, byte{'S'}, byte{'I'} };
// Valid magic but missing command
fd = open(CreateTempFileWithData(data).string().c_str(), O_RDONLY);
CommandContext context5(fd);
EXPECT_THROW(context5.ReadCommand(), io_exception);
close(fd);
const string filename = CreateTempFileWithData(data).string();
fd = open(filename.c_str(), O_RDWR | O_APPEND);
PbCommand command;
command.set_operation(PbOperation::SERVER_INFO);
SerializeMessage(fd, command);
close(fd);
fd = open(filename.c_str(), O_RDONLY);
CommandContext context6(fd);
EXPECT_TRUE(context6.ReadCommand());
close(fd);
EXPECT_EQ(PbOperation::SERVER_INFO, context6.GetCommand().operation());
}
TEST(CommandContext, Cleanup)
TEST(CommandContext, GetCommand)
{
CommandContext context("", 0);
PbCommand command;
command.set_operation(PbOperation::SERVER_INFO);
CommandContext context(command, "", "");
EXPECT_EQ(PbOperation::SERVER_INFO, context.GetCommand().operation());
}
EXPECT_EQ(0, context.GetFd());
context.Cleanup();
EXPECT_EQ(-1, context.GetFd());
TEST(CommandContext, WriteResult)
{
const string filename = CreateTempFile(0);
int fd = open(filename.c_str(), O_RDWR | O_APPEND);
PbResult result;
result.set_status(false);
result.set_error_code(PbErrorCode::UNAUTHORIZED);
CommandContext context(fd);
context.WriteResult(result);
close(fd);
EXPECT_FALSE(result.status());
fd = open(filename.c_str(), O_RDONLY);
result.set_status(true);
DeserializeMessage(fd, result);
close(fd);
EXPECT_FALSE(result.status());
EXPECT_EQ(PbErrorCode::UNAUTHORIZED, result.error_code());
}
TEST(CommandContext, WriteSuccessResult)
{
const string filename = CreateTempFile(0);
int fd = open(filename.c_str(), O_RDWR | O_APPEND);
PbResult result;
result.set_status(false);
CommandContext context(fd);
context.WriteSuccessResult(result);
close(fd);
EXPECT_TRUE(result.status());
}
TEST(CommandContext, ReturnLocalizedError)
{
CommandContext context("en_US", -1);
PbCommand command;
CommandContext context(command, "", "en_US");
EXPECT_FALSE(context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL));
}
TEST(CommandContext, ReturnStatus)
TEST(CommandContext, ReturnSuccessStatus)
{
CommandContext context("", -1);
PbCommand command;
EXPECT_TRUE(context.ReturnStatus(true, "status"));
EXPECT_FALSE(context.ReturnStatus(false, "status"));
CommandContext context1(command, "", "");
EXPECT_TRUE(context1.ReturnSuccessStatus());
const int fd = open("/dev/null", O_RDWR);
CommandContext context2(fd);
EXPECT_TRUE(context2.ReturnSuccessStatus());
close(fd);
}
TEST(CommandContext, ReturnErrorStatus)
{
PbCommand command;
CommandContext context1(command, "", "");
EXPECT_FALSE(context1.ReturnErrorStatus("error"));
const int fd = open("/dev/null", O_RDWR);
CommandContext context2(fd);
EXPECT_FALSE(context2.ReturnErrorStatus("error"));
close(fd);
}
+45 -24
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -13,54 +13,75 @@
TEST(ControllerManagerTest, LifeCycle)
{
const int ID = 4;
const int ID1 = 4;
const int ID2 = 5;
const int LUN1 = 0;
const int LUN2 = 3;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(SCHS, -1, "");
EXPECT_FALSE(controller_manager->AttachToScsiController(ID, device));
EXPECT_FALSE(controller_manager.AttachToController(*bus, ID1, device));
device = device_factory.CreateDevice(SCHS, LUN1, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device));
auto controller = controller_manager->FindController(ID);
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID1, device));
EXPECT_TRUE(controller_manager.HasController(ID1));
auto controller = controller_manager.FindController(ID1);
EXPECT_NE(nullptr, controller);
EXPECT_EQ(1, controller->GetLunCount());
EXPECT_NE(nullptr, controller_manager->IdentifyController(1 << ID));
EXPECT_EQ(nullptr, controller_manager->IdentifyController(0));
EXPECT_EQ(nullptr, controller_manager->FindController(0));
EXPECT_NE(nullptr, controller_manager->GetDeviceByIdAndLun(ID, LUN1));
EXPECT_EQ(nullptr, controller_manager->GetDeviceByIdAndLun(0, 0));
EXPECT_FALSE(controller_manager.HasController(0));
EXPECT_EQ(nullptr, controller_manager.FindController(0));
EXPECT_TRUE(controller_manager.HasDeviceForIdAndLun(ID1, LUN1));
EXPECT_NE(nullptr, controller_manager.GetDeviceForIdAndLun(ID1, LUN1));
EXPECT_FALSE(controller_manager.HasDeviceForIdAndLun(0, 0));
EXPECT_EQ(nullptr, controller_manager.GetDeviceForIdAndLun(0, 0));
device = device_factory.CreateDevice(SCHS, LUN2, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device));
controller = controller_manager->FindController(ID);
EXPECT_TRUE(controller_manager->DeleteController(controller));
EXPECT_EQ(nullptr, controller_manager->FindController(ID));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID1, device));
EXPECT_TRUE(controller_manager.HasController(ID1));
controller = controller_manager.FindController(ID1);
EXPECT_NE(nullptr, controller_manager.FindController(ID1));
EXPECT_TRUE(controller_manager.DeleteController(*controller));
EXPECT_EQ(nullptr, controller_manager.FindController(ID1));
controller_manager->DeleteAllControllers();
EXPECT_EQ(nullptr, controller_manager->FindController(ID));
EXPECT_EQ(nullptr, controller_manager->GetDeviceByIdAndLun(ID, LUN1));
auto disk = make_shared<MockDisk>();
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID2, disk));
EXPECT_CALL(*disk, FlushCache);
controller_manager.DeleteAllControllers();
EXPECT_FALSE(controller_manager.HasController(ID1));
EXPECT_EQ(nullptr, controller_manager.FindController(ID1));
EXPECT_EQ(nullptr, controller_manager.GetDeviceForIdAndLun(ID1, LUN1));
EXPECT_FALSE(controller_manager.HasDeviceForIdAndLun(ID1, LUN1));
EXPECT_FALSE(controller_manager.HasController(ID2));
EXPECT_EQ(nullptr, controller_manager.FindController(ID2));
EXPECT_EQ(nullptr, controller_manager.GetDeviceForIdAndLun(ID2, LUN1));
EXPECT_FALSE(controller_manager.HasDeviceForIdAndLun(ID2, LUN1));
}
TEST(ControllerManagerTest, AttachToScsiController)
TEST(ControllerManagerTest, AttachToController)
{
const int ID = 4;
const int LUN1 = 3;
const int LUN2 = 0;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
DeviceFactory device_factory;
auto device1 = device_factory.CreateDevice(SCHS, LUN1, "");
EXPECT_FALSE(controller_manager->AttachToScsiController(ID, device1)) << "LUN 0 is missing";
EXPECT_FALSE(controller_manager.AttachToController(*bus, ID, device1)) << "LUN 0 is missing";
auto device2 = device_factory.CreateDevice(SCLP, LUN2, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device2));
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device1));
EXPECT_FALSE(controller_manager->AttachToScsiController(ID, device1));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device2));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device1));
EXPECT_FALSE(controller_manager.AttachToController(*bus, ID, device1));
}
TEST(ControllerManager, ProcessOnController)
{
ControllerManager controller_manager;
EXPECT_EQ(AbstractController::piscsi_shutdown_mode::NONE, controller_manager.ProcessOnController(0));
}
+9 -8
View File
@@ -3,11 +3,12 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include <net/ethernet.h>
#include "devices/ctapdriver.h"
TEST(CTapDriverTest, Crc32)
@@ -15,27 +16,27 @@ TEST(CTapDriverTest, Crc32)
array<uint8_t, ETH_FRAME_LEN> buf;
buf.fill(0x00);
EXPECT_EQ(0xe3d887bb, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0xe3d887bb, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
buf.fill(0xff);
EXPECT_EQ(0x814765f4, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0x814765f4, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
buf.fill(0x10);
EXPECT_EQ(0xb7288Cd3, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0xb7288Cd3, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
buf.fill(0x7f);
EXPECT_EQ(0x4b543477, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0x4b543477, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
buf.fill(0x80);
EXPECT_EQ(0x29cbd638, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0x29cbd638, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
for (size_t i = 0; i < buf.size(); i++) {
buf[i] = (uint8_t)i;
}
EXPECT_EQ(0xe7870705, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0xe7870705, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
for (size_t i = buf.size() - 1; i > 0; i--) {
buf[i] = (uint8_t)i;
}
EXPECT_EQ(0xe7870705, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
EXPECT_EQ(0xe7870705, CTapDriver::Crc32(span(buf.data(), ETH_FRAME_LEN)));
}
+18 -19
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -42,44 +42,43 @@ TEST(DeviceFactoryTest, GetTypeForFile)
TEST(DeviceFactoryTest, GetSectorSizes)
{
DeviceFactory device_factory;
unordered_set<uint32_t> sector_sizes;
sector_sizes = device_factory.GetSectorSizes(SCHD);
unordered_set<uint32_t> sector_sizes = device_factory.GetSectorSizes(SCHD);
EXPECT_EQ(4, sector_sizes.size());
EXPECT_TRUE(sector_sizes.find(512) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(1024) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(4096) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.contains(512));
EXPECT_TRUE(sector_sizes.contains(1024));
EXPECT_TRUE(sector_sizes.contains(2048));
EXPECT_TRUE(sector_sizes.contains(4096));
sector_sizes = device_factory.GetSectorSizes(SCRM);
EXPECT_EQ(4, sector_sizes.size());
EXPECT_TRUE(sector_sizes.find(512) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(1024) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(4096) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.contains(512));
EXPECT_TRUE(sector_sizes.contains(1024));
EXPECT_TRUE(sector_sizes.contains(2048));
EXPECT_TRUE(sector_sizes.contains(4096));
sector_sizes = device_factory.GetSectorSizes(SCMO);
EXPECT_EQ(4, sector_sizes.size());
EXPECT_TRUE(sector_sizes.find(512) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(1024) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(4096) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.contains(512));
EXPECT_TRUE(sector_sizes.contains(1024));
EXPECT_TRUE(sector_sizes.contains(2048));
EXPECT_TRUE(sector_sizes.contains(4096));
sector_sizes = device_factory.GetSectorSizes(SCCD);
EXPECT_EQ(2, sector_sizes.size());
EXPECT_TRUE(sector_sizes.find(512) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end());
EXPECT_TRUE(sector_sizes.contains(512));
EXPECT_TRUE(sector_sizes.contains(2048));
}
TEST(DeviceFactoryTest, GetExtensionMapping)
{
DeviceFactory device_factory;
unordered_map<string, PbDeviceType> mapping = device_factory.GetExtensionMapping();
auto mapping = device_factory.GetExtensionMapping();
EXPECT_EQ(10, mapping.size());
EXPECT_EQ(SCHD, mapping["hd1"]);
EXPECT_EQ(SCHD, mapping["hds"]);
@@ -97,7 +96,7 @@ TEST(DeviceFactoryTest, GetDefaultParams)
{
DeviceFactory device_factory;
unordered_map<string, string> params = device_factory.GetDefaultParams(SCHD);
param_map params = device_factory.GetDefaultParams(SCHD);
EXPECT_TRUE(params.empty());
params = device_factory.GetDefaultParams(SCRM);
+19 -12
View File
@@ -3,12 +3,11 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "devices/device.h"
TEST(DeviceTest, Properties)
@@ -118,28 +117,36 @@ TEST(DeviceTest, Properties)
TEST(DeviceTest, GetTypeString)
{
MockDevice schd(SCHD);
EXPECT_STREQ("SCHD", schd.GetTypeString());
EXPECT_EQ("SCHD", schd.GetTypeString());
MockDevice scrm(SCRM);
EXPECT_STREQ("SCRM", scrm.GetTypeString());
EXPECT_EQ("SCRM", scrm.GetTypeString());
MockDevice scmo(SCMO);
EXPECT_STREQ("SCMO", scmo.GetTypeString());
EXPECT_EQ("SCMO", scmo.GetTypeString());
MockDevice sccd(SCCD);
EXPECT_STREQ("SCCD", sccd.GetTypeString());
EXPECT_EQ("SCCD", sccd.GetTypeString());
MockDevice schs(SCHS);
EXPECT_STREQ("SCHS", schs.GetTypeString());
EXPECT_EQ("SCHS", schs.GetTypeString());
MockDevice scbr(SCBR);
EXPECT_STREQ("SCBR", scbr.GetTypeString());
EXPECT_EQ("SCBR", scbr.GetTypeString());
MockDevice scdp(SCDP);
EXPECT_STREQ("SCDP", scdp.GetTypeString());
EXPECT_EQ("SCDP", scdp.GetTypeString());
MockDevice sclp(SCLP);
EXPECT_STREQ("SCLP", sclp.GetTypeString());
EXPECT_EQ("SCLP", sclp.GetTypeString());
}
TEST(DeviceTest, GetIdentifier)
{
MockDevice device(1);
EXPECT_CALL(device, GetId());
EXPECT_EQ("UNDEFINED 0:1", device.GetIdentifier());
}
TEST(DeviceTest, Vendor)
@@ -188,7 +195,7 @@ TEST(DeviceTest, GetPaddedName)
TEST(DeviceTest, Params)
{
MockDevice device(0);
unordered_map<string, string> params;
param_map params;
params["key"] = "value";
EXPECT_EQ("", device.GetParam("key"));
@@ -196,7 +203,7 @@ TEST(DeviceTest, Params)
device.SetParams(params);
EXPECT_EQ("", device.GetParam("key"));
unordered_map<string, string> default_params;
param_map default_params;
default_params["key"] = "value";
device.SetDefaultParams(default_params);
EXPECT_EQ("", device.GetParam("key"));
+273 -409
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -9,7 +9,7 @@
#include "hal/gpiobus_raspberry.h"
#include "mocks.h"
#include "stdlib.h"
#include <cstdlib>
#include "test/test_shared.h"
class SetableGpiobusRaspberry : public GPIOBUS_Raspberry
@@ -23,9 +23,9 @@ class SetableGpiobusRaspberry : public GPIOBUS_Raspberry
{
// Level is inverted logic
if (!value) {
*level |= (1 << pin);
*level = *level | (1 << pin);
} else {
*level &= ~(1 << pin);
*level = *level & ~(1 << pin);
}
}
SetableGpiobusRaspberry()
@@ -65,7 +65,7 @@ TEST(GpiobusRaspberry, GetDtRanges)
EXPECT_EQ(0x20000000, GPIOBUS_Raspberry::bcm_host_get_peripheral_address());
DeleteTempFile("/proc/device-tree/soc/ranges");
CleanupAllTempFiles();
CleanUpAllTempFiles();
}
TEST(GpiobusRaspberry, GetDat)
+44 -60
View File
@@ -9,7 +9,6 @@
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "controllers/controller_manager.h"
#include "devices/host_services.h"
using namespace std;
@@ -22,82 +21,70 @@ void HostServices_SetUpModePages(map<int, vector<byte>>& pages)
TEST(HostServicesTest, TestUnitReady)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto services = CreateDevice(SCHS, *controller);
auto [controller, services] = CreateDevice(SCHS);
EXPECT_CALL(*controller, Status());
services->Dispatch(scsi_command::eCmdTestUnitReady);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(HostServicesTest, Inquiry)
{
TestInquiry(SCHS, device_type::PROCESSOR, scsi_level::SPC_3, "PiSCSI Host Services ", 0x1f, false);
TestInquiry::Inquiry(SCHS, device_type::processor, scsi_level::spc_3, "PiSCSI Host Services ", 0x1f, false);
}
TEST(HostServicesTest, StartStopUnit)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto services = CreateDevice(SCHS, *controller);
auto& cmd = controller->GetCmd();
auto [controller, services] = CreateDevice(SCHS);
// Required by the bullseye clang++ compiler
auto s = services;
// STOP
EXPECT_CALL(*controller, ScheduleShutdown(AbstractController::piscsi_shutdown_mode::STOP_PISCSI));
EXPECT_CALL(*controller, Status());
services->Dispatch(scsi_command::eCmdStartStop);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
// LOAD
cmd[4] = 0x02;
EXPECT_CALL(*controller, ScheduleShutdown(AbstractController::piscsi_shutdown_mode::STOP_PI));
controller->SetCmdByte(4, 0x02);
EXPECT_CALL(*controller, Status());
services->Dispatch(scsi_command::eCmdStartStop);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
// UNLOAD
cmd[4] = 0x03;
EXPECT_CALL(*controller, ScheduleShutdown(AbstractController::piscsi_shutdown_mode::RESTART_PI));
controller->SetCmdByte(4, 0x03);
EXPECT_CALL(*controller, Status());
services->Dispatch(scsi_command::eCmdStartStop);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
// START
cmd[4] = 0x01;
EXPECT_THAT([&] { services->Dispatch(scsi_command::eCmdStartStop); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))));
controller->SetCmdByte(4, 0x01);
EXPECT_THAT([&] { s->Dispatch(scsi_command::eCmdStartStop); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))));
}
TEST(HostServicesTest, ModeSense6)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto services = CreateDevice(SCHS, *controller);
const unordered_map<string, string> params;
services->Init(params);
auto [controller, services] = CreateDevice(SCHS);
// Required by the bullseye clang++ compiler
auto s = services;
auto& cmd = controller->GetCmd();
EXPECT_TRUE(services->Init({}));
EXPECT_THAT([&] { services->Dispatch(scsi_command::eCmdModeSense6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
EXPECT_THAT([&] { s->Dispatch(scsi_command::eCmdModeSense6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Unsupported mode page was returned";
cmd[2] = 0x20;
EXPECT_THAT([&] { services->Dispatch(scsi_command::eCmdModeSense6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(2, 0x20);
EXPECT_THAT([&] { s->Dispatch(scsi_command::eCmdModeSense6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Block descriptors are not supported";
cmd[1] = 0x08;
controller->SetCmdByte(1, 0x08);
// ALLOCATION LENGTH
cmd[4] = 255;
controller->SetCmdByte(4, 255);
EXPECT_CALL(*controller, DataIn());
services->Dispatch(scsi_command::eCmdModeSense6);
vector<uint8_t>& buffer = controller->GetBuffer();
@@ -111,7 +98,7 @@ TEST(HostServicesTest, ModeSense6)
EXPECT_NE(0x00, buffer[10]);
// ALLOCATION LENGTH
cmd[4] = 2;
controller->SetCmdByte(4, 2);
EXPECT_CALL(*controller, DataIn());
services->Dispatch(scsi_command::eCmdModeSense6);
buffer = controller->GetBuffer();
@@ -120,29 +107,26 @@ TEST(HostServicesTest, ModeSense6)
TEST(HostServicesTest, ModeSense10)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto services = CreateDevice(SCHS, *controller);
const unordered_map<string, string> params;
services->Init(params);
auto [controller, services] = CreateDevice(SCHS);
// Required by the bullseye clang++ compiler
auto s = services;
EXPECT_TRUE(services->Init({}));
auto& cmd = controller->GetCmd();
EXPECT_THAT([&] { services->Dispatch(scsi_command::eCmdModeSense10); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
EXPECT_THAT([&] { s->Dispatch(scsi_command::eCmdModeSense10); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Unsupported mode page was returned";
cmd[2] = 0x20;
EXPECT_THAT([&] { services->Dispatch(scsi_command::eCmdModeSense10); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(2, 0x20);
EXPECT_THAT([&] { s->Dispatch(scsi_command::eCmdModeSense10); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Block descriptors are not supported";
cmd[1] = 0x08;
controller->SetCmdByte(1, 0x08);
// ALLOCATION LENGTH
cmd[8] = 255;
controller->SetCmdByte(8, 255);
EXPECT_CALL(*controller, DataIn());
services->Dispatch(scsi_command::eCmdModeSense10);
vector<uint8_t>& buffer = controller->GetBuffer();
@@ -156,7 +140,7 @@ TEST(HostServicesTest, ModeSense10)
EXPECT_NE(0x00, buffer[14]);
// ALLOCATION LENGTH
cmd[8] = 2;
controller->SetCmdByte(8, 2);
EXPECT_CALL(*controller, DataIn());
services->Dispatch(scsi_command::eCmdModeSense10);
buffer = controller->GetBuffer();
+6 -4
View File
@@ -13,11 +13,13 @@
#include <filesystem>
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#ifdef __linux__
#include <sys/epoll.h>
#endif
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
@@ -61,4 +63,4 @@ FILE *__wrap_fopen(const char *__restrict __filename, const char *__restrict __m
#endif
}
} // end extern "C"
} // end extern "C"
+35 -26
View File
@@ -81,10 +81,11 @@ public:
class MockPhaseHandler : public PhaseHandler
{
FRIEND_TEST(PhaseHandlerTest, Phases);
FRIEND_TEST(PhaseHandlerTest, ProcessPhase);
public:
MOCK_METHOD(phase_t, Process, (int), (override));
MOCK_METHOD(bool, Process, (int), (override));
MOCK_METHOD(void, Status, (), ());
MOCK_METHOD(void, DataIn, (), ());
MOCK_METHOD(void, DataOut, (), ());
@@ -97,15 +98,16 @@ public:
using PhaseHandler::PhaseHandler;
};
inline static const auto mock_bus = make_shared<MockBus>();
class MockAbstractController : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
{
friend class TestInquiry;
friend shared_ptr<PrimaryDevice> CreateDevice(piscsi_interface::PbDeviceType, AbstractController&, int);
friend void TestInquiry(piscsi_interface::PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level,
scsi_defs::scsi_level, const std::string&, int, bool);
FRIEND_TEST(AbstractControllerTest, AllocateCmd);
FRIEND_TEST(AbstractControllerTest, Reset);
FRIEND_TEST(AbstractControllerTest, ProcessPhase);
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
FRIEND_TEST(AbstractControllerTest, ExtractInitiatorId);
FRIEND_TEST(AbstractControllerTest, GetOpcode);
@@ -148,10 +150,26 @@ class MockAbstractController : public AbstractController //NOSONAR Having many f
FRIEND_TEST(DiskTest, PreventAllowMediumRemoval);
FRIEND_TEST(DiskTest, SynchronizeCache);
FRIEND_TEST(DiskTest, ReadDefectData);
FRIEND_TEST(DiskTest, StartStopUnit);
FRIEND_TEST(DiskTest, ModeSense6);
FRIEND_TEST(DiskTest, ModeSense10);
FRIEND_TEST(ScsiDaynaportTest, Read);
FRIEND_TEST(ScsiDaynaportTest, Write);
FRIEND_TEST(ScsiDaynaportTest, Read6);
FRIEND_TEST(ScsiDaynaportTest, Write6);
FRIEND_TEST(ScsiDaynaportTest, TestRetrieveStats);
FRIEND_TEST(ScsiDaynaportTest, SetInterfaceMode);
FRIEND_TEST(ScsiDaynaportTest, SetMcastAddr);
FRIEND_TEST(ScsiDaynaportTest, EnableInterface);
FRIEND_TEST(HostServicesTest, StartStopUnit);
FRIEND_TEST(HostServicesTest, ModeSense6);
FRIEND_TEST(HostServicesTest, ModeSense10);
FRIEND_TEST(HostServicesTest, SetUpModePages);
FRIEND_TEST(ScsiPrinterTest, Print);
public:
MOCK_METHOD(phase_t, Process, (int), (override));
MOCK_METHOD(bool, Process, (int), (override));
MOCK_METHOD(int, GetEffectiveLun, (), (const override));
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
MOCK_METHOD(int, GetInitiatorId, (), (const override));
@@ -163,10 +181,12 @@ public:
MOCK_METHOD(void, Command, (), ());
MOCK_METHOD(void, MsgIn, (), ());
MOCK_METHOD(void, MsgOut, (), ());
MOCK_METHOD(void, ScheduleShutdown, (piscsi_shutdown_mode), (override));
explicit MockAbstractController(shared_ptr<ControllerManager> controller_manager, int target_id)
: AbstractController(controller_manager, target_id, 32) {
MockAbstractController() : AbstractController(*mock_bus, 0, 32) {}
explicit MockAbstractController(int target_id) : AbstractController(*mock_bus, target_id, 32) {
AllocateBuffer(512);
}
MockAbstractController(shared_ptr<BUS> bus, int target_id) : AbstractController(*bus, target_id, 32) {
AllocateBuffer(512);
}
~MockAbstractController() override = default;
@@ -193,10 +213,8 @@ public:
MOCK_METHOD(void, Execute, (), ());
using ScsiController::ScsiController;
MockScsiController(shared_ptr<ControllerManager> controller_manager, int target_id)
: ScsiController(controller_manager, target_id) {}
explicit MockScsiController(shared_ptr<ControllerManager> controller_manager)
: ScsiController(controller_manager, 0) {}
MockScsiController(shared_ptr<BUS> bus, int target_id) : ScsiController(*bus, target_id) {}
explicit MockScsiController(shared_ptr<BUS> bus) : ScsiController(*bus, 0) {}
~MockScsiController() override = default;
};
@@ -233,6 +251,7 @@ class MockPrimaryDevice : public PrimaryDevice
public:
MOCK_METHOD(vector<uint8_t>, InquiryInternal, (), (const));
MOCK_METHOD(void, FlushCache, (), ());
explicit MockPrimaryDevice(int lun) : PrimaryDevice(UNDEFINED, lun) {}
~MockPrimaryDevice() override = default;
@@ -247,8 +266,8 @@ class MockModePageDevice : public ModePageDevice
public:
MOCK_METHOD(vector<uint8_t>, InquiryInternal, (), (const));
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<uint8_t>&), (const override));
MOCK_METHOD(int, ModeSense10, (const vector<int>&, vector<uint8_t>&), (const override));
MOCK_METHOD(int, ModeSense6, (span<const int>, vector<uint8_t>&), (const override));
MOCK_METHOD(int, ModeSense10, (span<const int>, vector<uint8_t>&), (const override));
MockModePageDevice() : ModePageDevice(UNDEFINED, 0) {}
~MockModePageDevice() override = default;
@@ -290,8 +309,8 @@ public:
MOCK_METHOD(vector<uint8_t>, InquiryInternal, (), (const));
MOCK_METHOD(void, Open, (), (override));
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<uint8_t>&), (const override));
MOCK_METHOD(int, ModeSense10, (const vector<int>&, vector<uint8_t>&), (const override));
MOCK_METHOD(int, ModeSense6, (span<const int>, vector<uint8_t>&), (const override));
MOCK_METHOD(int, ModeSense10, (span<const int>, vector<uint8_t>&), (const override));
MOCK_METHOD(void, SetUpModePages, ((map<int, vector<byte>>&), int, bool), (const override));
MockStorageDevice() : StorageDevice(UNDEFINED, 0) {}
@@ -391,16 +410,6 @@ class MockHostServices : public HostServices
using HostServices::HostServices;
};
class MockCommandContext : public CommandContext
{
public:
MockCommandContext() {
SetFd(open("/dev/null", O_WRONLY));
}
~MockCommandContext() = default;
};
class MockPiscsiExecutor : public PiscsiExecutor
{
public:
+25 -41
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -33,8 +33,8 @@ TEST(ModePageDeviceTest, AddModePages)
// Page 0
cdb[2] = 0x00;
EXPECT_THAT([&] { device.AddModePages(cdb, buf, 0, 12, 255); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Data were returned for non-existing mode page 0";
// All pages, non changeable
@@ -42,8 +42,8 @@ TEST(ModePageDeviceTest, AddModePages)
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, 0, 255));
EXPECT_EQ(3, device.AddModePages(cdb, buf, 0, 3, 255));
EXPECT_THAT([&] { device.AddModePages(cdb, buf, 0, 12, -1); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Maximum size was ignored";
// All pages, changeable
@@ -51,8 +51,8 @@ TEST(ModePageDeviceTest, AddModePages)
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, 0, 255));
EXPECT_EQ(3, device.AddModePages(cdb, buf, 0, 3, 255));
EXPECT_THAT([&] { device.AddModePages(cdb, buf, 0, 12, -1); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Maximum size was ignored";
}
@@ -80,12 +80,9 @@ TEST(ModePageDeviceTest, AddVendorPage)
TEST(ModePageDeviceTest, ModeSense6)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>(0);
auto device = make_shared<NiceMock<MockModePageDevice>>();
const unordered_map<string, string> params;
device->Init(params);
EXPECT_TRUE(device->Init({}));
controller->AddDevice(device);
@@ -95,12 +92,9 @@ TEST(ModePageDeviceTest, ModeSense6)
TEST(ModePageDeviceTest, ModeSense10)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>(0);
auto device = make_shared<NiceMock<MockModePageDevice>>();
const unordered_map<string, string> params;
device->Init(params);
EXPECT_TRUE(device->Init({}));
controller->AddDevice(device);
@@ -115,57 +109,47 @@ TEST(ModePageDeviceTest, ModeSelect)
vector<uint8_t> buf;
EXPECT_THAT([&] { device.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 0); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_COMMAND_OPERATION_CODE))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_command_operation_code))))
<< "Unexpected MODE SELECT(6) default implementation";
EXPECT_THAT([&] { device.ModeSelect(scsi_command::eCmdModeSelect10, cmd, buf, 0); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_COMMAND_OPERATION_CODE))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_command_operation_code))))
<< "Unexpected MODE SELECT(10) default implementation";
}
TEST(ModePageDeviceTest, ModeSelect6)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>(0);
auto device = make_shared<MockModePageDevice>();
const unordered_map<string, string> params;
device->Init(params);
EXPECT_TRUE(device->Init({}));
controller->AddDevice(device);
auto& cmd = controller->GetCmd();
EXPECT_CALL(*controller, DataOut());
device->Dispatch(scsi_command::eCmdModeSelect6);
cmd[1] = 0x01;
controller->SetCmdByte(1, 0x01);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdModeSelect6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Saving parameters is not supported by base class";
}
TEST(ModePageDeviceTest, ModeSelect10)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>(0);
auto device = make_shared<MockModePageDevice>();
const unordered_map<string, string> params;
device->Init(params);
EXPECT_TRUE(device->Init({}));
controller->AddDevice(device);
auto& cmd = controller->GetCmd();
EXPECT_CALL(*controller, DataOut());
device->Dispatch(scsi_command::eCmdModeSelect10);
cmd[1] = 0x01;
controller->SetCmdByte(1, 0x01);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdModeSelect10); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Saving parameters is not supported for by base class";
}
+33
View File
@@ -0,0 +1,33 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <gtest/gtest.h>
#include <netdb.h>
#include <netinet/in.h>
#include "shared/network_util.h"
using namespace network_util;
TEST(NetworkUtilTest, IsInterfaceUp)
{
EXPECT_FALSE(IsInterfaceUp("foo_bar"));
}
TEST(NetworkUtilTest, GetNetworkInterfaces)
{
EXPECT_FALSE(GetNetworkInterfaces().empty());
}
TEST(NetworkUtilTest, ResolveHostName)
{
sockaddr_in server_addr = {};
EXPECT_FALSE(ResolveHostName("foo.foobar", &server_addr));
EXPECT_TRUE(ResolveHostName("127.0.0.1", &server_addr));
}
+48 -1
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -94,3 +94,50 @@ TEST(PhaseHandlerTest, Phases)
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
}
TEST(PhaseHandlerTest, ProcessPhase)
{
MockPhaseHandler handler;
handler.SetPhase(phase_t::selection);
EXPECT_CALL(handler, Selection);
handler.ProcessPhase();
handler.SetPhase(phase_t::busfree);
EXPECT_CALL(handler, BusFree);
handler.ProcessPhase();
handler.SetPhase(phase_t::datain);
EXPECT_CALL(handler, DataIn);
handler.ProcessPhase();
handler.SetPhase(phase_t::dataout);
EXPECT_CALL(handler, DataOut);
handler.ProcessPhase();
handler.SetPhase(phase_t::command);
EXPECT_CALL(handler, Command);
handler.ProcessPhase();
handler.SetPhase(phase_t::status);
EXPECT_CALL(handler, Status);
handler.ProcessPhase();
handler.SetPhase(phase_t::msgin);
EXPECT_CALL(handler, MsgIn);
handler.ProcessPhase();
handler.SetPhase(phase_t::msgout);
EXPECT_CALL(handler, MsgOut);
handler.ProcessPhase();
handler.SetPhase(phase_t::reselection);
EXPECT_THAT([&] { handler.ProcessPhase(); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::aborted_command),
Property(&scsi_exception::get_asc, asc::no_additional_sense_information))));
handler.SetPhase(phase_t::reserved);
EXPECT_THAT([&] { handler.ProcessPhase(); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::aborted_command),
Property(&scsi_exception::get_asc, asc::no_additional_sense_information))));
}
+7 -7
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -36,18 +36,18 @@ TEST(PiscsiExceptionsTest, FileNotFoundException)
TEST(PiscsiExceptionsTest, ScsiErrorException)
{
try {
throw scsi_exception(sense_key::UNIT_ATTENTION);
throw scsi_exception(sense_key::unit_attention);
}
catch(const scsi_exception& e) {
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
EXPECT_EQ(sense_key::unit_attention, e.get_sense_key());
EXPECT_EQ(asc::no_additional_sense_information, e.get_asc());
}
try {
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE);
throw scsi_exception(sense_key::illegal_request, asc::lba_out_of_range);
}
catch(const scsi_exception& e) {
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
EXPECT_EQ(sense_key::illegal_request, e.get_sense_key());
EXPECT_EQ(asc::lba_out_of_range, e.get_asc());
}
}
+239 -235
View File
@@ -3,11 +3,10 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "spdlog/spdlog.h"
#include "mocks.h"
#include "shared/protobuf_util.h"
#include "shared/piscsi_exceptions.h"
@@ -24,224 +23,194 @@ using namespace filesystem;
using namespace piscsi_interface;
using namespace protobuf_util;
const extern bool enable_logging;
// This test fixture is required in order to reset the log level changed by the log level tests
class PiscsiExecutorTest : public Test
{
void TearDown() override {
spdlog::set_level(enable_logging ? spdlog::level::trace : spdlog::level::off);
}
};
TEST_F(PiscsiExecutorTest, ProcessDeviceCmd)
TEST(PiscsiExecutorTest, ProcessDeviceCmd)
{
const int ID = 3;
const int LUN = 0;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, ID);
ControllerManager controller_manager;
MockAbstractController controller(bus, ID);
PiscsiImage piscsi_image;
auto executor = make_shared<MockPiscsiExecutor>(piscsi_image, *controller_manager);
auto executor = make_shared<MockPiscsiExecutor>(piscsi_image, *bus, controller_manager);
PbDeviceDefinition definition;
PbCommand command;
MockCommandContext context;
CommandContext context(command, "", "");
definition.set_id(8);
definition.set_unit(32);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Invalid ID and LUN must fail";
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, true)) << "Invalid ID and LUN must fail";
definition.set_unit(LUN);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Invalid ID must fail";
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, true)) << "Invalid ID must fail";
definition.set_id(ID);
definition.set_unit(32);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Invalid LUN must fail";
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, true)) << "Invalid LUN must fail";
definition.set_unit(LUN);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Unknown operation must fail";
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, true)) << "Unknown operation must fail";
command.set_operation(ATTACH);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Operation for unknown device type must fail";
CommandContext context_attach(command, "", "");
EXPECT_FALSE(executor->ProcessDeviceCmd(context_attach, definition, true)) << "Operation for unknown device type must fail";
auto device1 = make_shared<MockPrimaryDevice>(LUN);
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device1));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device1));
definition.set_type(SCHS);
command.set_operation(INSERT);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Operation unsupported by device must fail";
controller_manager->DeleteAllControllers();
CommandContext context_insert1(command, "", "");
EXPECT_FALSE(executor->ProcessDeviceCmd(context_insert1, definition, true)) << "Operation unsupported by device must fail";
controller_manager.DeleteAllControllers();
definition.set_type(SCRM);
auto device2 = make_shared<MockSCSIHD_NEC>(LUN);
device2->SetRemovable(true);
device2->SetProtectable(true);
device2->SetReady(true);
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device2));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device2));
command.set_operation(ATTACH);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "ID and LUN already exist";
EXPECT_FALSE(executor->ProcessDeviceCmd(context_attach, definition, true)) << "ID and LUN already exist";
command.set_operation(START);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
CommandContext context_start(command, "", "");
EXPECT_TRUE(executor->ProcessDeviceCmd(context_start, definition, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context_start, definition, false));
command.set_operation(PROTECT);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
CommandContext context_protect(command, "", "");
EXPECT_TRUE(executor->ProcessDeviceCmd(context_protect, definition, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context_protect, definition, false));
command.set_operation(UNPROTECT);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
CommandContext context_unprotect(command, "", "");
EXPECT_TRUE(executor->ProcessDeviceCmd(context_unprotect, definition, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context_unprotect, definition, false));
command.set_operation(STOP);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
CommandContext context_stop(command, "", "");
EXPECT_TRUE(executor->ProcessDeviceCmd(context_stop, definition, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context_stop, definition, false));
command.set_operation(EJECT);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
CommandContext context_eject(command, "", "");
EXPECT_TRUE(executor->ProcessDeviceCmd(context_eject, definition, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context_eject, definition, false));
command.set_operation(INSERT);
SetParam(definition, "file", "filename");
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true)) << "Non-existing file";
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, false)) << "Non-existing file";
CommandContext context_insert2(command, "", "");
EXPECT_FALSE(executor->ProcessDeviceCmd(context_insert2, definition, true)) << "Non-existing file";
EXPECT_FALSE(executor->ProcessDeviceCmd(context_insert2, definition, false)) << "Non-existing file";
command.set_operation(DETACH);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device2));
command.set_operation(CHECK_AUTHENTICATION);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
command.set_operation(NO_OPERATION);
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context, definition, command, false));
// The operations below are not related to a device
command.set_operation(DETACH_ALL);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(RESERVE_IDS);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(CREATE_IMAGE);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(DELETE_IMAGE);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(RENAME_IMAGE);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(COPY_IMAGE);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(PROTECT_IMAGE);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
command.set_operation(UNPROTECT_IMAGE);
EXPECT_FALSE(executor->ProcessDeviceCmd(context, definition, command, true));
CommandContext context_detach(command, "", "");
EXPECT_TRUE(executor->ProcessDeviceCmd(context_detach, definition, true));
EXPECT_TRUE(executor->ProcessDeviceCmd(context_detach, definition, false));
}
TEST_F(PiscsiExecutorTest, ProcessCmd)
TEST(PiscsiExecutorTest, ProcessCmd)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
ControllerManager controller_manager;
MockAbstractController controller(bus, 0);
PiscsiImage piscsi_image;
auto executor = make_shared<MockPiscsiExecutor>(piscsi_image, *controller_manager);
PbCommand command1;
PbCommand command2;
MockCommandContext context;
auto executor = make_shared<MockPiscsiExecutor>(piscsi_image, *bus, controller_manager);
command1.set_operation(DETACH_ALL);
EXPECT_TRUE(executor->ProcessCmd(context, command1));
PbCommand command_detach_all;
command_detach_all.set_operation(DETACH_ALL);
CommandContext context_detach_all(command_detach_all, "", "");
EXPECT_TRUE(executor->ProcessCmd(context_detach_all));
command1.set_operation(RESERVE_IDS);
SetParam(command1, "ids", "2,3");
EXPECT_TRUE(executor->ProcessCmd(context, command1));
PbCommand command_reserve_ids1;
command_reserve_ids1.set_operation(RESERVE_IDS);
SetParam(command_reserve_ids1, "ids", "2,3");
CommandContext context_reserve_ids1(command_reserve_ids1, "", "");
EXPECT_TRUE(executor->ProcessCmd(context_reserve_ids1));
const unordered_set<int> ids = executor->GetReservedIds();
EXPECT_EQ(2, ids.size());
EXPECT_NE(ids.end(), ids.find(2));
EXPECT_NE(ids.end(), ids.find(3));
command2.set_operation(RESERVE_IDS);
EXPECT_TRUE(executor->ProcessCmd(context, command2));
EXPECT_TRUE(ids.contains(2));
EXPECT_TRUE(ids.contains(3));
PbCommand command_reserve_ids2;
command_reserve_ids2.set_operation(RESERVE_IDS);
CommandContext context_reserve_ids2(command_reserve_ids2, "", "");
EXPECT_TRUE(executor->ProcessCmd(context_reserve_ids2));
EXPECT_TRUE(executor->GetReservedIds().empty());
SetParam(command2, "ids", "-1");
EXPECT_FALSE(executor->ProcessCmd(context, command2));
PbCommand command_reserve_ids3;
command_reserve_ids3.set_operation(RESERVE_IDS);
SetParam(command_reserve_ids3, "ids", "-1");
CommandContext context_reserve_ids3(command_reserve_ids3, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_reserve_ids3));
EXPECT_TRUE(executor->GetReservedIds().empty());
command1.set_operation(NO_OPERATION);
EXPECT_TRUE(executor->ProcessCmd(context, command1));
PbCommand command_no_operation;
command_no_operation.set_operation(NO_OPERATION);
CommandContext context_no_operation(command_no_operation, "", "");
EXPECT_TRUE(executor->ProcessCmd(context_no_operation));
command1.set_operation(ATTACH);
auto device = command1.add_devices();
device->set_type(SCHS);
device->set_id(-1);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
device->set_id(0);
device->set_unit(1);
EXPECT_FALSE(executor->ProcessCmd(context, command1)) << "LUN 0 is missing";
device->set_unit(0);
EXPECT_TRUE(executor->ProcessCmd(context, command1));
PbCommand command_attach1;
command_attach1.set_operation(ATTACH);
auto device1 = command_attach1.add_devices();
device1->set_type(SCHS);
device1->set_id(-1);
CommandContext context_attach1(command_attach1, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_attach1));
PbCommand command_attach2;
command_attach2.set_operation(ATTACH);
auto device2 = command_attach2.add_devices();
device2->set_type(SCHS);
device2->set_id(0);
device2->set_unit(1);
CommandContext context_attach2(command_attach2, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_attach2)) << "LUN 0 is missing";
// The operations below must fail because of missing parameters.
// The respective functionality is tested in piscsi_image_test.cpp.
command1.set_operation(CREATE_IMAGE);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
PbCommand command;
command1.set_operation(DELETE_IMAGE);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
command.set_operation(CREATE_IMAGE);
CommandContext context_create_image(command, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_create_image));
command1.set_operation(RENAME_IMAGE);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
command.set_operation(DELETE_IMAGE);
CommandContext context_delete_image(command, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_delete_image));
command1.set_operation(COPY_IMAGE);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
command.set_operation(RENAME_IMAGE);
CommandContext context_rename_image(command, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_rename_image));
command1.set_operation(PROTECT_IMAGE);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
command.set_operation(COPY_IMAGE);
CommandContext context_copy_image(command, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_copy_image));
command1.set_operation(UNPROTECT_IMAGE);
EXPECT_FALSE(executor->ProcessCmd(context, command1));
command.set_operation(PROTECT_IMAGE);
CommandContext context_protect_image(command, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_protect_image));
command.set_operation(UNPROTECT_IMAGE);
CommandContext context_unprotect_image(command, "", "");
EXPECT_FALSE(executor->ProcessCmd(context_unprotect_image));
}
TEST_F(PiscsiExecutorTest, SetLogLevel)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, 0);
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
EXPECT_TRUE(executor.SetLogLevel("trace"));
EXPECT_TRUE(executor.SetLogLevel("debug"));
EXPECT_TRUE(executor.SetLogLevel("info"));
EXPECT_TRUE(executor.SetLogLevel("warn"));
EXPECT_TRUE(executor.SetLogLevel("err"));
EXPECT_TRUE(executor.SetLogLevel("off"));
EXPECT_FALSE(executor.SetLogLevel("xyz"));
}
TEST_F(PiscsiExecutorTest, Attach)
TEST(PiscsiExecutorTest, Attach)
{
const int ID = 3;
const int LUN = 0;
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbDeviceDefinition definition;
MockCommandContext context;
PbCommand command;
CommandContext context(command, "", "");
definition.set_unit(32);
EXPECT_FALSE(executor.Attach(context, definition, false));
@@ -258,7 +227,7 @@ TEST_F(PiscsiExecutorTest, Attach)
definition.set_type(PbDeviceType::SCHS);
EXPECT_TRUE(executor.Attach(context, definition, false));
controller_manager->DeleteAllControllers();
controller_manager.DeleteAllControllers();
definition.set_type(PbDeviceType::SCHD);
EXPECT_FALSE(executor.Attach(context, definition, false)) << "Drive without sectors not rejected";
@@ -277,19 +246,19 @@ TEST_F(PiscsiExecutorTest, Attach)
EXPECT_FALSE(executor.Attach(context, definition, false)) << "Drive with non-existing image file not rejected";
path filename = CreateTempFile(1);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
EXPECT_FALSE(executor.Attach(context, definition, false)) << "Too small image file not rejected";
remove(filename);
filename = CreateTempFile(512);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
bool result = executor.Attach(context, definition, false);
remove(filename);
EXPECT_TRUE(result);
controller_manager->DeleteAllControllers();
controller_manager.DeleteAllControllers();
filename = CreateTempFile(513);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
result = executor.Attach(context, definition, false);
remove(filename);
EXPECT_TRUE(result);
@@ -297,7 +266,7 @@ TEST_F(PiscsiExecutorTest, Attach)
definition.set_type(PbDeviceType::SCCD);
definition.set_unit(LUN + 1);
filename = CreateTempFile(2048);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
result = executor.Attach(context, definition, false);
remove(filename);
EXPECT_TRUE(result);
@@ -306,25 +275,26 @@ TEST_F(PiscsiExecutorTest, Attach)
definition.set_unit(LUN + 2);
SetParam(definition, "read_only", "true");
filename = CreateTempFile(4096);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
result = executor.Attach(context, definition, false);
remove(filename);
EXPECT_TRUE(result);
controller_manager->DeleteAllControllers();
controller_manager.DeleteAllControllers();
}
TEST_F(PiscsiExecutorTest, Insert)
TEST(PiscsiExecutorTest, Insert)
{
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
PbDeviceDefinition definition;
MockCommandContext context;
auto device = device_factory.CreateDevice(SCRM, 0, "test");
auto bus = make_shared<MockBus>();
ControllerManager controller_manager;
auto [controller, device] = CreateDevice(SCHD);
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbDeviceDefinition definition;
PbCommand command;
CommandContext context(command, "", "");
device->SetRemoved(false);
EXPECT_FALSE(executor.Insert(context, definition, device, false)) << "Medium is not removed";
@@ -358,18 +328,18 @@ TEST_F(PiscsiExecutorTest, Insert)
EXPECT_FALSE(executor.Insert(context, definition, device, false));
path filename = CreateTempFile(1);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
EXPECT_FALSE(executor.Insert(context, definition, device, false)) << "Too small image file not rejected";
remove(filename);
filename = CreateTempFile(512);
SetParam(definition, "file", filename.c_str());
SetParam(definition, "file", filename.string());
const bool result = executor.Insert(context, definition, device, false);
remove(filename);
EXPECT_TRUE(result);
}
TEST_F(PiscsiExecutorTest, Detach)
TEST(PiscsiExecutorTest, Detach)
{
const int ID = 3;
const int LUN1 = 0;
@@ -377,68 +347,72 @@ TEST_F(PiscsiExecutorTest, Detach)
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
auto device1 = device_factory.CreateDevice(SCHS, LUN1, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device1));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device1));
auto device2 = device_factory.CreateDevice(SCHS, LUN2, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device2));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device2));
auto d1 = controller_manager->GetDeviceByIdAndLun(ID, LUN1);
EXPECT_FALSE(executor.Detach(context, d1, false)) << "LUNs > 0 have to be detached first";
auto d2 = controller_manager->GetDeviceByIdAndLun(ID, LUN2);
EXPECT_TRUE(executor.Detach(context, d2, false));
EXPECT_TRUE(executor.Detach(context, d1, false));
EXPECT_TRUE(controller_manager->GetAllDevices().empty());
auto d1 = controller_manager.GetDeviceForIdAndLun(ID, LUN1);
EXPECT_FALSE(executor.Detach(context, *d1, false)) << "LUNs > 0 have to be detached first";
auto d2 = controller_manager.GetDeviceForIdAndLun(ID, LUN2);
EXPECT_TRUE(executor.Detach(context, *d2, false));
EXPECT_TRUE(executor.Detach(context, *d1, false));
EXPECT_TRUE(controller_manager.GetAllDevices().empty());
EXPECT_FALSE(executor.Detach(context, d1, false));
EXPECT_FALSE(executor.Detach(context, *d1, false));
}
TEST_F(PiscsiExecutorTest, DetachAll)
TEST(PiscsiExecutorTest, DetachAll)
{
const int ID = 4;
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
auto device = device_factory.CreateDevice(SCHS, 0, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device));
EXPECT_NE(nullptr, controller_manager->FindController(ID));
EXPECT_FALSE(controller_manager->GetAllDevices().empty());
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device));
EXPECT_TRUE(controller_manager.HasController(ID));
EXPECT_FALSE(controller_manager.GetAllDevices().empty());
executor.DetachAll();
EXPECT_EQ(nullptr, controller_manager->FindController(ID));
EXPECT_TRUE(controller_manager->GetAllDevices().empty());
EXPECT_EQ(nullptr, controller_manager.FindController(ID));
EXPECT_TRUE(controller_manager.GetAllDevices().empty());
}
TEST_F(PiscsiExecutorTest, ShutDown)
TEST(PiscsiExecutorTest, ShutDown)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
command.set_operation(SHUT_DOWN);
CommandContext context(command, "", "");
EXPECT_FALSE(executor.ShutDown(context, ""));
EXPECT_FALSE(executor.ShutDown(context, "xyz"));
EXPECT_FALSE(executor.ShutDown(context, "system")) << "Only available for the root user";
EXPECT_FALSE(executor.ShutDown(context, "reboot")) << "Only available for the root user";
EXPECT_TRUE(executor.ShutDown(context, "rascsi"));
EXPECT_FALSE(executor.ShutDown(context, "system"));
EXPECT_FALSE(executor.ShutDown(context, "reboot"));
}
TEST_F(PiscsiExecutorTest, SetReservedIds)
TEST(PiscsiExecutorTest, SetReservedIds)
{
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
string error = executor.SetReservedIds("xyz");
EXPECT_FALSE(error.empty());
@@ -460,61 +434,85 @@ TEST_F(PiscsiExecutorTest, SetReservedIds)
EXPECT_TRUE(error.empty());
unordered_set<int> reserved_ids = executor.GetReservedIds();
EXPECT_EQ(5, reserved_ids.size());
EXPECT_NE(reserved_ids.end(), reserved_ids.find(1));
EXPECT_NE(reserved_ids.end(), reserved_ids.find(2));
EXPECT_NE(reserved_ids.end(), reserved_ids.find(3));
EXPECT_NE(reserved_ids.end(), reserved_ids.find(5));
EXPECT_NE(reserved_ids.end(), reserved_ids.find(7));
EXPECT_TRUE(reserved_ids.contains(1));
EXPECT_TRUE(reserved_ids.contains(2));
EXPECT_TRUE(reserved_ids.contains(3));
EXPECT_TRUE(reserved_ids.contains(5));
EXPECT_TRUE(reserved_ids.contains(7));
auto device = device_factory.CreateDevice(SCHS, 0, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(5, device));
EXPECT_TRUE(controller_manager.AttachToController(*bus, 5, device));
error = executor.SetReservedIds("5");
EXPECT_FALSE(error.empty());
}
TEST_F(PiscsiExecutorTest, ValidateImageFile)
TEST(PiscsiExecutorTest, ValidateImageFile)
{
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
string full_path;
auto device = dynamic_pointer_cast<StorageDevice>(device_factory.CreateDevice(SCHD, 0, "test"));
EXPECT_TRUE(executor.ValidateImageFile(context, *device, "", full_path));
EXPECT_TRUE(full_path.empty());
EXPECT_TRUE(executor.ValidateImageFile(context, *device, ""));
EXPECT_FALSE(executor.ValidateImageFile(context, *device, "/non_existing_file", full_path));
EXPECT_TRUE(full_path.empty());
EXPECT_FALSE(executor.ValidateImageFile(context, *device, "/non_existing_file"));
}
TEST_F(PiscsiExecutorTest, ValidateLunSetup)
TEST(PiscsiExecutorTest, PrintCommand)
{
auto bus = make_shared<MockBus>();
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbDeviceDefinition definition;
PbCommand command;
string s = executor.PrintCommand(command, definition);
EXPECT_NE(s.find("operation="), string::npos);
EXPECT_EQ(s.find("key1=value1"), string::npos);
EXPECT_EQ(s.find("key2=value2"), string::npos);
SetParam(command, "key1", "value1");
s = executor.PrintCommand(command, definition);
EXPECT_NE(s.find("operation="), string::npos);
EXPECT_NE(s.find("key1=value1"), string::npos);
SetParam(command, "key2", "value2");
s = executor.PrintCommand(command, definition);
EXPECT_NE(s.find("operation="), string::npos);
EXPECT_NE(s.find("key1=value1"), string::npos);
EXPECT_NE(s.find("key2=value2"), string::npos);
}
TEST(PiscsiExecutorTest, EnsureLun0)
{
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
auto device1 = command.add_devices();
device1->set_unit(0);
string error = executor.ValidateLunSetup(command);
string error = executor.EnsureLun0(command);
EXPECT_TRUE(error.empty());
device1->set_unit(1);
error = executor.ValidateLunSetup(command);
error = executor.EnsureLun0(command);
EXPECT_FALSE(error.empty());
auto device2 = device_factory.CreateDevice(SCHS, 0, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(0, device2));
error = executor.ValidateLunSetup(command);
EXPECT_TRUE(controller_manager.AttachToController(*bus, 0, device2));
error = executor.EnsureLun0(command);
EXPECT_TRUE(error.empty());
}
TEST_F(PiscsiExecutorTest, VerifyExistingIdAndLun)
TEST(PiscsiExecutorTest, VerifyExistingIdAndLun)
{
const int ID = 1;
const int LUN1 = 0;
@@ -522,25 +520,27 @@ TEST_F(PiscsiExecutorTest, VerifyExistingIdAndLun)
DeviceFactory device_factory;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
EXPECT_FALSE(executor.VerifyExistingIdAndLun(context, ID, LUN1));
auto device = device_factory.CreateDevice(SCHS, LUN1, "");
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device));
EXPECT_TRUE(executor.VerifyExistingIdAndLun(context, ID, LUN1));
EXPECT_FALSE(executor.VerifyExistingIdAndLun(context, ID, LUN2));
}
TEST_F(PiscsiExecutorTest, CreateDevice)
TEST(PiscsiExecutorTest, CreateDevice)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
EXPECT_EQ(nullptr, executor.CreateDevice(context, UNDEFINED, 0, ""));
#pragma GCC diagnostic push
@@ -551,13 +551,14 @@ TEST_F(PiscsiExecutorTest, CreateDevice)
EXPECT_NE(nullptr, executor.CreateDevice(context, SCHS, 0, ""));
}
TEST_F(PiscsiExecutorTest, SetSectorSize)
TEST(PiscsiExecutorTest, SetSectorSize)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
unordered_set<uint32_t> sizes;
auto hd = make_shared<MockSCSIHD>(0, sizes, false);
@@ -570,13 +571,14 @@ TEST_F(PiscsiExecutorTest, SetSectorSize)
EXPECT_TRUE(executor.SetSectorSize(context, hd, 512));
}
TEST_F(PiscsiExecutorTest, ValidateOperationAgainstDevice)
TEST(PiscsiExecutorTest, ValidateOperationAgainstDevice)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
auto device = make_shared<MockPrimaryDevice>(0);
@@ -623,13 +625,14 @@ TEST_F(PiscsiExecutorTest, ValidateOperationAgainstDevice)
EXPECT_TRUE(executor.ValidateOperationAgainstDevice(context, *device, UNPROTECT));
}
TEST_F(PiscsiExecutorTest, ValidateIdAndLun)
TEST(PiscsiExecutorTest, ValidateIdAndLun)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
EXPECT_FALSE(executor.ValidateIdAndLun(context, -1, 0));
EXPECT_FALSE(executor.ValidateIdAndLun(context, 8, 0));
@@ -639,13 +642,14 @@ TEST_F(PiscsiExecutorTest, ValidateIdAndLun)
EXPECT_TRUE(executor.ValidateIdAndLun(context, 7, 31));
}
TEST_F(PiscsiExecutorTest, SetProductData)
TEST(PiscsiExecutorTest, SetProductData)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiImage piscsi_image;
PiscsiExecutor executor(piscsi_image, *controller_manager);
MockCommandContext context;
PiscsiExecutor executor(piscsi_image, *bus, controller_manager);
PbCommand command;
CommandContext context(command, "", "");
PbDeviceDefinition definition;
auto device = make_shared<MockPrimaryDevice>(0);
+67 -42
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -35,104 +35,129 @@ TEST(PiscsiImageTest, SetGetDefaultFolder)
TEST(PiscsiImageTest, CreateImage)
{
MockCommandContext context;
PbCommand command;
PiscsiImage image;
StorageDevice::UnreserveAll();
EXPECT_FALSE(image.CreateImage(context, command)) << "Filename must be reported as missing";
PbCommand command1;
CommandContext context1(command1, "", "");
EXPECT_FALSE(image.CreateImage(context1)) << "Filename must be reported as missing";
SetParam(command, "file", "/a/b/c/filename");
EXPECT_FALSE(image.CreateImage(context, command)) << "Depth must be reported as invalid";
PbCommand command2;
SetParam(command2, "file", "/a/b/c/filename");
CommandContext context2(command2, "", "");
EXPECT_FALSE(image.CreateImage(context2)) << "Depth must be reported as invalid";
SetParam(command, "file", "filename");
SetParam(command, "size", "-1");
EXPECT_FALSE(image.CreateImage(context, command)) << "Size must be reported as invalid";
PbCommand command3;
SetParam(command3, "file", "filename");
SetParam(command3, "size", "-1");
CommandContext context3(command3, "", "");
EXPECT_FALSE(image.CreateImage(context3)) << "Size must be reported as invalid";
SetParam(command, "size", "1");
EXPECT_FALSE(image.CreateImage(context, command)) << "Size must be reported as invalid";
PbCommand command4;
SetParam(command4, "size", "1");
CommandContext context4(command4, "", "");
EXPECT_FALSE(image.CreateImage(context4)) << "Size must be reported as invalid";
SetParam(command, "size", "513");
EXPECT_FALSE(image.CreateImage(context, command)) << "Size must be reported as not a multiple of 512";
PbCommand command5;
SetParam(command5, "size", "513");
CommandContext context5(command5, "", "");
EXPECT_FALSE(image.CreateImage(context4)) << "Size must be reported as not a multiple of 512";
// Further tests would modify the filesystem
}
TEST(PiscsiImageTest, DeleteImage)
{
MockCommandContext context;
PbCommand command;
PiscsiImage image;
StorageDevice::UnreserveAll();
EXPECT_FALSE(image.DeleteImage(context, command)) << "Filename must be reported as missing";
PbCommand command1;
CommandContext context1(command1, "", "");
EXPECT_FALSE(image.DeleteImage(context1)) << "Filename must be reported as missing";
SetParam(command, "file", "/a/b/c/filename");
EXPECT_FALSE(image.DeleteImage(context, command)) << "Depth must be reported as invalid";
PbCommand command2;
SetParam(command2, "file", "/a/b/c/filename");
CommandContext context2(command2, "", "");
EXPECT_FALSE(image.DeleteImage(context2)) << "Depth must be reported as invalid";
MockStorageDevice device;
device.ReserveFile("filename", 0, 0);
SetParam(command, "file", "filename");
EXPECT_FALSE(image.DeleteImage(context, command)) << "File must be reported as in use";
device.SetFilename("filename");
device.ReserveFile();
PbCommand command3;
SetParam(command3, "file", "filename");
CommandContext context3(command3, "", "");
EXPECT_FALSE(image.DeleteImage(context3)) << "File must be reported as in use";
// Further testing would modify the filesystem
}
TEST(PiscsiImageTest, RenameImage)
{
MockCommandContext context;
PbCommand command;
PiscsiImage image;
StorageDevice::UnreserveAll();
EXPECT_FALSE(image.RenameImage(context, command)) << "Source filename must be reported as missing";
PbCommand command1;
CommandContext context1(command1, "", "");
EXPECT_FALSE(image.RenameImage(context1)) << "Source filename must be reported as missing";
SetParam(command, "from", "/a/b/c/filename_from");
EXPECT_FALSE(image.RenameImage(context, command)) << "Depth must be reported as invalid";
PbCommand command2;
SetParam(command2, "from", "/a/b/c/filename_from");
CommandContext context2(command2, "", "");
EXPECT_FALSE(image.RenameImage(context2)) << "Depth must be reported as invalid";
SetParam(command, "from", "filename_from");
EXPECT_FALSE(image.RenameImage(context, command)) << "Source file must be reported as missing";
PbCommand command3;
SetParam(command3, "from", "filename_from");
CommandContext context3(command3, "", "");
EXPECT_FALSE(image.RenameImage(context3)) << "Source file must be reported as missing";
// Further testing would modify the filesystem
}
TEST(PiscsiImageTest, CopyImage)
{
MockCommandContext context;
PbCommand command;
PiscsiImage image;
StorageDevice::UnreserveAll();
EXPECT_FALSE(image.CopyImage(context, command)) << "Source filename must be reported as missing";
PbCommand command1;
CommandContext context1(command1, "", "");
EXPECT_FALSE(image.CopyImage(context1)) << "Source filename must be reported as missing";
SetParam(command, "from", "/a/b/c/filename_from");
EXPECT_FALSE(image.CopyImage(context, command)) << "Depth must be reported as invalid";
PbCommand command2;
SetParam(command2, "from", "/a/b/c/filename_from");
CommandContext context2(command2, "", "");
EXPECT_FALSE(image.CopyImage(context2)) << "Depth must be reported as invalid";
SetParam(command, "from", "filename_from");
EXPECT_FALSE(image.CopyImage(context, command)) << "Source file must be reported as missing";
PbCommand command3;
SetParam(command3, "from", "filename_from");
CommandContext context3(command3, "", "");
EXPECT_FALSE(image.CopyImage(context3)) << "Source file must be reported as missing";
// Further testing would modify the filesystem
}
TEST(PiscsiImageTest, SetImagePermissions)
{
MockCommandContext context;
PbCommand command;
PiscsiImage image;
StorageDevice::UnreserveAll();
EXPECT_FALSE(image.SetImagePermissions(context, command)) << "Filename must be reported as missing";
PbCommand command1;
CommandContext context1(command1, "", "");
EXPECT_FALSE(image.SetImagePermissions(context1)) << "Filename must be reported as missing";
SetParam(command, "file", "/a/b/c/filename");
EXPECT_FALSE(image.SetImagePermissions(context, command)) << "Depth must be reported as invalid";
PbCommand command2;
SetParam(command2, "file", "/a/b/c/filename");
CommandContext context2(command2, "", "");
EXPECT_FALSE(image.SetImagePermissions(context2)) << "Depth must be reported as invalid";
SetParam(command, "file", "filename");
EXPECT_FALSE(image.CopyImage(context, command)) << "Source file must be reported as missing";
PbCommand command3;
SetParam(command3, "file", "filename");
CommandContext context3(command3, "", "");
EXPECT_FALSE(image.CopyImage(context3)) << "Source file must be reported as missing";
// Further testing would modify the filesystem
}
+74 -69
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -13,32 +13,33 @@
#include "devices/device_factory.h"
#include "generated/piscsi_interface.pb.h"
#include "piscsi/piscsi_response.h"
#include <sys/stat.h>
using namespace piscsi_interface;
TEST(PiscsiResponseTest, Operation_Count)
{
PiscsiResponse response;
PbResult result;
const auto info = response.GetOperationInfo(result, 0);
EXPECT_EQ(PbOperation_ARRAYSIZE - 1, info->operations_size());
PbOperationInfo info;
response.GetOperationInfo(info, 0);
EXPECT_EQ(PbOperation_ARRAYSIZE - 1, info.operations_size());
}
void TestNonDiskDevice(PbDeviceType type, int default_param_count)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
DeviceFactory device_factory;
PiscsiResponse response;
auto d = device_factory.CreateDevice(type, 0, "");
const unordered_map<string, string> params;
const param_map params;
d->Init(params);
EXPECT_TRUE(controller_manager->AttachToScsiController(0, d));
EXPECT_TRUE(controller_manager.AttachToController(*bus, 0, d));
PbServerInfo info;
response.GetDevices(controller_manager->GetAllDevices(), info, "image_folder");
response.GetDevices(controller_manager.GetAllDevices(), info, "image_folder");
EXPECT_EQ(1, info.devices_info().devices().size());
@@ -81,21 +82,29 @@ TEST(PiscsiResponseTest, GetImageFile)
EXPECT_EQ(SCHD, image_file.type());
}
TEST(PiscsiResponseTest, GetImageFilesInfo)
{
PiscsiResponse response;
PbImageFilesInfo info;
response.GetImageFilesInfo(info, "default_folder", "", "", 1);
EXPECT_TRUE(info.image_files().empty());
}
TEST(PiscsiResponseTest, GetReservedIds)
{
PiscsiResponse response;
unordered_set<int> ids;
PbResult result;
const auto& info1 = response.GetReservedIds(result, ids);
EXPECT_TRUE(result.status());
EXPECT_TRUE(info1->ids().empty());
PbReservedIdsInfo info1;
response.GetReservedIds(info1, ids);
EXPECT_TRUE(info1.ids().empty());
ids.insert(3);
const auto& info2 = response.GetReservedIds(result, ids);
EXPECT_TRUE(result.status());
EXPECT_EQ(1, info2->ids().size());
EXPECT_EQ(3, info2->ids()[0]);
PbReservedIdsInfo info2;
response.GetReservedIds(info2, ids);
EXPECT_EQ(1, info2.ids().size());
EXPECT_EQ(3, info2.ids()[0]);
}
TEST(PiscsiResponseTest, GetDevicesInfo)
@@ -106,40 +115,42 @@ TEST(PiscsiResponseTest, GetDevicesInfo)
const int LUN3 = 6;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
ControllerManager controller_manager;
PiscsiResponse response;
PbCommand command;
PbResult result;
response.GetDevicesInfo(controller_manager->GetAllDevices(), result, command, "");
EXPECT_TRUE(result.status());
EXPECT_TRUE(result.devices_info().devices().empty());
PbResult result1;
response.GetDevicesInfo(controller_manager.GetAllDevices(), result1, command, "");
EXPECT_TRUE(result1.status());
EXPECT_TRUE(result1.devices_info().devices().empty());
auto device1 = make_shared<MockHostServices>(LUN1);
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device1));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device1));
response.GetDevicesInfo(controller_manager->GetAllDevices(), result, command, "");
EXPECT_TRUE(result.status());
auto& devices1 = result.devices_info().devices();
response.GetDevicesInfo(controller_manager.GetAllDevices(), result1, command, "");
EXPECT_TRUE(result1.status());
auto& devices1 = result1.devices_info().devices();
EXPECT_EQ(1, devices1.size());
EXPECT_EQ(SCHS, devices1[0].type());
EXPECT_EQ(ID, devices1[0].id());
EXPECT_EQ(LUN1, devices1[0].unit());
auto device2 = make_shared<MockSCSIHD_NEC>(LUN2);
EXPECT_TRUE(controller_manager->AttachToScsiController(ID, device2));
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device2));
response.GetDevicesInfo(controller_manager->GetAllDevices(), result, command, "");
EXPECT_TRUE(result.status());
auto& devices2 = result.devices_info().devices();
EXPECT_EQ(2, devices2.size()) << "Data for all devices must be returned";
PbResult result2;
response.GetDevicesInfo(controller_manager.GetAllDevices(), result2, command, "");
EXPECT_TRUE(result2.status());
auto& devices2 = result2.devices_info().devices();
EXPECT_EQ(2, devices2.size()) << "Device count mismatch";
auto requested_device = command.add_devices();
requested_device->set_id(ID);
requested_device->set_unit(LUN1);
response.GetDevicesInfo(controller_manager->GetAllDevices(), result, command, "");
EXPECT_TRUE(result.status());
auto& devices3 = result.devices_info().devices();
PbResult result3;
response.GetDevicesInfo(controller_manager.GetAllDevices(), result3, command, "");
EXPECT_TRUE(result3.status());
auto& devices3 = result3.devices_info().devices();
EXPECT_EQ(1, devices3.size()) << "Only data for the specified ID and LUN must be returned";
EXPECT_EQ(SCHS, devices3[0].type());
EXPECT_EQ(ID, devices3[0].id());
@@ -147,79 +158,73 @@ TEST(PiscsiResponseTest, GetDevicesInfo)
requested_device->set_id(ID);
requested_device->set_unit(LUN3);
response.GetDevicesInfo(controller_manager->GetAllDevices(), result, command, "");
EXPECT_FALSE(result.status()) << "Only data for the specified ID and LUN must be returned";
PbResult result4;
response.GetDevicesInfo(controller_manager.GetAllDevices(), result4, command, "");
EXPECT_FALSE(result4.status()) << "Only data for the specified ID and LUN must be returned";
}
TEST(PiscsiResponseTest, GetDeviceTypesInfo)
{
PiscsiResponse response;
PbResult result;
const auto& info = response.GetDeviceTypesInfo(result);
EXPECT_TRUE(result.status());
EXPECT_EQ(8, info->properties().size());
PbDeviceTypesInfo info;
response.GetDeviceTypesInfo(info);
EXPECT_EQ(8, info.properties().size());
}
TEST(PiscsiResponseTest, GetServerInfo)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
PiscsiResponse response;
const unordered_set<shared_ptr<PrimaryDevice>> devices;
const unordered_set<int> ids = { 1, 3 };
PbResult result;
const auto& info = response.GetServerInfo(devices, result, ids, "log_level", "default_folder", "", "", 1234);
EXPECT_TRUE(result.status());
EXPECT_EQ(piscsi_major_version, info->version_info().major_version());
EXPECT_EQ(piscsi_minor_version, info->version_info().minor_version());
EXPECT_EQ(piscsi_patch_version, info->version_info().patch_version());
EXPECT_EQ("log_level", info->log_level_info().current_log_level());
EXPECT_EQ("default_folder", info->image_files_info().default_image_folder());
EXPECT_EQ(1234, info->image_files_info().depth());
EXPECT_EQ(2, info->reserved_ids_info().ids().size());
PbServerInfo info;
response.GetServerInfo(info, devices, ids, "default_folder", "", "", 1234);
EXPECT_EQ(piscsi_major_version, info.version_info().major_version());
EXPECT_EQ(piscsi_minor_version, info.version_info().minor_version());
EXPECT_EQ(piscsi_patch_version, info.version_info().patch_version());
EXPECT_EQ(level::level_string_views[get_level()], info.log_level_info().current_log_level());
EXPECT_EQ("default_folder", info.image_files_info().default_image_folder());
EXPECT_EQ(1234, info.image_files_info().depth());
EXPECT_EQ(2, info.reserved_ids_info().ids().size());
}
TEST(PiscsiResponseTest, GetVersionInfo)
{
PiscsiResponse response;
PbResult result;
const auto& info = response.GetVersionInfo(result);
EXPECT_TRUE(result.status());
EXPECT_EQ(piscsi_major_version, info->major_version());
EXPECT_EQ(piscsi_minor_version, info->minor_version());
EXPECT_EQ(piscsi_patch_version, info->patch_version());
PbVersionInfo info;
response.GetVersionInfo(info);
EXPECT_EQ(piscsi_major_version, info.major_version());
EXPECT_EQ(piscsi_minor_version, info.minor_version());
EXPECT_EQ(piscsi_patch_version, info.patch_version());
}
TEST(PiscsiResponseTest, GetLogLevelInfo)
{
PiscsiResponse response;
PbResult result;
const auto& info = response.GetLogLevelInfo(result, "level");
EXPECT_TRUE(result.status());
EXPECT_EQ("level", info->current_log_level());
EXPECT_EQ(6, info->log_levels().size());
PbLogLevelInfo info;
response.GetLogLevelInfo(info);
EXPECT_EQ(level::level_string_views[get_level()], info.current_log_level());
EXPECT_EQ(7, info.log_levels().size());
}
TEST(PiscsiResponseTest, GetNetworkInterfacesInfo)
{
PiscsiResponse response;
PbResult result;
const auto& info = response.GetNetworkInterfacesInfo(result);
EXPECT_TRUE(result.status());
EXPECT_FALSE(info->name().empty());
PbNetworkInterfacesInfo info;
response.GetNetworkInterfacesInfo(info);
EXPECT_FALSE(info.name().empty());
}
TEST(PiscsiResponseTest, GetMappingInfo)
{
PiscsiResponse response;
PbResult result;
const auto& info = response.GetMappingInfo(result);
EXPECT_TRUE(result.status());
EXPECT_EQ(10, info->mapping().size());
PbMappingInfo info;
response.GetMappingInfo(info);
EXPECT_EQ(10, info.mapping().size());
}
+92 -8
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
// These tests only test up the point where a network connection is required.
//
@@ -11,16 +11,100 @@
#include <gtest/gtest.h>
#include "generated/piscsi_interface.pb.h"
#include "shared/protobuf_util.h"
#include "shared/network_util.h"
#include "shared/piscsi_exceptions.h"
#include "piscsi/command_context.h"
#include "piscsi/piscsi_service.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
TEST(PiscsiServiceTest, LifeCycle)
using namespace piscsi_interface;
using namespace protobuf_util;
using namespace network_util;
void SendCommand(const PbCommand& command, PbResult& result)
{
sockaddr_in server_addr = {};
ASSERT_TRUE(ResolveHostName("127.0.0.1", &server_addr));
server_addr.sin_port = htons(uint16_t(9999));
const int fd = socket(AF_INET, SOCK_STREAM, 0);
ASSERT_NE(-1, fd);
EXPECT_TRUE(connect(fd, reinterpret_cast<sockaddr *>(&server_addr), sizeof(server_addr)) >= 0) << "Service should be running"; //NOSONAR bit_cast is not supported by the bullseye clang++ compiler
ASSERT_EQ(6, write(fd, "RASCSI", 6));
SerializeMessage(fd, command);
DeserializeMessage(fd, result);
close(fd);
}
TEST(PiscsiServiceTest, Init)
{
PiscsiService service;
EXPECT_TRUE(service.Init(nullptr, 65535));
EXPECT_FALSE(service.Init(nullptr, 65536));
EXPECT_FALSE(service.Init(nullptr, 0));
EXPECT_FALSE(service.Init(nullptr, -1));
service.Cleanup();
EXPECT_FALSE(service.Init(nullptr, 65536).empty()) << "Illegal port number";
EXPECT_FALSE(service.Init(nullptr, 0).empty()) << "Illegal port number";
EXPECT_FALSE(service.Init(nullptr, -1).empty()) << "Illegal port number";
EXPECT_FALSE(service.Init(nullptr, 1).empty()) << "Port 1 is only available for the root user";
EXPECT_TRUE(service.Init(nullptr, 9999).empty()) << "Port 9999 is expected not to be in use for this test";
service.Stop();
}
TEST(PiscsiServiceTest, IsRunning)
{
PiscsiService service;
EXPECT_FALSE(service.IsRunning());
EXPECT_TRUE(service.Init(nullptr, 9999).empty()) << "Port 9999 is expected not to be in use for this test";
EXPECT_FALSE(service.IsRunning());
service.Start();
EXPECT_TRUE(service.IsRunning());
service.Stop();
EXPECT_FALSE(service.IsRunning());
}
TEST(PiscsiServiceTest, Execute)
{
sockaddr_in server_addr = {};
ASSERT_TRUE(ResolveHostName("127.0.0.1", &server_addr));
const int fd = socket(AF_INET, SOCK_STREAM, 0);
ASSERT_NE(-1, fd);
server_addr.sin_port = htons(uint16_t(9999));
EXPECT_FALSE(connect(fd, reinterpret_cast<sockaddr *>(&server_addr), sizeof(server_addr)) >= 0) << "Service should not be running"; //NOSONAR bit_cast is not supported by the bullseye clang++ compiler
close(fd);
PiscsiService service;
service.Init([] (const CommandContext& context) {
if (context.GetCommand().operation() == PbOperation::NO_OPERATION) {
PbResult result;
result.set_status(true);
context.WriteResult(result);
}
else {
throw io_exception("error");
}
return true;
}, 9999);
service.Start();
PbCommand command;
PbResult result;
SendCommand(command, result);
command.set_operation(PbOperation::NO_OPERATION);
EXPECT_TRUE(result.status()) << "Command should have been successful";
command.set_operation(PbOperation::EJECT);
SendCommand(command, result);
EXPECT_FALSE(result.status()) << "Exception should have been raised";
service.Stop();
}
+68 -12
View File
@@ -3,53 +3,109 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <gtest/gtest.h>
#include "shared/piscsi_util.h"
#include "generated/piscsi_interface.pb.h"
#ifdef __linux__
#include <sched.h>
#endif
using namespace std;
using namespace piscsi_interface;
using namespace piscsi_util;
TEST(PiscsiUtilTest, Split)
{
auto v = Split("this_is_a_test", '_');
EXPECT_EQ(4, v.size());
EXPECT_EQ("this", v[0]);
EXPECT_EQ("is", v[1]);
EXPECT_EQ("a", v[2]);
EXPECT_EQ("test", v[3]);
v = Split("test", ':');
EXPECT_EQ(1, v.size());
EXPECT_EQ("test", v[0]);
v = Split(":test", ':');
EXPECT_EQ(2, v.size());
EXPECT_EQ("", v[0]);
EXPECT_EQ("test", v[1]);
v = Split("test:", ':');
EXPECT_EQ(1, v.size());
EXPECT_EQ("test", v[0]);
v = Split(":", ':');
EXPECT_EQ(1, v.size());
EXPECT_EQ("", v[0]);
v = Split("", ':');
EXPECT_EQ(0, v.size());
v = Split("this:is:a:test", ':', 1);
EXPECT_EQ(1, v.size());
EXPECT_EQ("this:is:a:test", v[0]);
v = Split("this:is:a:test", ':', 2);
EXPECT_EQ(2, v.size());
EXPECT_EQ("this", v[0]);
EXPECT_EQ("is:a:test", v[1]);
}
TEST(PiscsiUtilTest, GetLocale)
{
EXPECT_LE(2, GetLocale().size());
}
TEST(PiscsiUtilTest, ProcessId)
{
int id = -1;
int lun = -1;
string error = ProcessId("", 32, id, lun);
string error = ProcessId("", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("0:32", 32, id, lun);
error = ProcessId("8", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("-1:", 32, id, lun);
error = ProcessId("0:32", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("0:-1", 32, id, lun);
error = ProcessId("-1:", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("0", 32, id, lun);
error = ProcessId("0:-1", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("a", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("a:0", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("0:a", id, lun);
EXPECT_FALSE(error.empty());
EXPECT_EQ(-1, id);
EXPECT_EQ(-1, lun);
error = ProcessId("0", id, lun);
EXPECT_TRUE(error.empty());
EXPECT_EQ(0, id);
EXPECT_EQ(0, lun);
EXPECT_EQ(-1, lun);
error = ProcessId("7:31", 32, id, lun);
error = ProcessId("7:31", id, lun);
EXPECT_TRUE(error.empty());
EXPECT_EQ(7, id);
EXPECT_EQ(31, lun);
@@ -78,10 +134,10 @@ TEST(PiscsiUtilTest, GetExtensionLowerCase)
{
EXPECT_EQ("", GetExtensionLowerCase(""));
EXPECT_EQ("", GetExtensionLowerCase("."));
EXPECT_EQ("", GetExtensionLowerCase(".ext"));
EXPECT_EQ("", GetExtensionLowerCase(".ext_long"));
EXPECT_EQ("ext", GetExtensionLowerCase("file.ext"));
EXPECT_EQ("ext", GetExtensionLowerCase("FILE.EXT"));
EXPECT_EQ("ext", GetExtensionLowerCase(".ext"));
EXPECT_EQ("ext_long", GetExtensionLowerCase(".ext_long"));
EXPECT_EQ("ext", GetExtensionLowerCase(".XYZ.EXT"));
}
+98 -176
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -17,33 +17,28 @@
using namespace scsi_defs;
using namespace scsi_command_util;
pair<shared_ptr<MockAbstractController>, shared_ptr<MockPrimaryDevice>> CreatePrimaryDevice(int id = 0)
{
auto controller = make_shared<NiceMock<MockAbstractController>>(id);
auto device = make_shared<MockPrimaryDevice>(0);
EXPECT_TRUE(device->Init({}));
EXPECT_TRUE(controller->AddDevice(device));
return { controller, device };
}
TEST(PrimaryDeviceTest, GetId)
{
const int ID = 5;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, ID);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
auto [controller, device] = CreatePrimaryDevice(ID);
EXPECT_EQ(-1, device->GetId()) << "Device ID cannot be known without assignment to a controller";
controller->AddDevice(device);
EXPECT_EQ(ID, device->GetId());
}
TEST(PrimaryDeviceTest, PhaseChange)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
EXPECT_CALL(*controller, Status);
device->EnterStatusPhase();
@@ -57,14 +52,7 @@ TEST(PrimaryDeviceTest, PhaseChange)
TEST(PrimaryDeviceTest, Reset)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
device->Dispatch(scsi_command::eCmdReserve6);
EXPECT_FALSE(device->CheckReservation(1, scsi_command::eCmdTestUnitReady, false))
@@ -76,14 +64,7 @@ TEST(PrimaryDeviceTest, Reset)
TEST(PrimaryDeviceTest, CheckReservation)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
EXPECT_TRUE(device->CheckReservation(0, scsi_command::eCmdTestUnitReady, false))
<< "Device must not be reserved for initiator ID 0";
@@ -110,14 +91,7 @@ TEST(PrimaryDeviceTest, CheckReservation)
TEST(PrimaryDeviceTest, ReserveReleaseUnit)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
device->Dispatch(scsi_command::eCmdReserve6);
EXPECT_FALSE(device->CheckReservation(1, scsi_command::eCmdTestUnitReady, false))
@@ -139,14 +113,7 @@ TEST(PrimaryDeviceTest, ReserveReleaseUnit)
TEST(PrimaryDeviceTest, DiscardReservation)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
device->Dispatch(scsi_command::eCmdReserve6);
EXPECT_FALSE(device->CheckReservation(1, scsi_command::eCmdTestUnitReady, false))
@@ -158,73 +125,61 @@ TEST(PrimaryDeviceTest, DiscardReservation)
TEST(PrimaryDeviceTest, TestUnitReady)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
// Required by the bullseye clang++ compiler
auto d = device;
device->SetReset(true);
device->SetAttn(true);
device->SetReady(false);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::UNIT_ATTENTION),
Property(&scsi_exception::get_asc, asc::POWER_ON_OR_RESET))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::unit_attention),
Property(&scsi_exception::get_asc, asc::power_on_or_reset))));
device->SetReset(false);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::UNIT_ATTENTION),
Property(&scsi_exception::get_asc, asc::NOT_READY_TO_READY_CHANGE))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::unit_attention),
Property(&scsi_exception::get_asc, asc::not_ready_to_ready_change))));
device->SetReset(true);
device->SetAttn(false);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::UNIT_ATTENTION),
Property(&scsi_exception::get_asc, asc::POWER_ON_OR_RESET))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::unit_attention),
Property(&scsi_exception::get_asc, asc::power_on_or_reset))));
device->SetReset(false);
device->SetAttn(true);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::UNIT_ATTENTION),
Property(&scsi_exception::get_asc, asc::NOT_READY_TO_READY_CHANGE))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::unit_attention),
Property(&scsi_exception::get_asc, asc::not_ready_to_ready_change))));
device->SetAttn(false);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::NOT_READY),
Property(&scsi_exception::get_asc, asc::MEDIUM_NOT_PRESENT))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdTestUnitReady); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::not_ready),
Property(&scsi_exception::get_asc, asc::medium_not_present))));
device->SetReady(true);
EXPECT_CALL(*controller, Status);
device->Dispatch(scsi_command::eCmdTestUnitReady);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(PrimaryDeviceTest, Inquiry)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto& cmd = controller->GetCmd();
auto [controller, device] = CreatePrimaryDevice();
// Required by the bullseye clang++ compiler
auto d = device;
// ALLOCATION LENGTH
cmd[4] = 255;
controller->SetCmdByte(4, 255);
ON_CALL(*device, InquiryInternal()).WillByDefault([&device]() {
return device->HandleInquiry(device_type::PROCESSOR, scsi_level::SPC_3, false);
ON_CALL(*d, InquiryInternal()).WillByDefault([&d]() {
return d->HandleInquiry(device_type::processor, scsi_level::spc_3, false);
});
EXPECT_CALL(*device, InquiryInternal);
EXPECT_CALL(*controller, DataIn);
@@ -237,42 +192,42 @@ TEST(PrimaryDeviceTest, Inquiry)
EXPECT_CALL(*device, InquiryInternal);
EXPECT_CALL(*controller, DataIn);
device->Dispatch(scsi_command::eCmdInquiry);
EXPECT_EQ(device_type::PROCESSOR, (device_type)controller->GetBuffer()[0]);
EXPECT_EQ(device_type::processor, (device_type)controller->GetBuffer()[0]);
EXPECT_EQ(0x00, controller->GetBuffer()[1]) << "Device was not reported as non-removable";
EXPECT_EQ(scsi_level::SPC_3, (scsi_level)controller->GetBuffer()[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::SCSI_2, (scsi_level)controller->GetBuffer()[3]) << "Wrong response level";
EXPECT_EQ(scsi_level::spc_3, (scsi_level)controller->GetBuffer()[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::scsi_2, (scsi_level)controller->GetBuffer()[3]) << "Wrong response level";
EXPECT_EQ(0x1f, controller->GetBuffer()[4]) << "Wrong additional data size";
ON_CALL(*device, InquiryInternal()).WillByDefault([&device]() {
return device->HandleInquiry(device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, true);
ON_CALL(*device, InquiryInternal()).WillByDefault([&d]() {
return d->HandleInquiry(device_type::direct_access, scsi_level::scsi_1_ccs, true);
});
EXPECT_CALL(*device, InquiryInternal);
EXPECT_CALL(*controller, DataIn);
device->Dispatch(scsi_command::eCmdInquiry);
EXPECT_EQ(device_type::DIRECT_ACCESS, (device_type)controller->GetBuffer()[0]);
EXPECT_EQ(device_type::direct_access, (device_type)controller->GetBuffer()[0]);
EXPECT_EQ(0x80, controller->GetBuffer()[1]) << "Device was not reported as removable";
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller->GetBuffer()[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller->GetBuffer()[3]) << "Wrong response level";
EXPECT_EQ(scsi_level::scsi_1_ccs, (scsi_level)controller->GetBuffer()[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::scsi_1_ccs, (scsi_level)controller->GetBuffer()[3]) << "Wrong response level";
EXPECT_EQ(0x1f, controller->GetBuffer()[4]) << "Wrong additional data size";
cmd[1] = 0x01;
controller->SetCmdByte(1, 0x01);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdInquiry); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdInquiry); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "EVPD bit is not supported";
cmd[2] = 0x01;
controller->SetCmdByte(2, 0x01);
EXPECT_CALL(*controller, DataIn).Times(0);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdInquiry); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
EXPECT_THAT([&d] { d->Dispatch(scsi_command::eCmdInquiry); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "PAGE CODE field is not supported";
cmd[1] = 0x00;
cmd[2] = 0x00;
controller->SetCmdByte(1, 0);
controller->SetCmdByte(2, 0);
// ALLOCATION LENGTH
cmd[4] = 1;
controller->SetCmdByte(4, 1);
EXPECT_CALL(*device, InquiryInternal);
EXPECT_CALL(*controller, DataIn);
device->Dispatch(scsi_command::eCmdInquiry);
@@ -282,64 +237,51 @@ TEST(PrimaryDeviceTest, Inquiry)
TEST(PrimaryDeviceTest, RequestSense)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
auto [controller, device] = CreatePrimaryDevice();
// Required by the bullseye clang++ compiler
auto d = device;
controller->AddDevice(device);
auto& cmd = controller->GetCmd();
// ALLOCATION LENGTH
cmd[4] = 255;
controller->SetCmdByte(4, 255);
device->SetReady(false);
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdRequestSense); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::NOT_READY),
Property(&scsi_exception::get_asc, asc::MEDIUM_NOT_PRESENT))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdRequestSense); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::not_ready),
Property(&scsi_exception::get_asc, asc::medium_not_present))));
device->SetReady(true);
EXPECT_CALL(*controller, DataIn);
device->Dispatch(scsi_command::eCmdRequestSense);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(PrimaryDeviceTest, SendDiagnostic)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto& cmd = controller->GetCmd();
auto [controller, device] = CreatePrimaryDevice();
// Required by the bullseye clang++ compiler
auto d = device;
EXPECT_CALL(*controller, Status);
device->Dispatch(scsi_command::eCmdSendDiagnostic);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
cmd[1] = 0x10;
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdSendDiagnostic); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(1, 0x10);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSendDiagnostic); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "SEND DIAGNOSTIC must fail because PF bit is not supported";
cmd[1] = 0;
controller->SetCmdByte(1, 0);
cmd[3] = 1;
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdSendDiagnostic); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(3, 1);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSendDiagnostic); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
cmd[3] = 0;
cmd[4] = 1;
EXPECT_THAT([&] { device->Dispatch(scsi_command::eCmdSendDiagnostic); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(3, 0);
controller->SetCmdByte(4, 1);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSendDiagnostic); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
}
@@ -348,23 +290,19 @@ TEST(PrimaryDeviceTest, ReportLuns)
const int LUN1 = 1;
const int LUN2 = 4;
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>(0);
auto device1 = make_shared<MockPrimaryDevice>(LUN1);
auto device2 = make_shared<MockPrimaryDevice>(LUN2);
const unordered_map<string, string> params;
device1->Init(params);
device2->Init(params);
EXPECT_TRUE(device1->Init({}));
EXPECT_TRUE(device2->Init({}));
controller->AddDevice(device1);
EXPECT_TRUE(controller->HasDeviceForLun(LUN1));
controller->AddDevice(device2);
EXPECT_TRUE(controller->HasDeviceForLun(LUN2));
auto& cmd = controller->GetCmd();
// ALLOCATION LENGTH
cmd[9] = 255;
controller->SetCmdByte(9, 255);
EXPECT_CALL(*controller, DataIn);
device1->Dispatch(scsi_command::eCmdReportLuns);
@@ -380,33 +318,25 @@ TEST(PrimaryDeviceTest, ReportLuns)
EXPECT_EQ(0, GetInt16(buffer, 20)) << "Wrong LUN2 number";
EXPECT_EQ(LUN2, GetInt16(buffer, 22)) << "Wrong LUN2 number";
cmd[2] = 0x01;
controller->SetCmdByte(2, 0x01);
EXPECT_THAT([&] { device1->Dispatch(scsi_command::eCmdReportLuns); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Only SELECT REPORT mode 0 is supported";
}
TEST(PrimaryDeviceTest, Dispatch)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
controller->AddDevice(device);
auto [controller, device] = CreatePrimaryDevice();
EXPECT_THROW(device->Dispatch(static_cast<scsi_command>(0x1f)), scsi_exception) << "Unknown command";
}
TEST(PrimaryDeviceTest, WriteByteSequence)
{
vector<uint8_t> data;
MockPrimaryDevice device(0);
auto [controller, device] = CreatePrimaryDevice();
EXPECT_FALSE(device.WriteByteSequence(data, 0)) << "Primary device does not support writing byte sequences";
EXPECT_FALSE(device->WriteByteSequence({})) << "Primary device does not support writing byte sequences";
}
TEST(PrimaryDeviceTest, GetSetSendDelay)
@@ -420,16 +350,8 @@ TEST(PrimaryDeviceTest, GetSetSendDelay)
TEST(PrimaryDeviceTest, Init)
{
unordered_map<string, string> params;
param_map params;
MockPrimaryDevice device(0);
EXPECT_TRUE(device.Init(params)) << "Initialization of primary device must not fail";
}
TEST(PrimaryDeviceTest, FlushCache)
{
MockPrimaryDevice device(0);
// Method must be present
device.FlushCache();
}
-98
View File
@@ -1,98 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/protobuf_serializer.h"
#include "shared/piscsi_exceptions.h"
#include "generated/piscsi_interface.pb.h"
#include <filesystem>
using namespace filesystem;
using namespace piscsi_interface;
TEST(ProtobufSerializerTest, SerializeMessage)
{
PbResult result;
ProtobufSerializer serializer;
const int fd = open("/dev/null", O_WRONLY);
EXPECT_NE(-1, fd);
serializer.SerializeMessage(fd, result);
EXPECT_THROW(serializer.SerializeMessage(-1, result), io_exception) << "Writing a message must fail";
close(fd);
}
TEST(ProtobufSerializerTest, DeserializeMessage)
{
PbResult result;
ProtobufSerializer serializer;
vector<byte> buf(1);
int fd = open("/dev/null", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_THROW(serializer.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);
EXPECT_NE(-1, fd1);
EXPECT_THROW(serializer.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(serializer.DeserializeMessage(fd2, result), io_exception) << "Invalid data were not rejected";
remove(filename2);
}
TEST(ProtobufSerializerTest, SerializeDeserializeMessage)
{
PbResult result;
result.set_status(true);
ProtobufSerializer serializer;
auto [fd, filename] = OpenTempFile();
EXPECT_NE(-1, fd);
serializer.SerializeMessage(fd, result);
close(fd);
result.set_status(false);
fd = open(filename.c_str(), O_RDONLY);
EXPECT_NE(-1, fd);
serializer.DeserializeMessage(fd, result);
close(fd);
remove(filename);
EXPECT_TRUE(result.status());
}
TEST(ProtobufSerializerTest, ReadBytes)
{
ProtobufSerializer serializer;
vector<byte> buf(1);
int fd = open("/dev/null", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_EQ(0, serializer.ReadBytes(fd, buf));
close(fd);
fd = open("/dev/zero", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_EQ(1, serializer.ReadBytes(fd, buf));
close(fd);
}
+90 -16
View File
@@ -3,13 +3,15 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// 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;
@@ -22,22 +24,14 @@ void TestSpecialDevice(const string& name)
EXPECT_EQ("", GetParam(device, "interfaces"));
}
TEST(ProtobufUtil, AddGetParam)
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"));
PbDeviceDefinition definition;
SetParam(definition, "key", "value");
EXPECT_EQ("value", GetParam(definition, "key"));
EXPECT_EQ("", GetParam(definition, "xyz"));
PbDevice device;
SetParam(device, "key", "value");
const auto& it = device.params().find("key");
EXPECT_EQ("value", it->second);
EXPECT_EQ("", GetParam(command, ""));
}
TEST(ProtobufUtil, ParseParameters)
@@ -84,7 +78,7 @@ TEST(ProtobufUtil, SetPatternParams)
TEST(ProtobufUtil, ListDevices)
{
list<PbDevice> devices;
vector<PbDevice> devices;
EXPECT_FALSE(ListDevices(devices).empty());
@@ -136,10 +130,90 @@ TEST(ProtobufUtil, SetIdAndLun)
{
PbDeviceDefinition device;
EXPECT_NE("", SetIdAndLun(device, "", 32));
EXPECT_EQ("", SetIdAndLun(device, "1", 32));
EXPECT_NE("", SetIdAndLun(device, ""));
EXPECT_EQ("", SetIdAndLun(device, "1"));
EXPECT_EQ(1, device.id());
EXPECT_EQ("", SetIdAndLun(device, "2:0", 32));
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);
}
+28 -31
View File
@@ -10,7 +10,6 @@
#include "mocks.h"
#include "shared/scsi.h"
#include "shared/piscsi_exceptions.h"
#include "devices/device_logger.h"
#include "devices/scsi_command_util.h"
using namespace scsi_command_util;
@@ -18,14 +17,13 @@ using namespace scsi_command_util;
TEST(ScsiCommandUtilTest, ModeSelect6)
{
const int LENGTH = 26;
DeviceLogger logger;
vector<int> cdb(6);
vector<uint8_t> buf(LENGTH);
// PF (vendor-specific parameter format) must not fail but be ignored
cdb[1] = 0x00;
ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 0);
ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 0);
cdb[0] = 0x15;
// PF (standard parameter format)
@@ -34,50 +32,49 @@ TEST(ScsiCommandUtilTest, ModeSelect6)
buf[9] = 0x00;
buf[10] = 0x02;
buf[11] = 0x00;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 256); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 256); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Requested sector size does not match current sector size";
// Page 0
buf[12] = 0x00;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page)
buf[12] = 0x03;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Requested sector size does not match current sector size";
// Match the requested to the current sector size
buf[24] = 0x02;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH - 1, 512); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH - 1, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Not enough command parameters";
ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512);
EXPECT_FALSE(ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512).empty());
}
TEST(ScsiCommandUtilTest, ModeSelect10)
{
const int LENGTH = 30;
DeviceLogger logger;
vector<int> cdb(10);
vector<uint8_t> buf(LENGTH);
// PF (vendor-specific parameter format) must not fail but be ignored
cdb[1] = 0x00;
ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 0);
ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 0);
// PF (standard parameter format)
cdb[1] = 0x10;
@@ -85,37 +82,37 @@ TEST(ScsiCommandUtilTest, ModeSelect10)
buf[13] = 0x00;
buf[14] = 0x02;
buf[15] = 0x00;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 256); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 256); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Requested sector size does not match current sector size";
// Page 0
buf[16] = 0x00;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page)
buf[16] = 0x03;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Requested sector size does not match current sector size";
// Match the requested to the current sector size
buf[28] = 0x02;
EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH - 1, 512); },
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH - 1, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Not enough command parameters";
ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512);
EXPECT_FALSE(ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512).empty());
}
TEST(ScsiCommandUtilTest, EnrichFormatPage)
+28 -57
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -19,8 +19,7 @@ TEST(ScsiControllerTest, GetInitiatorId)
const int ID = 2;
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.Process(ID);
EXPECT_EQ(ID, controller.GetInitiatorId());
@@ -31,46 +30,42 @@ TEST(ScsiControllerTest, GetInitiatorId)
TEST(ScsiControllerTest, Process)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::reserved);
ON_CALL(*bus, GetRST).WillByDefault(Return(true));
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST);
EXPECT_CALL(*bus, Reset);
EXPECT_CALL(controller, Reset);
EXPECT_EQ(phase_t::reserved, controller.Process(0));
EXPECT_FALSE(controller.Process(0));
controller.SetPhase(phase_t::busfree);
ON_CALL(*bus, GetRST).WillByDefault(Return(false));
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST);
EXPECT_EQ(phase_t::busfree, controller.Process(0));
EXPECT_FALSE(controller.Process(0));
controller.SetPhase(phase_t::reserved);
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST);
EXPECT_CALL(*bus, Reset);
EXPECT_CALL(controller, Reset);
EXPECT_EQ(phase_t::busfree, controller.Process(0));
EXPECT_FALSE(controller.Process(0));
}
TEST(ScsiControllerTest, BusFree)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::busfree);
controller.BusFree();
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
controller.SetStatus(status::CHECK_CONDITION);
controller.SetStatus(status::check_condition);
controller.SetPhase(phase_t::reserved);
controller.BusFree();
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
EXPECT_EQ(status::GOOD, controller.GetStatus());
EXPECT_EQ(status::good, controller.GetStatus());
controller.ScheduleShutdown(AbstractController::piscsi_shutdown_mode::NONE);
controller.SetPhase(phase_t::reserved);
@@ -86,14 +81,13 @@ TEST(ScsiControllerTest, BusFree)
controller.ScheduleShutdown(AbstractController::piscsi_shutdown_mode::STOP_PISCSI);
controller.SetPhase(phase_t::reserved);
EXPECT_EXIT(controller.BusFree(), ExitedWithCode(EXIT_SUCCESS), "");
controller.BusFree();
}
TEST(ScsiControllerTest, Selection)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockScsiController>(controller_manager, 0);
auto controller = make_shared<MockScsiController>(bus, 0);
controller->SetPhase(phase_t::selection);
ON_CALL(*bus, GetSEL).WillByDefault(Return(true));
@@ -130,17 +124,7 @@ TEST(ScsiControllerTest, Selection)
controller->Selection();
EXPECT_EQ(phase_t::msgout, controller->GetPhase());
controller->SetPhase(phase_t::reserved);
ON_CALL(*bus, GetDAT).WillByDefault(Return(0));
controller->Selection();
EXPECT_EQ(phase_t::reserved, controller->GetPhase());
ON_CALL(*bus, GetDAT).WillByDefault(Return(1));
controller->Selection();
EXPECT_EQ(phase_t::reserved, controller->GetPhase()) << "There is no device that can be selected";
auto device = make_shared<MockPrimaryDevice>(0);
controller->AddDevice(device);
EXPECT_CALL(*bus, SetBSY(true));
controller->Selection();
EXPECT_EQ(phase_t::selection, controller->GetPhase());
@@ -149,8 +133,7 @@ TEST(ScsiControllerTest, Selection)
TEST(ScsiControllerTest, Command)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::command);
EXPECT_CALL(controller, Status);
@@ -177,8 +160,7 @@ TEST(ScsiControllerTest, Command)
TEST(ScsiControllerTest, MsgIn)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::reserved);
EXPECT_CALL(*bus, SetMSG(true));
@@ -193,8 +175,7 @@ TEST(ScsiControllerTest, MsgIn)
TEST(ScsiControllerTest, MsgOut)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::reserved);
EXPECT_CALL(*bus, SetMSG(true));
@@ -209,8 +190,7 @@ TEST(ScsiControllerTest, MsgOut)
TEST(ScsiControllerTest, DataIn)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::reserved);
controller.SetLength(0);
@@ -230,8 +210,7 @@ TEST(ScsiControllerTest, DataIn)
TEST(ScsiControllerTest, DataOut)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
controller.SetPhase(phase_t::reserved);
controller.SetLength(0);
@@ -251,66 +230,58 @@ TEST(ScsiControllerTest, DataOut)
TEST(ScsiControllerTest, Error)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
MockScsiController controller(controller_manager, 0);
MockScsiController controller(bus, 0);
ON_CALL(*bus, GetRST).WillByDefault(Return(true));
controller.SetPhase(phase_t::reserved);
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST());
EXPECT_CALL(*bus, Reset);
EXPECT_CALL(controller, Reset);
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
EXPECT_EQ(status::GOOD, controller.GetStatus());
controller.Error(sense_key::aborted_command, asc::no_additional_sense_information, status::reservation_conflict);
EXPECT_EQ(status::good, controller.GetStatus());
EXPECT_EQ(phase_t::reserved, controller.GetPhase());
ON_CALL(*bus, GetRST).WillByDefault(Return(false));
controller.SetPhase(phase_t::status);
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST());
EXPECT_CALL(*bus, Reset).Times(0);
EXPECT_CALL(controller, Reset).Times(0);
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
controller.Error(sense_key::aborted_command, asc::no_additional_sense_information, status::reservation_conflict);
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
controller.SetPhase(phase_t::msgin);
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST());
EXPECT_CALL(*bus, Reset).Times(0);
EXPECT_CALL(controller, Reset).Times(0);
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
controller.Error(sense_key::aborted_command, asc::no_additional_sense_information, status::reservation_conflict);
EXPECT_EQ(phase_t::busfree, controller.GetPhase());
controller.SetPhase(phase_t::reserved);
EXPECT_CALL(*bus, Acquire);
EXPECT_CALL(*bus, GetRST());
EXPECT_CALL(*bus, Reset).Times(0);
EXPECT_CALL(controller, Reset).Times(0);
EXPECT_CALL(controller, Status);
controller.Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION, status::RESERVATION_CONFLICT);
EXPECT_EQ(status::RESERVATION_CONFLICT, controller.GetStatus());
controller.Error(sense_key::aborted_command, asc::no_additional_sense_information, status::reservation_conflict);
EXPECT_EQ(status::reservation_conflict, controller.GetStatus());
EXPECT_EQ(phase_t::reserved, controller.GetPhase());
}
TEST(ScsiControllerTest, RequestSense)
{
auto bus = make_shared<NiceMock<MockBus>>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockScsiController>(controller_manager, 0);
auto controller = make_shared<MockScsiController>(bus, 0);
auto device = make_shared<MockPrimaryDevice>(0);
const unordered_map<string, string> params;
device->Init(params);
EXPECT_TRUE(device->Init({}));
controller->AddDevice(device);
auto& cmd = controller->GetCmd();
// ALLOCATION LENGTH
cmd[4] = 255;
controller->SetCmdByte(4, 255);
// Non-existing LUN
cmd[1] = 0x20;
controller->SetCmdByte(1, 0x20);
device->SetReady(true);
EXPECT_CALL(*controller, Status);
device->Dispatch(scsi_command::eCmdRequestSense);
EXPECT_EQ(status::GOOD, controller->GetStatus()) << "Wrong CHECK CONDITION for non-existing LUN";
EXPECT_EQ(status::good, controller->GetStatus()) << "Wrong CHECK CONDITION for non-existing LUN";
}
+80 -114
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -13,202 +13,168 @@
TEST(ScsiDaynaportTest, Inquiry)
{
TestInquiry(SCDP, device_type::PROCESSOR, scsi_level::SCSI_2, "Dayna SCSI/Link 1.4a", 0x20, false);
TestInquiry::Inquiry(SCDP, device_type::processor, scsi_level::scsi_2, "Dayna SCSI/Link 1.4a", 0x20, false);
}
TEST(ScsiDaynaportTest, TestUnitReady)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto [controller, daynaport] = CreateDevice(SCDP);
EXPECT_CALL(*controller, Status());
daynaport->Dispatch(scsi_command::eCmdTestUnitReady);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(ScsiDaynaportTest, Read)
{
vector<uint8_t> buf(0);
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = dynamic_pointer_cast<SCSIDaynaPort>(CreateDevice(SCDP, *controller));
auto& cmd = controller->GetCmd();
auto [controller, daynaport] = CreateDevice(SCDP);
// ALLOCATION LENGTH
cmd[4] = 1;
EXPECT_EQ(0, daynaport->Read(cmd, buf, 0)) << "Trying to read the root sector must fail";
controller->SetCmdByte(4, 1);
vector<uint8_t> buf(0);
EXPECT_EQ(0, dynamic_pointer_cast<SCSIDaynaPort>(daynaport)->Read(controller->GetCmd(), buf, 0)) << "Trying to read the root sector must fail";
}
TEST(ScsiDaynaportTest, WriteBytes)
TEST(ScsiDaynaportTest, Write)
{
vector<uint8_t> buf(0);
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = dynamic_pointer_cast<SCSIDaynaPort>(CreateDevice(SCDP, *controller));
auto& cmd = controller->GetCmd();
auto [controller, daynaport] = CreateDevice(SCDP);
// Unknown data format
cmd[5] = 0xff;
EXPECT_TRUE(daynaport->WriteBytes(cmd, buf, 0));
controller->SetCmdByte(5, 0xff);
vector<uint8_t> buf(0);
EXPECT_TRUE(dynamic_pointer_cast<SCSIDaynaPort>(daynaport)->Write(controller->GetCmd(), buf));
}
TEST(ScsiDaynaportTest, Read6)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto [controller, daynaport] = CreateDevice(SCDP);
// Required by the bullseye clang++ compiler
auto d = daynaport;
auto& cmd = controller->GetCmd();
cmd[5] = 0xff;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdRead6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(5, 0xff);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdRead6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Invalid data format";
}
TEST(ScsiDaynaportTest, Write6)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto [controller, daynaport] = CreateDevice(SCDP);
// Required by the bullseye clang++ compiler
auto d = daynaport;
auto& cmd = controller->GetCmd();
cmd[5] = 0x00;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdWrite6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(5, 0x00);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdWrite6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Invalid transfer length";
cmd[3] = -1;
cmd[4] = -8;
cmd[5] = 0x80;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdWrite6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(3, -1);
controller->SetCmdByte(4, -8);
controller->SetCmdByte(5, 0x08);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdWrite6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Invalid transfer length";
cmd[3] = 0;
cmd[4] = 0;
cmd[5] = 0xff;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdWrite6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(3, 0);
controller->SetCmdByte(4, 0);
controller->SetCmdByte(5, 0xff);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdWrite6); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Invalid transfer length";
}
TEST(ScsiDaynaportTest, TestRetrieveStats)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto& cmd = controller->GetCmd();
auto [controller, daynaport] = CreateDevice(SCDP);
// ALLOCATION LENGTH
cmd[4] = 255;
controller->SetCmdByte(4, 255);
EXPECT_CALL(*controller, DataIn());
daynaport->Dispatch(scsi_command::eCmdRetrieveStats);
}
TEST(ScsiDaynaportTest, SetInterfaceMode)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto& cmd = controller->GetCmd();
auto [controller, daynaport] = CreateDevice(SCDP);
// Required by the bullseye clang++ compiler
auto d = daynaport;
// Unknown interface command
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_COMMAND_OPERATION_CODE))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_command_operation_code))));
// Not implemented, do nothing
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_SETMODE;
controller->SetCmdByte(5, SCSIDaynaPort::CMD_SCSILINK_SETMODE);
EXPECT_CALL(*controller, Status());
daynaport->Dispatch(scsi_command::eCmdSetIfaceMode);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_SETMAC;
controller->SetCmdByte(5, SCSIDaynaPort::CMD_SCSILINK_SETMAC);
EXPECT_CALL(*controller, DataOut());
daynaport->Dispatch(scsi_command::eCmdSetIfaceMode);
// Not implemented
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_STATS;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_COMMAND_OPERATION_CODE))));
controller->SetCmdByte(5, SCSIDaynaPort::CMD_SCSILINK_STATS);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_command_operation_code))));
// Not implemented
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_ENABLE;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_COMMAND_OPERATION_CODE))));
controller->SetCmdByte(5, SCSIDaynaPort::CMD_SCSILINK_ENABLE);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_command_operation_code))));
// Not implemented
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_SET;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_COMMAND_OPERATION_CODE))));
controller->SetCmdByte(5, SCSIDaynaPort::CMD_SCSILINK_SET);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSetIfaceMode); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_command_operation_code))));
}
TEST(ScsiDaynaportTest, SetMcastAddr)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto [controller, daynaport] = CreateDevice(SCDP);
// Required by the bullseye clang++ compiler
auto d = daynaport;
auto& cmd = controller->GetCmd();
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdSetMcastAddr); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdSetMcastAddr); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Length of 0 is not supported";
cmd[4] = 1;
controller->SetCmdByte(4, 1);
EXPECT_CALL(*controller, DataOut());
daynaport->Dispatch(scsi_command::eCmdSetMcastAddr);
}
TEST(ScsiDaynaportTest, EnableInterface)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto daynaport = CreateDevice(SCDP, *controller);
auto& cmd = controller->GetCmd();
auto [controller, daynaport] = CreateDevice(SCDP);
// Required by the bullseye clang++ compiler
auto d = daynaport;
// Enable
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdEnableInterface); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))));
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdEnableInterface); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::aborted_command),
Property(&scsi_exception::get_asc, asc::no_additional_sense_information))));
// Disable
cmd[5] = 0x80;
EXPECT_THAT([&] { daynaport->Dispatch(scsi_command::eCmdEnableInterface); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))));
controller->SetCmdByte(5, 0x00);
EXPECT_THAT([&] { d->Dispatch(scsi_command::eCmdEnableInterface); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::aborted_command),
Property(&scsi_exception::get_asc, asc::no_additional_sense_information))));
}
TEST(ScsiDaynaportTest, GetSendDelay)
{
SCSIDaynaPort daynaport(0);
const unordered_map<string, string> params;
daynaport.Init(params);
daynaport.Init({});
EXPECT_EQ(6, daynaport.GetSendDelay());
}
+2 -2
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -11,5 +11,5 @@
TEST(ScsiHostBridgeTest, Inquiry)
{
TestInquiry(SCBR, device_type::COMMUNICATIONS, scsi_level::SCSI_2, "PiSCSI RASCSI BRIDGE ", 0x27, false);
TestInquiry::Inquiry(SCBR, device_type::communications, scsi_level::scsi_2, "PiSCSI RASCSI BRIDGE ", 0x27, false);
}
+32 -59
View File
@@ -3,27 +3,22 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "controllers/controller_manager.h"
#include "devices/scsi_printer.h"
using namespace std;
TEST(ScsiPrinterTest, Init)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
unordered_map<string, string> params;
EXPECT_TRUE(printer->Init(params));
auto [controller, printer] = CreateDevice(SCLP);
EXPECT_TRUE(printer->Init({}));
param_map params;
params["cmd"] = "missing_filename_specifier";
EXPECT_FALSE(printer->Init(params));
@@ -33,99 +28,80 @@ TEST(ScsiPrinterTest, Init)
TEST(ScsiPrinterTest, TestUnitReady)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
EXPECT_CALL(*controller, Status());
printer->Dispatch(scsi_command::eCmdTestUnitReady);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(ScsiPrinterTest, Inquiry)
{
TestInquiry(SCLP, device_type::PRINTER, scsi_level::SCSI_2, "PiSCSI SCSI PRINTER ", 0x1f, false);
TestInquiry::Inquiry(SCLP, device_type::printer, scsi_level::scsi_2, "PiSCSI SCSI PRINTER ", 0x1f, false);
}
TEST(ScsiPrinterTest, ReserveUnit)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
EXPECT_CALL(*controller, Status()).Times(1);
printer->Dispatch(scsi_command::eCmdReserve6);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(ScsiPrinterTest, ReleaseUnit)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
EXPECT_CALL(*controller, Status()).Times(1);
printer->Dispatch(scsi_command::eCmdRelease6);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(ScsiPrinterTest, SendDiagnostic)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
EXPECT_CALL(*controller, Status()).Times(1);
printer->Dispatch(scsi_command::eCmdSendDiagnostic);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(ScsiPrinterTest, Print)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto& cmd = controller->GetCmd();
auto [controller, printer] = CreateDevice(SCLP);
// Required by the bullseye clang++ compiler
auto p = printer;
EXPECT_CALL(*controller, DataOut());
printer->Dispatch(scsi_command::eCmdPrint);
cmd[3] = 0xff;
cmd[4] = 0xff;
EXPECT_THAT([&] { printer->Dispatch(scsi_command::eCmdPrint); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_CDB))))
controller->SetCmdByte(3, 0xff);
controller->SetCmdByte(4, 0xff);
EXPECT_THAT([&] { p->Dispatch(scsi_command::eCmdPrint); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_cdb))))
<< "Buffer overflow was not reported";
}
TEST(ScsiPrinterTest, StopPrint)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
EXPECT_CALL(*controller, Status());
printer->Dispatch(scsi_command::eCmdStopPrint);
EXPECT_EQ(status::GOOD, controller->GetStatus());
EXPECT_EQ(status::good, controller->GetStatus());
}
TEST(ScsiPrinterTest, SynchronizeBuffer)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
// Required by the bullseye clang++ compiler
auto p = printer;
EXPECT_THAT([&] { printer->Dispatch(scsi_command::eCmdSynchronizeBuffer); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ABORTED_COMMAND),
Property(&scsi_exception::get_asc, asc::NO_ADDITIONAL_SENSE_INFORMATION))))
EXPECT_THAT([&] { p->Dispatch(scsi_command::eCmdSynchronizeBuffer); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::aborted_command),
Property(&scsi_exception::get_asc, asc::no_additional_sense_information))))
<< "Nothing to print";
// Further testing would use the printing system
@@ -133,11 +109,8 @@ TEST(ScsiPrinterTest, SynchronizeBuffer)
TEST(ScsiPrinterTest, WriteByteSequence)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto printer = CreateDevice(SCLP, *controller);
auto [controller, printer] = CreateDevice(SCLP);
vector<uint8_t> buf(1);
EXPECT_TRUE(printer->WriteByteSequence(buf, buf.size()));
const vector<uint8_t> buf(1);
EXPECT_TRUE(printer->WriteByteSequence(buf));
}
+12 -17
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -29,16 +29,15 @@ void ScsiCdTest_SetUpModePages(map<int, vector<byte>>& pages)
TEST(ScsiCdTest, Inquiry)
{
TestInquiry(SCCD, device_type::CD_ROM, scsi_level::SCSI_2, "PiSCSI SCSI CD-ROM ", 0x1f, true);
TestInquiry::Inquiry(SCCD, device_type::cd_rom, scsi_level::scsi_2, "PiSCSI SCSI CD-ROM ", 0x1f, true);
TestInquiry(SCCD, device_type::CD_ROM, scsi_level::SCSI_1_CCS, "PiSCSI SCSI CD-ROM ", 0x1f, true, ".is1");
TestInquiry::Inquiry(SCCD, device_type::cd_rom, scsi_level::scsi_1_ccs, "PiSCSI SCSI CD-ROM ", 0x1f, true, "file.is1");
}
TEST(ScsiCdTest, SetUpModePages)
{
map<int, vector<byte>> pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSICD cd(0, sector_sizes);
MockSCSICD cd(0, {});
// Non changeable
cd.SetUpModePages(pages, 0x3f, false);
@@ -52,11 +51,10 @@ TEST(ScsiCdTest, SetUpModePages)
TEST(ScsiCdTest, Open)
{
const unordered_set<uint32_t> sector_sizes;
MockSCSICD cd_iso(0, sector_sizes);
MockSCSICD cd_cue(0, sector_sizes);
MockSCSICD cd_raw(0, sector_sizes);
MockSCSICD cd_physical(0, sector_sizes);
MockSCSICD cd_iso(0, {});
MockSCSICD cd_cue(0, {});
MockSCSICD cd_raw(0, {});
MockSCSICD cd_physical(0, {});
EXPECT_THROW(cd_iso.Open(), io_exception) << "Missing filename";
@@ -112,19 +110,16 @@ TEST(ScsiCdTest, Open)
TEST(ScsiCdTest, ReadToc)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<MockAbstractController>(controller_manager, 0);
auto controller = make_shared<MockAbstractController>();
const unordered_set<uint32_t> sector_sizes;
auto cd = make_shared<MockSCSICD>(0, sector_sizes);
const unordered_map<string, string> params;
cd->Init(params);
EXPECT_TRUE(cd->Init({}));
controller->AddDevice(cd);
EXPECT_THAT([&] { cd->Dispatch(scsi_command::eCmdReadToc); }, Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::NOT_READY),
Property(&scsi_exception::get_asc, asc::MEDIUM_NOT_PRESENT))));
Property(&scsi_exception::get_sense_key, sense_key::not_ready),
Property(&scsi_exception::get_asc, asc::medium_not_present))));
// Further testing requires filesystem access
}
+4 -1
View File
@@ -92,8 +92,11 @@ TEST(ScsictlCommandsTest, Execute)
command.set_operation(OPERATION_INFO);
EXPECT_THROW(commands.Execute("", "", "", "", ""), io_exception);
command.set_operation(NO_OPERATION);
command.set_operation(DETACH_ALL);
EXPECT_THROW(commands.Execute("", "", "", "", ""), io_exception);
command.set_operation(NO_OPERATION);
EXPECT_FALSE(commands.Execute("", "", "", "", ""));
}
TEST(ScsictlCommandsTest, CommandDevicesInfo)
+4 -5
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
// These tests only test key aspects of the expected output, because the output may change over time.
//
@@ -51,10 +51,9 @@ TEST(ScsictlDisplayTest, DisplayDeviceInfo)
EXPECT_NE(string::npos, s.find(to_string(1234 *4321)));
device.mutable_properties()->set_supports_file(true);
auto file = make_unique<PbImageFile>();
auto file = device.mutable_file();
file->set_name("filename");
device.set_allocated_file(file.release());
s = display.DisplayDeviceInfo(device); //NOSONAR The allocated memory is managed by protobuf
s = display.DisplayDeviceInfo(device);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("filename"));
@@ -154,7 +153,7 @@ TEST(ScsictlDisplayTest, DisplayReservedIdsInfo)
PbReservedIdsInfo info;
string s = display.DisplayReservedIdsInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_TRUE(s.empty());
info.mutable_ids()->Add(5);
s = display.DisplayReservedIdsInfo(info);
+10 -11
View File
@@ -9,7 +9,6 @@
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "controllers/controller_manager.h"
#include "devices/scsihd_nec.h"
#include <filesystem>
#include <fstream>
@@ -29,7 +28,7 @@ void ScsiHdNecTest_SetUpModePages(map<int, vector<byte>>& pages)
TEST(ScsiHdNecTest, Inquiry)
{
TestInquiry(SCHD, device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, "PiSCSI ", 0x1f, false, ".hdn");
TestInquiry::Inquiry(SCHD, device_type::direct_access, scsi_level::scsi_1_ccs, "PiSCSI ", 0x1f, false, "file.hdn");
}
TEST(ScsiHdNecTest, SetUpModePages)
@@ -134,19 +133,19 @@ TEST(ScsiHdNecTest, SetParameters)
ofstream out;
out.open(hdi);
const array<char, 4> cylinders1 = { 1, 0, 0, 0 };
const array<const char, 4> cylinders1 = { 1, 0, 0, 0 };
out.seekp(28);
out.write(cylinders1.data(), cylinders1.size());
const array<char, 4> heads1 = { 1, 0, 0, 0 };
const array<const char, 4> heads1 = { 1, 0, 0, 0 };
out.seekp(24);
out.write(heads1.data(), heads1.size());
const array<char, 4> sectors1 = { 1, 0, 0, 0 };
const array<const char, 4> sectors1 = { 1, 0, 0, 0 };
out.seekp(20);
out.write(sectors1.data(), sectors1.size());
const array<char, 4> sector_size1 = { 0, 2, 0, 0 };
const array<const char, 4> sector_size1 = { 0, 2, 0, 0 };
out.seekp(16);
out.write(sector_size1.data(), sector_size1.size());
const array<char, 4> image_size = { 0, 2, 0, 0 };
const array<const char, 4> image_size = { 0, 2, 0, 0 };
out.seekp(12);
out.write(image_size.data(), image_size.size());
out.close();
@@ -179,18 +178,18 @@ TEST(ScsiHdNecTest, SetParameters)
out.open(nhd);
out << "T98HDDIMAGE.R0";
const array<char, 2> cylinders2 = { 1, 0 };
const array<const char, 2> cylinders2 = { 1, 0 };
out.seekp(0x114);
out.write(cylinders2.data(), cylinders2.size());
const array<char, 2> heads2 = { 1, 0 };
const array<const char, 2> heads2 = { 1, 0 };
out.seekp(0x118);
out.write(heads2.data(), heads2.size());
const array<char, 2> sectors2 = { 1, 0 };
const array<const char, 2> sectors2 = { 1, 0 };
out.seekp(0x11a);
out.write(sectors2.data(), sectors2.size());
out.seekp(0x11c);
out.write(sector_size2.data(), sector_size2.size());
const array<char, 4> image_offset = { 1, 0, 0, 0 };
const array<const char, 4> image_offset = { 1, 0, 0, 0 };
out.seekp(0x110);
out.write(image_offset.data(), image_offset.size());
out.close();
+10 -15
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -23,23 +23,21 @@ void ScsiHdTest_SetUpModePages(map<int, vector<byte>>& pages)
TEST(ScsiHdTest, Inquiry)
{
TestInquiry(SCHD, device_type::DIRECT_ACCESS, scsi_level::SCSI_2, "PiSCSI ", 0x1f, false);
TestInquiry::Inquiry(SCHD, device_type::direct_access, scsi_level::scsi_2, "PiSCSI ", 0x1f, false);
TestInquiry(SCHD, device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, "PiSCSI ", 0x1f, false, ".hd1");
TestInquiry::Inquiry(SCHD, device_type::direct_access, scsi_level::scsi_1_ccs, "PiSCSI ", 0x1f, false, "file.hd1");
}
TEST(ScsiHdTest, SupportsSaveParameters)
{
const unordered_set<uint32_t> sector_sizes;
MockSCSIHD hd(0, sector_sizes, false);
MockSCSIHD hd(0, {}, false);
EXPECT_TRUE(hd.SupportsSaveParameters());
}
TEST(ScsiHdTest, FinalizeSetup)
{
const unordered_set<uint32_t> sector_sizes;
MockSCSIHD hd(0, sector_sizes, false);
MockSCSIHD hd(0, {}, false);
hd.SetSectorSizeInBytes(1024);
EXPECT_THROW(hd.FinalizeSetup(0), io_exception) << "Device has 0 blocks";
@@ -47,10 +45,9 @@ TEST(ScsiHdTest, FinalizeSetup)
TEST(ScsiHdTest, GetProductData)
{
const unordered_set<uint32_t> sector_sizes;
MockSCSIHD hd_kb(0, sector_sizes, false);
MockSCSIHD hd_mb(0, sector_sizes, false);
MockSCSIHD hd_gb(0, sector_sizes, false);
MockSCSIHD hd_kb(0, {}, false);
MockSCSIHD hd_mb(0, {}, false);
MockSCSIHD hd_gb(0, {}, false);
const path filename = CreateTempFile(1);
hd_kb.SetFilename(string(filename));
@@ -79,8 +76,7 @@ TEST(ScsiHdTest, GetProductData)
TEST(ScsiHdTest, SetUpModePages)
{
map<int, vector<byte>> pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSIHD hd(0, sector_sizes, false);
MockSCSIHD hd(0, {}, false);
// Non changeable
hd.SetUpModePages(pages, 0x3f, false);
@@ -94,8 +90,7 @@ TEST(ScsiHdTest, SetUpModePages)
TEST(ScsiHdTest, ModeSelect)
{
const unordered_set<uint32_t> sector_sizes = { 512 };
MockSCSIHD hd(0, sector_sizes, false);
MockSCSIHD hd(0, { 512 }, false);
vector<int> cmd(10);
vector<uint8_t> buf(255);
+6 -10
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -22,14 +22,13 @@ void ScsiMo_SetUpModePages(map<int, vector<byte>>& pages)
TEST(ScsiMoTest, Inquiry)
{
TestInquiry(SCMO, device_type::OPTICAL_MEMORY, scsi_level::SCSI_2, "PiSCSI SCSI MO ", 0x1f, true);
TestInquiry::Inquiry(SCMO, device_type::optical_memory, scsi_level::scsi_2, "PiSCSI SCSI MO ", 0x1f, true);
}
TEST(ScsiMoTest, SupportsSaveParameters)
{
map<int, vector<byte>> pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSIMO mo(0, sector_sizes);
MockSCSIMO mo(0, {});
EXPECT_TRUE(mo.SupportsSaveParameters());
}
@@ -37,8 +36,7 @@ TEST(ScsiMoTest, SupportsSaveParameters)
TEST(ScsiMoTest, SetUpModePages)
{
map<int, vector<byte>> pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSIMO mo(0, sector_sizes);
MockSCSIMO mo(0, {});
// Non changeable
mo.SetUpModePages(pages, 0x3f, false);
@@ -53,8 +51,7 @@ TEST(ScsiMoTest, SetUpModePages)
TEST(ScsiMoTest, TestAddVendorPage)
{
map<int, vector<byte>> pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSIMO mo(0, sector_sizes);
MockSCSIMO mo(0, {});
mo.SetReady(true);
mo.SetUpModePages(pages, 0x21, false);
@@ -125,8 +122,7 @@ TEST(ScsiMoTest, TestAddVendorPage)
TEST(ScsiMoTest, ModeSelect)
{
const unordered_set<uint32_t> sector_sizes = { 1024, 2048 };
MockSCSIMO mo(0, sector_sizes);
MockSCSIMO mo(0, { 1024, 2048 });
vector<int> cmd(10);
vector<uint8_t> buf(255);
+36 -26
View File
@@ -3,18 +3,19 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/piscsi_util.h"
#include "shared/piscsi_exceptions.h"
#include "devices/storage_device.h"
#include <filesystem>
using namespace filesystem;
TEST(StorageDeviceTest, Filename)
TEST(StorageDeviceTest, SetGetFilename)
{
MockStorageDevice device;
@@ -62,6 +63,8 @@ TEST(StorageDeviceTest, MediumChanged)
{
MockStorageDevice device;
EXPECT_FALSE(device.IsMediumChanged());
device.SetMediumChanged(true);
EXPECT_TRUE(device.IsMediumChanged());
@@ -72,22 +75,26 @@ TEST(StorageDeviceTest, MediumChanged)
TEST(StorageDeviceTest, GetIdsForReservedFile)
{
const int ID = 1;
const int LUN = 2;
const int LUN = 0;
auto bus = make_shared<MockBus>();
ControllerManager controller_manager;
MockAbstractController controller(bus, ID);
auto device = make_shared<MockSCSIHD_NEC>(LUN);
device->SetFilename("filename");
StorageDevice::UnreserveAll();
MockStorageDevice device;
device.SetFilename("filename");
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device));
const auto [id1, lun1] = StorageDevice::GetIdsForReservedFile("filename");
EXPECT_EQ(-1, id1);
EXPECT_EQ(-1, lun1);
device.ReserveFile("filename", ID, LUN);
device->ReserveFile();
const auto [id2, lun2] = StorageDevice::GetIdsForReservedFile("filename");
EXPECT_EQ(ID, id2);
EXPECT_EQ(LUN, lun2);
device.UnreserveFile();
device->UnreserveFile();
const auto [id3, lun3] = StorageDevice::GetIdsForReservedFile("filename");
EXPECT_EQ(-1, id3);
EXPECT_EQ(-1, lun3);
@@ -95,9 +102,17 @@ TEST(StorageDeviceTest, GetIdsForReservedFile)
TEST(StorageDeviceTest, UnreserveAll)
{
MockStorageDevice device;
device.ReserveFile("filename", 2, 31);
const int ID = 1;
const int LUN = 0;
auto bus = make_shared<MockBus>();
ControllerManager controller_manager;
MockAbstractController controller(bus, ID);
auto device = make_shared<MockSCSIHD_NEC>(LUN);
device->SetFilename("filename");
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device));
device->ReserveFile();
StorageDevice::UnreserveAll();
const auto [id, lun] = StorageDevice::GetIdsForReservedFile("filename");
EXPECT_EQ(-1, id);
@@ -107,18 +122,24 @@ TEST(StorageDeviceTest, UnreserveAll)
TEST(StorageDeviceTest, GetSetReservedFiles)
{
const int ID = 1;
const int LUN = 16;
const int LUN = 0;
auto bus = make_shared<MockBus>();
ControllerManager controller_manager;
MockAbstractController controller(bus, ID);
auto device = make_shared<MockSCSIHD_NEC>(LUN);
device->SetFilename("filename");
MockStorageDevice device;
device.ReserveFile("filename", ID, LUN);
EXPECT_TRUE(controller_manager.AttachToController(*bus, ID, device));
const unordered_map<string, id_set> reserved_files = StorageDevice::GetReservedFiles();
device->ReserveFile();
const auto& reserved_files = StorageDevice::GetReservedFiles();
EXPECT_EQ(1, reserved_files.size());
EXPECT_NE(reserved_files.end(), reserved_files.find("filename"));
EXPECT_TRUE(reserved_files.contains("filename"));
StorageDevice::SetReservedFiles(reserved_files);
EXPECT_EQ(1, reserved_files.size());
EXPECT_NE(reserved_files.end(), reserved_files.find("filename"));
EXPECT_TRUE(reserved_files.contains("filename"));
}
TEST(StorageDeviceTest, FileExists)
@@ -127,17 +148,6 @@ TEST(StorageDeviceTest, FileExists)
EXPECT_TRUE(StorageDevice::FileExists("/dev/null"));
}
TEST(StorageDeviceTest, IsReadOnlyFile)
{
MockStorageDevice device;
device.SetFilename("/dev/null");
EXPECT_FALSE(device.IsReadOnlyFile());
device.SetFilename("/dev/mem");
EXPECT_TRUE(device.IsReadOnlyFile());
}
TEST(StorageDeviceTest, GetFileSize)
{
MockStorageDevice device;
+18 -19
View File
@@ -3,35 +3,34 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <gtest/gtest.h>
#include "spdlog/spdlog.h"
// Also used by the PiscsiExecutor tests
bool enable_logging; //NOSONAR Must be global in order to be shared with the tests
class Environment final : public ::testing::Environment
{
public:
Environment() = default;
~Environment() override = default;
void SetUp() override { spdlog::set_level(enable_logging ? spdlog::level::trace : spdlog::level::off); }
};
#include <spdlog/spdlog.h>
int main(int argc, char *[])
{
// If any argument is provided the log level is set to trace
enable_logging = argc > 1;
const bool disable_logging = argc <= 1;
testing::AddGlobalTestEnvironment(new Environment());
// If any argument is provided the log level is set to trace
spdlog::set_level(disable_logging ? spdlog::level::off : spdlog::level::trace);
int fd = -1;
if (disable_logging) {
fd = open("/dev/null", O_WRONLY);
dup2(fd, STDERR_FILENO);
}
testing::InitGoogleTest();
return RUN_ALL_TESTS();
const int result = RUN_ALL_TESTS();
if (fd != -1) {
close(fd);
}
return result;
}
+22 -23
View File
@@ -8,7 +8,6 @@
//---------------------------------------------------------------------------
#include "test_shared.h"
#include "controllers/controller_manager.h"
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "shared/piscsi_version.h"
@@ -28,38 +27,33 @@ const path test_data_temp_path(temp_directory_path() /
path(fmt::format("piscsi-test-{}",
getpid()))); // NOSONAR Publicly writable directory is fine here
shared_ptr<PrimaryDevice> CreateDevice(PbDeviceType type, MockAbstractController& controller, const string& extension)
pair<shared_ptr<MockAbstractController>, shared_ptr<PrimaryDevice>> CreateDevice(PbDeviceType type, const string& extension)
{
DeviceFactory device_factory;
auto controller = make_shared<NiceMock<MockAbstractController>>(0);
auto device = device_factory.CreateDevice(type, 0, extension);
unordered_map<string, string> params;
device->Init(params);
device->Init({});
controller.AddDevice(device);
EXPECT_TRUE(controller->AddDevice(device));
return device;
return { controller, device };
}
void TestInquiry(PbDeviceType type, device_type t, scsi_level l, const string& ident, int additional_length,
bool removable, const string& extension)
void TestInquiry::Inquiry(PbDeviceType type, device_type t, scsi_level l, const string& ident, int additional_length,
bool removable, const string& extension)
{
auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus);
auto controller = make_shared<NiceMock<MockAbstractController>>(controller_manager, 0);
auto device = CreateDevice(type, *controller, extension);
auto& cmd = controller->GetCmd();
auto [controller, device] = CreateDevice(type, extension);
// ALLOCATION LENGTH
cmd[4] = 255;
controller->SetCmdByte(4, 255);
EXPECT_CALL(*controller, DataIn());
device->Dispatch(scsi_command::eCmdInquiry);
const vector<uint8_t>& buffer = controller->GetBuffer();
EXPECT_EQ(t, static_cast<device_type>(buffer[0]));
EXPECT_EQ(removable ? 0x80 : 0x00, buffer[1]);
EXPECT_EQ(l, static_cast<scsi_level>(buffer[2]));
EXPECT_EQ(l > scsi_level::SCSI_2 ? scsi_level::SCSI_2 : l, static_cast<scsi_level>(buffer[3]));
EXPECT_EQ(l > scsi_level::scsi_2 ? scsi_level::scsi_2 : l, static_cast<scsi_level>(buffer[3]));
EXPECT_EQ(additional_length, buffer[4]);
string product_data;
if (ident.size() == 24) {
@@ -88,13 +82,18 @@ pair<int, path> OpenTempFile()
}
path CreateTempFile(int size)
{
const auto data = vector<byte>(size);
return CreateTempFileWithData(data);
}
path CreateTempFileWithData(const span<const byte> data)
{
const auto [fd, filename] = OpenTempFile();
vector<char> data(size);
const size_t count = write(fd, data.data(), data.size());
close(fd);
EXPECT_EQ(count, data.size()) << "Couldn't create temporary file '" << string(filename) << "'";
close(fd);
return path(filename);
}
@@ -110,14 +109,14 @@ void CreateTempFileWithData(const string& filename, vector<uint8_t>& data)
FILE* fp = fopen(new_filename.c_str(), "wb");
if (fp == nullptr) {
printf("ERROR: Unable to open file %s\n", new_filename.c_str());
cerr << "ERROR: Unable to open file '" << new_filename << "'";
return;
}
if (const size_t size_written = fwrite(&data[0], sizeof(uint8_t), data.size(), fp);
size_written != sizeof(vector<uint8_t>::value_type) * data.size()) {
printf("Expected to write %zu bytes, but only wrote %zu to %s", size_written,
sizeof(vector<uint8_t>::value_type) * data.size(), filename.c_str());
cerr << "ERROR: Expected to write " << sizeof(vector<uint8_t>::value_type) * data.size() << " bytes"
<< ", but only wrote " << data.size() << " to '" << filename << "'";
}
fclose(fp);
}
@@ -129,14 +128,14 @@ void DeleteTempFile(const string& filename)
remove(temp_file);
}
void CleanupAllTempFiles()
void CleanUpAllTempFiles()
{
remove_all(test_data_temp_path);
}
string ReadTempFileToString(const string& filename)
{
path temp_file = test_data_temp_path / path(filename);
const path temp_file = test_data_temp_path / path(filename);
ifstream in_fs(temp_file);
stringstream buffer;
buffer << in_fs.rdbuf();
+12 -6
View File
@@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
@@ -13,6 +13,7 @@
#include "shared/scsi.h"
#include <filesystem>
#include <memory>
#include <span>
#include <string>
using namespace std;
@@ -24,22 +25,27 @@ class MockAbstractController;
extern const path test_data_temp_path;
shared_ptr<PrimaryDevice> CreateDevice(PbDeviceType, MockAbstractController&, const string& = "");
void TestInquiry(PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level, const string&, int, bool,
const string& = "");
pair<shared_ptr<MockAbstractController>, shared_ptr<PrimaryDevice>> CreateDevice(PbDeviceType, const string& = "");
pair<int, path> OpenTempFile();
path CreateTempFile(int);
path CreateTempFileWithData(span<const byte>);
// create a file with the specified data
void CreateTempFileWithData(const string&, vector<uint8_t>&);
void DeleteTempFile(const string&);
// Call this at the end of every test case to make sure things are cleaned up
void CleanupAllTempFiles();
void CleanUpAllTempFiles();
string ReadTempFileToString(const string& filename);
int GetInt16(const vector<byte>&, int);
uint32_t GetInt32(const vector<byte>&, int);
// This class is needed in order to be declared as friend, required to have access to AbstractController::SetCmdByte
class TestInquiry {
public:
static void Inquiry(PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level, const string&, int, bool,
const string& = "");
};