Skip to content

Commit

Permalink
nvme: add unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Derek Su <derek.su@suse.com>
  • Loading branch information
derekbit committed Dec 19, 2023
1 parent 1bbe4c6 commit 040c946
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 2 deletions.
14 changes: 12 additions & 2 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ENV PATH /go/bin:$PATH
ENV DAPPER_DOCKER_SOCKET true
ENV DAPPER_ENV TAG REPO
ENV DAPPER_OUTPUT bin coverage.out
ENV DAPPER_RUN_ARGS --privileged -v /dev:/host/dev -v /proc:/host/proc
ENV DAPPER_RUN_ARGS --privileged -v /dev:/host/dev -v /proc:/host/proc -v /sys:/host/sys
ENV DAPPER_SOURCE /go/src/github.com/longhorn/go-spdk-helper
WORKDIR ${DAPPER_SOURCE}

Expand All @@ -25,7 +25,7 @@ RUN zypper -n install kmod curl fuse wget tar gzip git awk \
nfs-client nfs4-acl-tools cifs-utils \
libibverbs librdmacm1 rdma-core-devel perl-Config-General libaio-devel sg3_utils uuid-devel \
iputils telnet iproute2 qemu-tools \
e2fsprogs e2fsprogs-devel xfsprogs xfsprogs-devel util-linux-systemd python3
e2fsprogs e2fsprogs-devel xfsprogs xfsprogs-devel util-linux-systemd python3 python3-devel meson ninja nvmetcli


# Install Go & tools
Expand All @@ -49,6 +49,16 @@ RUN git clone https://github.com/longhorn/spdk.git ${SPDK_DIR} --recursive && \
make install; \
fi

# nvme-cli 2.5
ENV NVME_CLI_DIR /usr/src/nvme-cli
ENV NVME_CLI_COMMIT_ID d6c07e0de9be777009ebb9ab7475bee1ae3e0e95
RUN git clone https://github.com/linux-nvme/nvme-cli.git ${NVME_CLI_DIR} && \
cd ${NVME_CLI_DIR} && \
git checkout ${NVME_CLI_COMMIT_ID} && \
meson setup --force-fallback-for=libnvme .build && \
meson compile -C .build && \
meson install -C .build && \
ldconfig

VOLUME /tmp
ENV TMPDIR /tmp
Expand Down
95 changes: 95 additions & 0 deletions pkg/nvme/nvme_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package nvme

import (
"fmt"
"strings"
"testing"

execlib "github.com/longhorn/go-common-libs/exec"
nslib "github.com/longhorn/go-common-libs/ns"
typeslib "github.com/longhorn/go-common-libs/types"

. "gopkg.in/check.v1"
)

const (
TestHostNQN = "hostnqn"
TestNQN = "testnqn"
TestTransportType = "loop"
)

func Test(t *testing.T) { TestingT(t) }

type TestSuite struct{}

var _ = Suite(&TestSuite{})

func ProbeNvmeModules() error {
namespaces := []typeslib.Namespace{typeslib.NamespaceMnt, typeslib.NamespaceIpc, typeslib.NamespaceNet}
ne, err := nslib.NewNamespaceExecutor(typeslib.ProcessNone, typeslib.HostProcDirectory, namespaces)
if err != nil {
return err
}
_, err = ne.Execute("modprobe", []string{"nvme", "nvme_loop", "nvmet", "nvme_fabrics"}, typeslib.ExecuteDefaultTimeout)
return err
}

func (s *TestSuite) TestNvmeVersion(c *C) {
fmt.Println("Testing nvme-version With Host Namespace")

namespaces := []typeslib.Namespace{typeslib.NamespaceMnt, typeslib.NamespaceIpc, typeslib.NamespaceNet}
ne, err := nslib.NewNamespaceExecutor(typeslib.ProcessNone, typeslib.ProcDirectory, namespaces)
c.Assert(err, IsNil)

major, minor, err := cliVersion(ne)
c.Assert(err, IsNil)
nvmeVersion := fmt.Sprintf("%d.%d", major, minor)

e := execlib.NewExecutor()
output, err := e.Execute(nil, "nvme", []string{"--version"}, typeslib.ExecuteDefaultTimeout)
c.Assert(err, IsNil)
c.Assert(strings.Contains(output, nvmeVersion), Equals, true)
}

