From 1ad60d721fac0af8c7af57fe3cab817df351ba3b Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Fri, 25 Mar 2016 18:44:57 +0100
Subject: [PATCH] tests: initial version of the testsuite

This requires nose2 and can be run using make test

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 Makefile            |   3 +
 README.md           |   9 +++
 nvmet/test_nvmet.py | 176 ++++++++++++++++++++++++++++++++++++++++++++
 setup.py            |   1 +
 4 files changed, 189 insertions(+)
 create mode 100644 nvmet/test_nvmet.py

diff --git a/Makefile b/Makefile
index e1887a6..83d599c 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,9 @@ all:
 	@echo "  make clean       - Cleanup the local repository build files."
 	@echo "  make cleanall    - Also remove dist/*"
 
+test:
+	@nose2 -C --coverage ./nvmet
+
 clean:
 	@rm -fv ${NAME}/*.pyc ${NAME}/*.html
 	@rm -frv doc
diff --git a/README.md b/README.md
index 7a8a56b..3ece072 100644
--- a/README.md
+++ b/README.md
@@ -50,3 +50,12 @@ arguments.  Then in the nvmetcli prompt type:
 /subsystems/testnqn/namespaces> create 1
 /subsystems/testnqn/namespaces> cd 1
 /subsystems/t.../namespaces/1> set device path=/dev/ram1
+/subsystems/t.../namespaces/1> enable
+
+
+Testing
+-------
+
+nvmetcli comes with a testsuite that tests itsels and the kernel configfs
+interface for the NVMe target.  To run it make sure you have nose2 and
+the coverage plugin for it installed and simple run 'make test'.
diff --git a/nvmet/test_nvmet.py b/nvmet/test_nvmet.py
new file mode 100644
index 0000000..7696590
--- /dev/null
+++ b/nvmet/test_nvmet.py
@@ -0,0 +1,176 @@
+
+import unittest
+import nvmet.nvme as nvme
+
+
+class TestNvmet(unittest.TestCase):
+    def test_subsystem(self):
+        root = nvme.Root()
+        root.clear_existing()
+        for s in root.subsystems:
+            self.assertTrue(False, 'Found Subsystem after clear')
+
+        # create mode
+        s1 = nvme.Subsystem(nqn='testnqn1', mode='create')
+        self.assertIsNotNone(s1)
+        self.assertEqual(len(list(root.subsystems)), 1)
+
+        # any mode, should create
+        s2 = nvme.Subsystem(nqn='testnqn2', mode='any')
+        self.assertIsNotNone(s2)
+        self.assertEqual(len(list(root.subsystems)), 2)
+
+        # random name
+        s3 = nvme.Subsystem(mode='create')
+        self.assertIsNotNone(s3)
+        self.assertEqual(len(list(root.subsystems)), 3)
+
+        # duplicate
+        self.assertRaises(nvme.CFSError, nvme.Subsystem,
+                          nqn='testnqn1', mode='create')
+        self.assertEqual(len(list(root.subsystems)), 3)
+
+        # lookup using any, should not create
+        s = nvme.Subsystem(nqn='testnqn1', mode='any')
+        self.assertEqual(s1, s)
+        self.assertEqual(len(list(root.subsystems)), 3)
+
+        # lookup only
+        s = nvme.Subsystem(nqn='testnqn2', mode='lookup')
+        self.assertEqual(s2, s)
+        self.assertEqual(len(list(root.subsystems)), 3)
+
+        # lookup without nqn
+        self.assertRaises(nvme.CFSError, nvme.Subsystem, mode='lookup')
+
+        # and delete them all
+        for s in root.subsystems:
+            s.delete()
+        self.assertEqual(len(list(root.subsystems)), 0)
+
+    def test_namespace(self):
+        root = nvme.Root()
+        root.clear_existing()
+
+        s = nvme.Subsystem(nqn='testnqn', mode='create')
+        for n in s.namespaces:
+            self.assertTrue(False, 'Found Namespace in new Subsystem')
+
+        # create mode
+        n1 = nvme.Namespace(s, nsid=3, mode='create')
+        self.assertIsNotNone(n1)
+        self.assertEqual(len(list(s.namespaces)), 1)
+
+        # any mode, should create
+        n2 = nvme.Namespace(s, nsid=2, mode='any')
+        self.assertIsNotNone(n2)
+        self.assertEqual(len(list(s.namespaces)), 2)
+
+        # create without nsid, should pick lowest available
+        n3 = nvme.Namespace(s, mode='create')
+        self.assertIsNotNone(n3)
+        self.assertEqual(n3.nsid, 1)
+        self.assertEqual(len(list(s.namespaces)), 3)
+
+        n4 = nvme.Namespace(s, mode='create')
+        self.assertIsNotNone(n4)
+        self.assertEqual(n4.nsid, 4)
+        self.assertEqual(len(list(s.namespaces)), 4)
+
+        # duplicate
+        self.assertRaises(nvme.CFSError, nvme.Namespace, 1, mode='create')
+        self.assertEqual(len(list(s.namespaces)), 4)
+
+        # lookup using any, should not create
+        n = nvme.Namespace(s, nsid=3, mode='any')
+        self.assertEqual(n1, n)
+        self.assertEqual(len(list(s.namespaces)), 4)
+
+        # lookup only
+        n = nvme.Namespace(s, nsid=2, mode='lookup')
+        self.assertEqual(n2, n)
+        self.assertEqual(len(list(s.namespaces)), 4)
+
+        # lookup without nsid
+        self.assertRaises(nvme.CFSError, nvme.Namespace, None, mode='lookup')
+
+        # and delete them all
+        for n in s.namespaces:
+            n.delete()
+        self.assertEqual(len(list(s.namespaces)), 0)
+
+    def test_namespace_attrs(self):
+        root = nvme.Root()
+        root.clear_existing()
+
+        s = nvme.Subsystem(nqn='testnqn', mode='create')
+        n = nvme.Namespace(s, mode='create')
+
+        self.assertFalse(n.get_enable())
+        self.assertTrue('device' in n.attr_groups)
+        self.assertTrue('path' in n.list_attrs('device'))
+
+        # no device set yet, should fail
+        self.assertRaises(nvme.CFSError, n.set_enable, 1)
+
+        # now set a path and enable
+        n.set_attr('device', 'path', '/dev/ram0')
+        n.set_enable(1)
+        self.assertTrue(n.get_enable())
+
+        # test double enable
+        n.set_enable(1)
+
+        # test that we can't write to attrs while enabled
+        self.assertRaises(nvme.CFSError, n.set_attr, 'device', 'path',
+                          '/dev/ram1')
+        self.assertRaises(nvme.CFSError, n.set_attr, 'device', 'nguid',
+                          '15f7767b-50e7-4441-949c-75b99153dea7')
+
+        # disable: once and twice
+        n.set_enable(0)
+        n.set_enable(0)
+
+        # enable again, and remove while enabled
+        n.set_enable(1)
+        n.delete()
+
+    def test_recursive_delete(self):
+        root = nvme.Root()
+        root.clear_existing()
+
+        s = nvme.Subsystem(nqn='testnqn', mode='create')
+        n1 = nvme.Namespace(s, mode='create')
+        n2 = nvme.Namespace(s, mode='create')
+
+        s.delete()
+        self.assertEqual(len(list(root.subsystems)), 0)
+
+    def test_save_restore(self):
+        root = nvme.Root()
+        root.clear_existing()
+
+        s = nvme.Subsystem(nqn='testnqn', mode='create')
+
+        n = nvme.Namespace(s, nsid=42, mode='create')
+        n.set_attr('device', 'path', '/dev/ram0')
+        n.set_enable(1)
+
+        root.save_to_file('test.json')
+        root.clear_existing()
+        root.restore_from_file('test.json')
+
+        # additional restores should fai
+        self.assertRaises(nvme.CFSError, root.restore_from_file,
+                          'test.json', False)
+
+        # ... unless forced!
+        root.restore_from_file('test.json', True)
+
+        # rebuild our view of the world
+        s = nvme.Subsystem(nqn='testnqn', mode='lookup')
+        n = nvme.Namespace(s, nsid=42, mode='lookup')
+
+        # and check everything is still the same
+        self.assertTrue(n.get_enable())
+        self.assertEqual(n.get_attr('device', 'path'), '/dev/ram0')
diff --git a/setup.py b/setup.py
index 93cdae1..078020f 100755
--- a/setup.py
+++ b/setup.py
@@ -25,5 +25,6 @@ setup(
     license = 'Apache 2.0',
     maintainer = 'Christoph Hellwig',
     maintainer_email = 'hch@lst.de',
+    test_suite='nose2.collector.collector',
     packages = ['nvmet'],
     )
-- 
GitLab