Skip to content

Commit

Permalink
tests: Fix tools::is_hdd unit tests
Browse files Browse the repository at this point in the history
Correct the unit tests for tools::is_hdd to avoid making assumptions
about the configuration of a particular device based solely on the
value of the __GLIBC__ preprocessor flag. Instead, rely on the
test invoker to provide paths for devices of specific types via
the process environment, thereby avoiding faulty assumptions and
improving the specificity of test assertions. To ensure appropriate
devices exist, add a script, tests/create_test_disks.sh, which
configures loopback devices mirroring relevant configurations.
  • Loading branch information
iamamyth committed Jan 17, 2025
1 parent 1179269 commit d39dad1
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ jobs:
run: sudo ${{env.APT_INSTALL_LINUX}}
- name: install Python dependencies
run: pip install requests psutil monotonic zmq deepdiff
- name: create dummy disk drives for testing
run: tests/create_test_disks.sh >> $GITHUB_ENV
- name: tests
env:
CTEST_OUTPUT_ON_FAILURE: ON
Expand Down
90 changes: 90 additions & 0 deletions tests/create_test_disks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/bin/bash

set -e

LOOP_DEVICE_MAJOR=7
LOOP_DEVICE_MIN_ID=100

echo_err() {
echo "$@" >&2
}

create_device_node() {
local -r last_id=$(find /dev/ -name 'loop[0-9]*' | sed 's/^.*loop//' | sort -r -n | head -1)
local id=$((last_id + 1))
if [[ "$id" -lt "$LOOP_DEVICE_MIN_ID" ]]; then
id="$LOOP_DEVICE_MIN_ID"
fi
local path
for (( i=0; i<10; i++ )); do
path="/dev/loop$id"
if [[ ! -e "$path" ]] && sudo mknod "$path" b "$LOOP_DEVICE_MAJOR" "$id"; then
echo "$path"
return 0
fi
$((id++))
done
return 1
}

device_mountpoint() {
local -r datadir="$1"
local -r dev="$2"
if [[ -z "$datadir" || -z "$dev" ]]; then
echo_err "Usage: device_mountpoint <data dir> <device>"
return 1
fi
echo "$datadir/mnt-$(basename "$dev")"
}

create_device() {
local -r datadir="$1"
if [[ -z "$datadir" ]]; then
echo_err "Usage: create_device <data dir>"
return 1
fi
local -r dev=$(create_device_node)
local -r fs="$datadir/$(basename "$dev").vhd"
local -r mountpoint=$(device_mountpoint "$datadir" "$dev")
echo_err
echo_err "# Device $dev"
dd if=/dev/zero of="$fs" bs=64K count=128 >/dev/null 2>&1
sudo losetup "$dev" "$fs"
sudo mkfs.ext4 "$dev" >/dev/null 2>&1
mkdir "$mountpoint"
sudo mount "$dev" "$mountpoint"
echo "$dev"
}

# Unused by default, but helpful for local development
destroy_device() {
local -r datadir="$1"
local -r dev="$2"
if [[ -z "$datadir" || -z "$dev" ]]; then
echo_err "Usage: destroy_device <data dir> <device>"
return 1
fi
echo_err "Destroying device $dev"
sudo umount $(device_mountpoint "$datadir" "$dev")
sudo losetup -d "$dev"
sudo rm "$dev"
}

block_device_path() {
device_name=$(basename "$1")
device_minor=${device_name/#loop}
echo "/sys/dev/block/$LOOP_DEVICE_MAJOR:$device_minor"
}

tmpdir=$(mktemp --tmpdir -d monerotest.XXXXXXXX)
echo_err "Creating devices using temporary directory: $tmpdir"

dev_rot=$(create_device "$tmpdir")
bdev_rot=$(block_device_path "$dev_rot")
echo 1 | sudo tee "$bdev_rot/queue/rotational" >/dev/null
echo MONERO_TEST_DEVICE_HDD=$(device_mountpoint "$tmpdir" "$dev_rot")

dev_ssd=$(create_device "$tmpdir")
bdev_ssd=$(block_device_path "$dev_ssd")
echo 0 | sudo tee "$bdev_ssd/queue/rotational" >/dev/null
echo MONERO_TEST_DEVICE_SSD=$(device_mountpoint "$tmpdir" "$dev_ssd")
37 changes: 28 additions & 9 deletions tests/unit_tests/is_hdd.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
#include "common/util.h"
#include <cstdlib>
#include <string>
#include <gtest/gtest.h>
#include <boost/optional/optional_io.hpp> /* required to output boost::optional in assertions */

#ifndef GTEST_SKIP
#include <iostream>
#define SKIP_TEST(reason) do {std::cerr << "Skipping test: " << reason << std::endl; return;} while(0)
#else
#define SKIP_TEST(reason) GTEST_SKIP() << reason
#endif

#if defined(__GLIBC__)
TEST(is_hdd, linux_os_root)
{
std::string path = "/";
EXPECT_TRUE(tools::is_hdd(path.c_str()) != boost::none);
TEST(is_hdd, rotational_drive) {
const char *hdd = std::getenv("MONERO_TEST_DEVICE_HDD");
if (hdd == nullptr)
SKIP_TEST("No rotational disk device configured");
EXPECT_EQ(tools::is_hdd(hdd), boost::optional<bool>(true));
}
#else
TEST(is_hdd, unknown_os)
{
std::string path = "";
EXPECT_FALSE(tools::is_hdd(path.c_str()) != boost::none);

TEST(is_hdd, ssd) {
const char *ssd = std::getenv("MONERO_TEST_DEVICE_SSD");
if (ssd == nullptr)
SKIP_TEST("No SSD device configured");
EXPECT_EQ(tools::is_hdd(ssd), boost::optional<bool>(false));
}

TEST(is_hdd, unknown_attrs) {
EXPECT_EQ(tools::is_hdd("/dev/null"), boost::none);
}
#endif
TEST(is_hdd, stability)
{
EXPECT_NO_THROW(tools::is_hdd(""));
}

0 comments on commit d39dad1

Please sign in to comment.