func (s *TestSuite) TestNvmeConnectionAndDisconnection(c *C) {
fmt.Println("Testing nvme connect and disconnect")

err := ProbeNvmeModules()
c.Assert(err, IsNil)

namespaces := []typeslib.Namespace{typeslib.NamespaceMnt, typeslib.NamespaceIpc, typeslib.NamespaceNet}
ne, err := nslib.NewNamespaceExecutor(typeslib.ProcessNone, typeslib.ProcDirectory, namespaces)
c.Assert(err, IsNil)

// Connect to a nvme target
_, err = connect(TestHostNQN, TestNQN, TestTransportType, "", "", ne)
c.Assert(err, IsNil)
defer func() {
err := disconnect(TestNQN, ne)
c.Assert(err, IsNil)
}()

// Check device is connected
devices, err := GetDevices("", "", "", ne)
c.Assert(err, IsNil)
found := false
for _, device := range devices {
if device.SubsystemNQN == TestNQN {
found = true
break
}
}
c.Assert(found, Equals, true)

// List subsystems
subsystems, err := listSubsystems("", ne)
c.Assert(err, IsNil)
found = false
for _, subsystem := range subsystems {
if subsystem.NQN == TestNQN {
found = true
break
}
}
c.Assert(found, Equals, true)
}
121 changes: 121 additions & 0 deletions scripts/test
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,125 @@ echo Running tests

PACKAGES="$(find -name '*.go' | xargs -I{} dirname {} | cut -f2 -d/ | sort -u | grep -Ev '(^\.$|.git|.trash-cache|vendor|bin)' | sed -e 's!^!./!' -e 's!$!/...!')"

function cleanup() {
echo "Cleaning up NVMe target configuration"
nvmetcli clear

echo "Cleaning up loopback device $1"
local loop_device="$1"
losetup -d "$loop_device"
}

function create_nvme_target_config() {
if [ $# -ne 1 ]; then
echo "Usage: generate_nvme_target_config <loop device path>"
return 1
fi

local replacement="$1"
local file_content='
{
"hosts": [
{
"nqn": "hostnqn"
}
],
"ports": [
{
"addr": {
"adrfam": "",
"traddr": "",
"treq": "not specified",
"trsvcid": "",
"trtype": "loop"
},
"portid": 1,
"referrals": [],
"subsystems": [
"testnqn"
]
}
],
"subsystems": [
{
"allowed_hosts": [
"hostnqn"
],
"attr": {
"allow_any_host": "0"
},
"namespaces": [
{
"device": {
"nguid": "ef90689c-6c46-d44c-89c1-4067801309a8",
"path": "unknown"
},
"enable": 1,
"nsid": 1
}
],
"nqn": "testnqn"
}
]
}'

# Perform the replacement
updated_content="${file_content//\"unknown\"/\"$replacement\"}"

# Output the updated content to a file
echo "$updated_content" > /tmp/loop.json
}

function create_loop_device() {
if [ $# -ne 1 ]; then
echo "Usage: create_loop_device <file path>"
return 1
fi

local file_path="$1"
local loop_device=$(losetup -f --show "$file_path")
if [ -z "$loop_device" ]; then
echo "Failed to create loopback device"
return 1
fi

echo "$loop_device"
}

function create_nvme_device() {
local loop_device="$1"
if [ -z "$loop_device" ]; then
echo "Usage: create_nvme_device <loop device path>"
return 1
fi
# Generate NVMe target configuration file
create_nvme_target_config "$loop_device" || return 1

# Create an emulated NVMe device
nvmetcli restore /tmp/loop.json || return 1
}

# Mount necessary directories
mount --rbind /host/dev /dev
mount --rbind /host/sys /sys

# Create a test file and loop device
dd if=/dev/zero of=testfile bs=1M count=100 || exit 1
loop_device=$(create_loop_device testfile)
if [ $? -ne 0 ]; then

Check notice on line 115 in scripts/test

View check run for this annotation

codefactor.io / CodeFactor

scripts/test#L115

Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?. (SC2181)
echo "Failed to create loopback device"
exit 1
fi

echo "Created loopback device $loop_device"

# Create NVMe device and handle cleanup
create_nvme_device "$loop_device"
if [ $? -ne 0 ]; then

Check notice on line 124 in scripts/test

View check run for this annotation

codefactor.io / CodeFactor

scripts/test#L124

Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?. (SC2181)
echo "Failed to create NVMe device"
exit 1
fi

trap "cleanup $loop_device" EXIT

go test -v -race -cover ${PACKAGES}

0 comments on commit 040c946

Please sign in to comment.