mirror of
https://github.com/akuker/RASCSI.git
synced 2026-04-22 09:17:29 +00:00
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:
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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))));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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& = "");
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user