[guest] Add ro/rw/volatile variations of virtio block tests
TEST=fx run-tests guest_integration_tests
Change-Id: I9c2b6c6bcaded3a8147ed6b9c4fd4740a4fa601c
diff --git a/bin/guest/integration_tests/virtio_block_tests.cc b/bin/guest/integration_tests/virtio_block_tests.cc
index 482107f..224b352 100644
--- a/bin/guest/integration_tests/virtio_block_tests.cc
+++ b/bin/guest/integration_tests/virtio_block_tests.cc
@@ -29,14 +29,14 @@
static constexpr uint32_t kVirtioQcowBlockCount = 4 * 1024 * 1024 * 2;
static constexpr uint32_t kVirtioTestStep = 8;
-class ZirconRamdiskGuestTest : public GuestTest<ZirconRamdiskGuestTest> {
+class ZirconReadOnlyRamdiskGuestTest : public GuestTest<ZirconReadOnlyRamdiskGuestTest> {
public:
static bool LaunchInfo(fuchsia::guest::LaunchInfo* launch_info) {
create_ramdisk(kBlockSectorSize, kVirtioBlockCount, ramdisk_path_);
launch_info->url = kZirconGuestUrl;
launch_info->args.push_back("--display=none");
launch_info->args.push_back("--cpus=1");
- launch_info->args.push_back(fxl::StringPrintf("--block=%s", ramdisk_path_));
+ launch_info->args.push_back(fxl::StringPrintf("--block=%s,ro", ramdisk_path_));
return true;
}
@@ -51,9 +51,9 @@
static char ramdisk_path_[PATH_MAX];
};
-char ZirconRamdiskGuestTest::ramdisk_path_[PATH_MAX] = "";
+char ZirconReadOnlyRamdiskGuestTest::ramdisk_path_[PATH_MAX] = "";
-TEST_F(ZirconRamdiskGuestTest, BlockDeviceExists) {
+TEST_F(ZirconReadOnlyRamdiskGuestTest, BlockDeviceExists) {
ASSERT_EQ(WaitForPkgfs(), ZX_OK);
std::string cmd = fxl::StringPrintf("run %s#%s check %lu %u", kTestUtilsUrl,
kVirtioBlockUtilCmx, kBlockSectorSize,
@@ -63,103 +63,328 @@
EXPECT_THAT(result, HasSubstr("PASS"));
}
-TEST_F(ZirconRamdiskGuestTest, Read) {
+TEST_F(ZirconReadOnlyRamdiskGuestTest, Read) {
ASSERT_EQ(WaitForPkgfs(), ZX_OK);
fbl::unique_fd fd(open(ramdisk_path_, O_RDWR));
ASSERT_TRUE(fd);
uint8_t data[kBlockSectorSize];
+ memset(data, 0xab, kBlockSectorSize);
for (off_t offset = 0; offset != kVirtioBlockCount;
offset += kVirtioTestStep) {
- memset(data, offset, kBlockSectorSize);
ASSERT_EQ(
pwrite(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
static_cast<ssize_t>(kBlockSectorSize));
std::string cmd = fxl::StringPrintf(
"run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
- kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset),
- static_cast<int>(offset));
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
std::string result;
EXPECT_EQ(Execute(cmd, &result), ZX_OK);
EXPECT_THAT(result, HasSubstr("PASS"));
}
}
-TEST_F(ZirconRamdiskGuestTest, Write) {
+TEST_F(ZirconReadOnlyRamdiskGuestTest, Write) {
ASSERT_EQ(WaitForPkgfs(), ZX_OK);
fbl::unique_fd fd(open(ramdisk_path_, O_RDWR));
ASSERT_TRUE(fd);
uint8_t data[kBlockSectorSize];
+ memset(data, 0, kBlockSectorSize);
for (off_t offset = 0; offset != kVirtioBlockCount;
offset += kVirtioTestStep) {
+ // Write the block to zero.
+ ASSERT_EQ(
+ pwrite(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+
+ // Tell the guest to write bytes to the block.
std::string cmd = fxl::StringPrintf(
"run %s#%s write %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
- kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset),
- static_cast<int>(offset));
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
std::string result;
EXPECT_EQ(Execute(cmd, &result), ZX_OK);
EXPECT_THAT(result, HasSubstr("PASS"));
+
+ // Check that the guest reads zero from the block (i.e. it wasn't written).
+ cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0);
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ // Check that the ramdisk block contains only zero.
ASSERT_EQ(
pread(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
static_cast<ssize_t>(kBlockSectorSize));
for (off_t i = 0; i != kBlockSectorSize; ++i) {
- EXPECT_EQ(data[i], offset);
+ EXPECT_EQ(data[i], 0);
}
}
}
-class ZirconQcowGuestTest : public GuestTest<ZirconQcowGuestTest> {
+class ZirconReadWriteRamdiskGuestTest : public GuestTest<ZirconReadWriteRamdiskGuestTest> {
+ public:
+ static bool LaunchInfo(fuchsia::guest::LaunchInfo* launch_info) {
+ create_ramdisk(kBlockSectorSize, kVirtioBlockCount, ramdisk_path_);
+ launch_info->url = kZirconGuestUrl;
+ launch_info->args.push_back("--display=none");
+ launch_info->args.push_back("--cpus=1");
+ launch_info->args.push_back(fxl::StringPrintf("--block=%s,rw", ramdisk_path_));
+ return true;
+ }
+
+ static bool SetUpGuest() {
+ if (WaitForPkgfs() != ZX_OK) {
+ ADD_FAILURE() << "Failed to wait for pkgfs";
+ return false;
+ }
+ return true;
+ }
+
+ static char ramdisk_path_[PATH_MAX];
+};
+
+char ZirconReadWriteRamdiskGuestTest::ramdisk_path_[PATH_MAX] = "";
+
+TEST_F(ZirconReadWriteRamdiskGuestTest, BlockDeviceExists) {
+ ASSERT_EQ(WaitForPkgfs(), ZX_OK);
+ std::string cmd = fxl::StringPrintf("run %s#%s check %lu %u", kTestUtilsUrl,
+ kVirtioBlockUtilCmx, kBlockSectorSize,
+ kVirtioBlockCount);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+}
+
+TEST_F(ZirconReadWriteRamdiskGuestTest, Read) {
+ ASSERT_EQ(WaitForPkgfs(), ZX_OK);
+ fbl::unique_fd fd(open(ramdisk_path_, O_RDWR));
+ ASSERT_TRUE(fd);
+
+ uint8_t data[kBlockSectorSize];
+ memset(data, 0xab, kBlockSectorSize);
+ for (off_t offset = 0; offset != kVirtioBlockCount;
+ offset += kVirtioTestStep) {
+ ASSERT_EQ(
+ pwrite(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+ }
+}
+
+TEST_F(ZirconReadWriteRamdiskGuestTest, Write) {
+ ASSERT_EQ(WaitForPkgfs(), ZX_OK);
+ fbl::unique_fd fd(open(ramdisk_path_, O_RDWR));
+ ASSERT_TRUE(fd);
+
+ uint8_t data[kBlockSectorSize];
+ memset(data, 0, kBlockSectorSize);
+ for (off_t offset = 0; offset != kVirtioBlockCount;
+ offset += kVirtioTestStep) {
+ // Write the block to zero.
+ ASSERT_EQ(
+ pwrite(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+
+ // Tell the guest to write bytes to the block.
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s write %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ // Check that the guest reads the written bytes from the block.
+ cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ // Check that the ramdisk block contains the written bytes.
+ ASSERT_EQ(
+ pread(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+ for (off_t i = 0; i != kBlockSectorSize; ++i) {
+ EXPECT_EQ(data[i], 0xab);
+ }
+ }
+}
+
+class ZirconVolatileRamdiskGuestTest : public GuestTest<ZirconVolatileRamdiskGuestTest> {
+ public:
+ static bool LaunchInfo(fuchsia::guest::LaunchInfo* launch_info) {
+ create_ramdisk(kBlockSectorSize, kVirtioBlockCount, ramdisk_path_);
+ launch_info->url = kZirconGuestUrl;
+ launch_info->args.push_back("--display=none");
+ launch_info->args.push_back("--cpus=1");
+ launch_info->args.push_back(fxl::StringPrintf("--block=%s,volatile", ramdisk_path_));
+ return true;
+ }
+
+ static bool SetUpGuest() {
+ if (WaitForPkgfs() != ZX_OK) {
+ ADD_FAILURE() << "Failed to wait for pkgfs";
+ return false;
+ }
+ return true;
+ }
+
+ static char ramdisk_path_[PATH_MAX];
+};
+
+char ZirconVolatileRamdiskGuestTest::ramdisk_path_[PATH_MAX] = "";
+
+TEST_F(ZirconVolatileRamdiskGuestTest, BlockDeviceExists) {
+ ASSERT_EQ(WaitForPkgfs(), ZX_OK);
+ std::string cmd = fxl::StringPrintf("run %s#%s check %lu %u", kTestUtilsUrl,
+ kVirtioBlockUtilCmx, kBlockSectorSize,
+ kVirtioBlockCount);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+}
+
+TEST_F(ZirconVolatileRamdiskGuestTest, Read) {
+ ASSERT_EQ(WaitForPkgfs(), ZX_OK);
+ fbl::unique_fd fd(open(ramdisk_path_, O_RDWR));
+ ASSERT_TRUE(fd);
+
+ uint8_t data[kBlockSectorSize];
+ memset(data, 0xab, kBlockSectorSize);
+ for (off_t offset = 0; offset != kVirtioBlockCount;
+ offset += kVirtioTestStep) {
+ ASSERT_EQ(
+ pwrite(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+ }
+}
+
+TEST_F(ZirconVolatileRamdiskGuestTest, Write) {
+ ASSERT_EQ(WaitForPkgfs(), ZX_OK);
+ fbl::unique_fd fd(open(ramdisk_path_, O_RDWR));
+ ASSERT_TRUE(fd);
+
+ uint8_t data[kBlockSectorSize];
+ memset(data, 0, kBlockSectorSize);
+ for (off_t offset = 0; offset != kVirtioBlockCount;
+ offset += kVirtioTestStep) {
+ // Write the block to zero.
+ ASSERT_EQ(
+ pwrite(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+
+ // Tell the guest to write bytes to the block.
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s write %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ // Check that the guest reads the written bytes from the block.
+ cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioBlockCount, static_cast<int>(offset), 0xab);
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ // Check that the ramdisk block contains only zero (i.e. was not written).
+ ASSERT_EQ(
+ pread(fd.get(), &data, kBlockSectorSize, offset * kBlockSectorSize),
+ static_cast<ssize_t>(kBlockSectorSize));
+ for (off_t i = 0; i != kBlockSectorSize; ++i) {
+ EXPECT_EQ(data[i], 0);
+ }
+ }
+}
+
+template <typename T>
+static bool write_at(int fd, const T* ptr, off_t off) {
+ ssize_t written = pwrite(fd, ptr, sizeof(T), off);
+ return written == static_cast<ssize_t>(sizeof(T));
+}
+
+// Writes an array of T values at the current file location.
+template <typename T>
+static bool write_at(int fd, const T* ptr, size_t len, off_t off) {
+ ssize_t written = pwrite(fd, ptr, len * sizeof(T), off);
+ return written == static_cast<ssize_t>(len * sizeof(T));
+}
+
+
+static bool write_qcow_file(int fd) {
+ if (!fd) {
+ return false;
+ }
+
+ QcowHeader header = kDefaultHeaderV2.HostToBigEndian();
+ bool write_success = write_at(fd, &header, 0);
+ if (!write_success) {
+ return false;
+ }
+
+ // Convert L1 entries to big-endian
+ uint64_t be_table[countof(kL2TableClusterOffsets)];
+ for (size_t i = 0; i < countof(kL2TableClusterOffsets); ++i) {
+ be_table[i] = HostToBigEndianTraits::Convert(kL2TableClusterOffsets[i]);
+ }
+
+ // Write L1 table.
+ write_success = write_at(fd, be_table, countof(kL2TableClusterOffsets),
+ kDefaultHeaderV2.l1_table_offset);
+ if (!write_success) {
+ return false;
+ }
+
+ // Initialize empty L2 tables.
+ for (size_t i = 0; i < countof(kL2TableClusterOffsets); ++i) {
+ write_success = write_at(fd, kZeroCluster, sizeof(kZeroCluster),
+ kL2TableClusterOffsets[i]);
+ if (!write_success) {
+ return false;
+ }
+ }
+
+ // Write L2 entry
+ uint64_t l2_offset = kL2TableClusterOffsets[0];
+ uint64_t data_cluster_offset = ClusterOffset(kFirstDataCluster);
+ uint64_t l2_entry = HostToBigEndianTraits::Convert(data_cluster_offset);
+ write_success = write_at(fd, &l2_entry, l2_offset);
+ if (!write_success) {
+ return false;
+ }
+
+ // Write data to cluster.
+ uint8_t cluster_data[kClusterSize];
+ memset(cluster_data, 0xab, sizeof(cluster_data));
+ write_success =
+ write_at(fd, cluster_data, kClusterSize, data_cluster_offset);
+ if (!write_success) {
+ return false;
+ }
+
+ return true;
+}
+
+class ZirconReadOnlyQcowGuestTest : public GuestTest<ZirconReadOnlyQcowGuestTest> {
public:
static bool LaunchInfo(fuchsia::guest::LaunchInfo* launch_info) {
fbl::unique_fd fd(mkstemp(&qcow_path_[0]));
- if (!fd) {
- return false;
- }
-
- QcowHeader header = kDefaultHeaderV2.HostToBigEndian();
- bool write_success = WriteAt(fd.get(), &header, 0);
- if (!write_success) {
- return false;
- }
-
- // Convert L1 entries to big-endian
- uint64_t be_table[countof(kL2TableClusterOffsets)];
- for (size_t i = 0; i < countof(kL2TableClusterOffsets); ++i) {
- be_table[i] = HostToBigEndianTraits::Convert(kL2TableClusterOffsets[i]);
- }
-
- // Write L1 table.
- write_success = WriteAt(fd.get(), be_table, countof(kL2TableClusterOffsets),
- kDefaultHeaderV2.l1_table_offset);
- if (!write_success) {
- return false;
- }
-
- // Initialize empty L2 tables.
- for (size_t i = 0; i < countof(kL2TableClusterOffsets); ++i) {
- write_success = WriteAt(fd.get(), kZeroCluster, sizeof(kZeroCluster),
- kL2TableClusterOffsets[i]);
- if (!write_success) {
- return false;
- }
- }
-
- // Write L2 entry
- uint64_t l2_offset = kL2TableClusterOffsets[0];
- uint64_t data_cluster_offset = ClusterOffset(kFirstDataCluster);
- uint64_t l2_entry = HostToBigEndianTraits::Convert(data_cluster_offset);
- write_success = WriteAt(fd.get(), &l2_entry, l2_offset);
- if (!write_success) {
- return false;
- }
-
- // Write data to cluster.
- uint8_t cluster_data[kClusterSize];
- memset(cluster_data, 0xab, sizeof(cluster_data));
- write_success =
- WriteAt(fd.get(), cluster_data, kClusterSize, data_cluster_offset);
- if (!write_success) {
+ bool qcow_success = write_qcow_file(fd.get());
+ if (!qcow_success) {
return false;
}
@@ -179,25 +404,12 @@
return true;
}
- template <typename T>
- static bool WriteAt(int fd, const T* ptr, off_t off) {
- ssize_t written = pwrite(fd, ptr, sizeof(T), off);
- return written == static_cast<ssize_t>(sizeof(T));
- }
-
- // Writes an array of T values at the current file location.
- template <typename T>
- static bool WriteAt(int fd, const T* ptr, size_t len, off_t off) {
- ssize_t written = pwrite(fd, ptr, len * sizeof(T), off);
- return written == static_cast<ssize_t>(len * sizeof(T));
- }
-
static char qcow_path_[PATH_MAX];
};
-char ZirconQcowGuestTest::qcow_path_[PATH_MAX] = "/tmp/guest-test.XXXXXX";
+char ZirconReadOnlyQcowGuestTest::qcow_path_[PATH_MAX] = "/tmp/guest-test.XXXXXX";
-TEST_F(ZirconQcowGuestTest, BlockDeviceExists) {
+TEST_F(ZirconReadOnlyQcowGuestTest, BlockDeviceExists) {
std::string cmd = fxl::StringPrintf("run %s#%s check %lu %u", kTestUtilsUrl,
kVirtioBlockUtilCmx, kBlockSectorSize,
kVirtioQcowBlockCount);
@@ -206,7 +418,7 @@
EXPECT_THAT(result, HasSubstr("PASS"));
}
-TEST_F(ZirconQcowGuestTest, ReadMappedCluster) {
+TEST_F(ZirconReadOnlyQcowGuestTest, ReadMappedCluster) {
for (off_t offset = 0; offset != kClusterSize / kBlockSectorSize;
offset += kVirtioTestStep) {
std::string cmd = fxl::StringPrintf("run %s#%s read %lu %u %d %d",
@@ -219,7 +431,7 @@
}
}
-TEST_F(ZirconQcowGuestTest, ReadUnmappedCluster) {
+TEST_F(ZirconReadOnlyQcowGuestTest, ReadUnmappedCluster) {
for (off_t offset = kClusterSize;
offset != kClusterSize + (kClusterSize / kBlockSectorSize);
offset += kVirtioTestStep) {
@@ -230,4 +442,107 @@
EXPECT_EQ(Execute(cmd, &result), ZX_OK);
EXPECT_THAT(result, HasSubstr("PASS"));
}
+}
+
+TEST_F(ZirconReadOnlyQcowGuestTest, Write) {
+ for (off_t offset = kClusterSize;
+ offset != kClusterSize + (kClusterSize / kBlockSectorSize);
+ offset += kVirtioTestStep) {
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s write %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioQcowBlockCount, static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioQcowBlockCount, static_cast<int>(offset), 0);
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+ }
+}
+
+class ZirconVolatileQcowGuestTest : public GuestTest<ZirconVolatileQcowGuestTest> {
+ public:
+ static bool LaunchInfo(fuchsia::guest::LaunchInfo* launch_info) {
+ fbl::unique_fd fd(mkstemp(&qcow_path_[0]));
+ bool qcow_success = write_qcow_file(fd.get());
+ if (!qcow_success) {
+ return false;
+ }
+
+ launch_info->url = kZirconGuestUrl;
+ launch_info->args.push_back("--display=none");
+ launch_info->args.push_back("--cpus=1");
+ launch_info->args.push_back(
+ fxl::StringPrintf("--block=%s,volatile,qcow", qcow_path_));
+ return true;
+ }
+
+ static bool SetUpGuest() {
+ if (WaitForPkgfs() != ZX_OK) {
+ ADD_FAILURE() << "Failed to wait for pkgfs";
+ return false;
+ }
+ return true;
+ }
+
+ static char qcow_path_[PATH_MAX];
+};
+
+char ZirconVolatileQcowGuestTest::qcow_path_[PATH_MAX] = "/tmp/guest-test.XXXXXX";
+
+TEST_F(ZirconVolatileQcowGuestTest, BlockDeviceExists) {
+ std::string cmd = fxl::StringPrintf("run %s#%s check %lu %u", kTestUtilsUrl,
+ kVirtioBlockUtilCmx, kBlockSectorSize,
+ kVirtioQcowBlockCount);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+}
+
+TEST_F(ZirconVolatileQcowGuestTest, ReadMappedCluster) {
+ for (off_t offset = 0; offset != kClusterSize / kBlockSectorSize;
+ offset += kVirtioTestStep) {
+ std::string cmd = fxl::StringPrintf("run %s#%s read %lu %u %d %d",
+ kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioQcowBlockCount,
+ static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+ }
+}
+
+TEST_F(ZirconVolatileQcowGuestTest, ReadUnmappedCluster) {
+ for (off_t offset = kClusterSize;
+ offset != kClusterSize + (kClusterSize / kBlockSectorSize);
+ offset += kVirtioTestStep) {
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioQcowBlockCount, static_cast<int>(offset), 0);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+ }
+}
+
+TEST_F(ZirconVolatileQcowGuestTest, Write) {
+ for (off_t offset = kClusterSize;
+ offset != kClusterSize + (kClusterSize / kBlockSectorSize);
+ offset += kVirtioTestStep) {
+ std::string cmd = fxl::StringPrintf(
+ "run %s#%s write %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioQcowBlockCount, static_cast<int>(offset), 0xab);
+ std::string result;
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+
+ cmd = fxl::StringPrintf(
+ "run %s#%s read %lu %u %d %d", kTestUtilsUrl, kVirtioBlockUtilCmx,
+ kBlockSectorSize, kVirtioQcowBlockCount, static_cast<int>(offset), 0xab);
+ EXPECT_EQ(Execute(cmd, &result), ZX_OK);
+ EXPECT_THAT(result, HasSubstr("PASS"));
+ }
}
\ No newline at end of file