[Libguestfs] [PATCH 1/3] python: tests: refactor to use unittest's discovery

Pino Toscano ptoscano at redhat.com
Mon Feb 22 16:35:21 UTC 2016


Instead of running all the tests manually, the unittest module has a
'discovery' mode to run tests by importing them from a directory: this
requires the tests to have different filenames, since they need to be
imported as modules now (hence an empty __init__.py is added), and the
current naming does not match the convention.

Using unittest as loader/runner brings another change: tests skipped as
whole cannot be done anymore with exit(77), since they are not run but
imported: thus introduce an helper module with decorators applied to the
test classes to skip them according to the current checks.  This also
gets us nicer recordings in the unittest log.

Due to the relative imports (needed for the helper code), it is no more
possible to execute tests anymore by invoking them manually; although
it is possible to run single tests, still using unittest's runner:

  $ cd python
  python$ ../run python -m unittest discover -v t test010Load.py

This does not change anything in what the tests do/check.
---
 .gitignore                       |   1 +
 python/run-python-tests          |  21 +-----
 python/t/010-load.py             |  25 -------
 python/t/070-optargs.py          |  39 -----------
 python/t/080-version.py          |  46 -------------
 python/t/090-retvalues.py        | 138 ---------------------------------------
 python/t/100-launch.py           |  37 -----------
 python/t/410-close-event.py      |  41 ------------
 python/t/420-log-messages.py     |  57 ----------------
 python/t/800-explicit-close.py   |  57 ----------------
 python/t/810-rhbz811650.py       |  40 ------------
 python/t/820-rhbz912499.py       | 118 ---------------------------------
 python/t/910-libvirt.py          |  52 ---------------
 python/t/__init__.py             |   0
 python/t/test010Load.py          |  22 +++++++
 python/t/test070OptArgs.py       |  36 ++++++++++
 python/t/test080Version.py       |  43 ++++++++++++
 python/t/test090RetValues.py     | 134 +++++++++++++++++++++++++++++++++++++
 python/t/test100Launch.py        |  34 ++++++++++
 python/t/test410CloseEvent.py    |  38 +++++++++++
 python/t/test420LogMessages.py   |  54 +++++++++++++++
 python/t/test800ExplicitClose.py |  54 +++++++++++++++
 python/t/test810RHBZ811650.py    |  37 +++++++++++
 python/t/test820RHBZ912499.py    |  94 ++++++++++++++++++++++++++
 python/t/test910Libvirt.py       |  42 ++++++++++++
 python/t/tests_helper.py         |  63 ++++++++++++++++++
 26 files changed, 653 insertions(+), 670 deletions(-)
 delete mode 100644 python/t/010-load.py
 delete mode 100644 python/t/070-optargs.py
 delete mode 100644 python/t/080-version.py
 delete mode 100644 python/t/090-retvalues.py
 delete mode 100644 python/t/100-launch.py
 delete mode 100644 python/t/410-close-event.py
 delete mode 100644 python/t/420-log-messages.py
 delete mode 100644 python/t/800-explicit-close.py
 delete mode 100644 python/t/810-rhbz811650.py
 delete mode 100644 python/t/820-rhbz912499.py
 delete mode 100644 python/t/910-libvirt.py
 create mode 100644 python/t/__init__.py
 create mode 100644 python/t/test010Load.py
 create mode 100644 python/t/test070OptArgs.py
 create mode 100644 python/t/test080Version.py
 create mode 100644 python/t/test090RetValues.py
 create mode 100644 python/t/test100Launch.py
 create mode 100644 python/t/test410CloseEvent.py
 create mode 100644 python/t/test420LogMessages.py
 create mode 100644 python/t/test800ExplicitClose.py
 create mode 100644 python/t/test810RHBZ811650.py
 create mode 100644 python/t/test820RHBZ912499.py
 create mode 100644 python/t/test910Libvirt.py
 create mode 100644 python/t/tests_helper.py

diff --git a/.gitignore b/.gitignore
index db354bc..40bebb3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
 *.o
 *.orig
 *.patch
+*.pyc
 *.rej
 *.swp
 *.trs
diff --git a/python/run-python-tests b/python/run-python-tests
index 1def36b..a374430 100755
--- a/python/run-python-tests
+++ b/python/run-python-tests
@@ -16,26 +16,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-errors=0
-
 guestsdir="$(cd ../test-data/phony-guests && pwd)"
 export guestsdir
 
-for f in $srcdir/t/*.py; do
-  $PYTHON $f
-  r=$?
-  case $r in
-      0) ;;
-      77)
-          echo "$f: test skipped"
-          ;;
-      *)
-          echo "FAIL: $f"
-          ((errors++))
-          ;;
-  esac
-done
-
-if [ $errors -gt 0 ]; then
-    exit 1
-fi
+$PYTHON -m unittest discover -v
diff --git a/python/t/010-load.py b/python/t/010-load.py
deleted file mode 100644
index aa14706..0000000
--- a/python/t/010-load.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2009 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-
-class Test010Load (unittest.TestCase):
-    def test_import (self):
-        import guestfs
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/070-optargs.py b/python/t/070-optargs.py
deleted file mode 100644
index c3e9ddd..0000000
--- a/python/t/070-optargs.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2010 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-import os
-import guestfs
-
-class Test070OptArgs (unittest.TestCase):
-    def setUp (self):
-        self.g = guestfs.GuestFS (python_return_dict=True)
-
-    def test_no_optargs (self):
-        self.g.add_drive ("/dev/null")
-
-    def test_one_optarg (self):
-        self.g.add_drive ("/dev/null", readonly = True)
-
-    def test_two_optargs (self):
-        self.g.add_drive ("/dev/null", iface = "virtio", format = "raw")
-
-    def tearDown (self):
-        self.g.close ()
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/080-version.py b/python/t/080-version.py
deleted file mode 100644
index cda4872..0000000
--- a/python/t/080-version.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2016 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-import sys
-import os
-import guestfs
-
-if sys.version_info >= (3, 0):
-    cl = int
-else:
-    cl = long
-
-class Test080Version (unittest.TestCase):
-    def setUp (self):
-        self.g = guestfs.GuestFS (python_return_dict=True)
-        self.version = self.g.version ()
-
-    def test_major (self):
-        self.assertEqual (self.version['major'], 1)
-
-    def test_minor (self):
-        self.assertIsInstance (self.version['minor'], cl)
-
-    def test_release (self):
-        self.assertIsInstance (self.version['release'], cl)
-
-    def test_extra (self):
-        self.assertIsInstance (self.version['extra'], str)
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/090-retvalues.py b/python/t/090-retvalues.py
deleted file mode 100644
index 8a5c912..0000000
--- a/python/t/090-retvalues.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2013-2016 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-# Test all the different return values.
-
-import unittest
-import guestfs
-
-
-class Test090PythonRetValues (unittest.TestCase):
-    def test_rint (self):
-        g = guestfs.GuestFS ()
-
-        self.assertAlmostEqual (g.internal_test_rint ("10"), 10, places=1)
-
-        self.assertRaises (RuntimeError, g.internal_test_rinterr)
-
-
-    def test_rint64 (self):
-        g = guestfs.GuestFS ()
-
-        self.assertAlmostEqual (g.internal_test_rint64 ("10"), 10L, places=1)
-
-        self.assertRaises (RuntimeError, g.internal_test_rint64err)
-
-
-    def test_rbool (self):
-        g = guestfs.GuestFS ()
-
-        self.assertTrue (g.internal_test_rbool ("true"))
-        self.assertFalse (g.internal_test_rbool ("false"))
-
-        self.assertRaises (RuntimeError, g.internal_test_rboolerr)
-
-
-    def test_rconststring (self):
-        g = guestfs.GuestFS ()
-
-        self.assertEqual (g.internal_test_rconststring ("test"), "static string")
-
-        self.assertRaises (RuntimeError, g.internal_test_rconststringerr)
-
-
-    def test_rconstoptstring (self):
-        g = guestfs.GuestFS ()
-
-        self.assertEqual (g.internal_test_rconstoptstring ("test"), "static string")
-
-        # this never fails
-        self.assertIsNone (g.internal_test_rconstoptstringerr ())
-
-
-    def test_rstring (self):
-        g = guestfs.GuestFS ()
-
-        self.assertEqual (g.internal_test_rstring ("test"), "test")
-
-        self.assertRaises (RuntimeError, g.internal_test_rstringerr)
-
-
-    def test_rstringlist (self):
-        g = guestfs.GuestFS ()
-
-        self.assertEqual (g.internal_test_rstringlist ("0"), [])
-        self.assertEqual (g.internal_test_rstringlist ("5"), ["0", "1", "2", "3", "4"])
-
-        self.assertRaises (RuntimeError, g.internal_test_rstringlisterr)
-
-
-    def test_rstruct (self):
-        g = guestfs.GuestFS ()
-
-        s = g.internal_test_rstruct ("unused")
-        self.assertIsInstance (s, dict)
-        self.assertEqual (s["pv_name"], "pv0")
-
-        self.assertRaises (RuntimeError, g.internal_test_rstructerr)
-
-
-    def test_rstructlist (self):
-        g = guestfs.GuestFS ()
-
-        self.assertEqual (g.internal_test_rstructlist ("0"), [])
-        l = g.internal_test_rstructlist ("5")
-        self.assertIsInstance (l, list)
-        self.assertEqual (len (l), 5)
-        for i in range (0, 5):
-            self.assertIsInstance (l[i], dict)
-            self.assertEqual (l[i]["pv_name"], "pv%d" % i)
-
-        self.assertRaises (RuntimeError, g.internal_test_rstructlisterr)
-
-
-    def test_rhashtable_list (self):
-        g = guestfs.GuestFS (python_return_dict=False)
-
-        self.assertEqual (g.internal_test_rhashtable ("0"), [])
-        r = g.internal_test_rhashtable ("5")
-        self.assertEqual (r, [ ("0","0"), ("1","1"), ("2","2"),
-                               ("3","3"), ("4","4") ])
-
-        self.assertRaises (RuntimeError, g.internal_test_rhashtableerr)
-
-
-    def test_rhashtable_dict (self):
-        g = guestfs.GuestFS (python_return_dict=True)
-
-        self.assertEqual (g.internal_test_rhashtable ("0"), {})
-        r = g.internal_test_rhashtable ("5")
-        self.assertEqual (r, {"0": "0", "1": "1", "2": "2", "3": "3", "4": "4"})
-
-        self.assertRaises (RuntimeError, g.internal_test_rhashtableerr)
-
-
-    def test_rbufferout (self):
-        g = guestfs.GuestFS ()
-
-        self.assertEqual (g.internal_test_rbufferout ("test"), b'test')
-
-        self.assertRaises (RuntimeError, g.internal_test_rbufferouterr)
-
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/100-launch.py b/python/t/100-launch.py
deleted file mode 100644
index 7c70ecc..0000000
--- a/python/t/100-launch.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2009-2016 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-import os
-import guestfs
-
-class Test100Launch (unittest.TestCase):
-    def test_launch (self):
-        g = guestfs.GuestFS (python_return_dict=True)
-        g.add_drive_scratch (500 * 1024 * 1024)
-        g.launch ()
-
-        g.pvcreate ("/dev/sda")
-        g.vgcreate ("VG", ["/dev/sda"])
-        g.lvcreate ("LV1", "VG", 200)
-        g.lvcreate ("LV2", "VG", 200)
-        self.assertEqual (g.lvs (), ["/dev/VG/LV1", "/dev/VG/LV2"])
-        g.shutdown ()
-        g.close ()
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/410-close-event.py b/python/t/410-close-event.py
deleted file mode 100644
index 5aa82a4..0000000
--- a/python/t/410-close-event.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2011-2016 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-import os
-import guestfs
-
-close_invoked = 0
-
-def close_callback (ev, eh, buf, array):
-    global close_invoked
-    close_invoked += 1
-
-class Test410CloseEvent (unittest.TestCase):
-    def test_close_event (self):
-        g = guestfs.GuestFS (python_return_dict=True)
-
-        # Register a callback for the close event.
-        g.set_event_callback (close_callback, guestfs.EVENT_CLOSE)
-
-        # Close the handle.  The close callback should be invoked.
-        self.assertEqual (close_invoked, 0)
-        g.close ()
-        self.assertEqual (close_invoked, 1)
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/420-log-messages.py b/python/t/420-log-messages.py
deleted file mode 100644
index 6b7c06c..0000000
--- a/python/t/420-log-messages.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2011 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-import os
-import guestfs
-
-log_invoked = 0
-
-def log_callback (ev,eh,buf,array):
-    global log_invoked
-    log_invoked += 1
-
-    if ev == guestfs.EVENT_APPLIANCE:
-        buf = buf.rstrip()
-
-    # Log what happened.
-    print ("python event logged: event=%s eh=%d buf='%s' array=%s" %
-           (guestfs.event_to_string (ev), eh, buf, array))
-
-class Test420LogMessages (unittest.TestCase):
-    def test_log_messages (self):
-        g = guestfs.GuestFS (python_return_dict=True)
-
-        # Register an event callback for all log messages.
-        events = guestfs.EVENT_APPLIANCE | guestfs.EVENT_LIBRARY \
-                 | guestfs.EVENT_WARNING | guestfs.EVENT_TRACE
-        g.set_event_callback (log_callback, events)
-
-        # Now make sure we see some messages.
-        g.set_trace (1)
-        g.set_verbose (1)
-
-        # Do some stuff.
-        g.add_drive_ro ("/dev/null")
-        g.set_autosync (1)
-
-        g.close ()
-
-        self.assertNotEqual (log_invoked, 0)
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/800-explicit-close.py b/python/t/800-explicit-close.py
deleted file mode 100644
index 4086829..0000000
--- a/python/t/800-explicit-close.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2011 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-# Test implicit vs explicit closes of the handle (RHBZ#717786).
-
-import unittest
-import os
-import guestfs
-
-close_invoked = 0
-
-def close_callback (ev, eh, buf, array):
-    global close_invoked
-    close_invoked += 1
-
-class Test800ExplicitClose (unittest.TestCase):
-    def test_explicit_close (self):
-        g = guestfs.GuestFS (python_return_dict=True)
-
-        g.close ()              # explicit close
-        del g                   # implicit close - should be no error/warning
-
-        # Expect an exception if we call a method on a closed handle.
-        g = guestfs.GuestFS (python_return_dict=True)
-        g.close ()
-        self.assertRaises (guestfs.ClosedHandle, g.set_memsize, 512)
-        del g
-
-        # Verify that the handle is really being closed by g.close, by
-        # setting up a close event and testing that it happened.
-        g = guestfs.GuestFS (python_return_dict=True)
-
-        g.set_event_callback (close_callback, guestfs.EVENT_CLOSE)
-
-        self.assertEqual (close_invoked, 0)
-        g.close ()
-        self.assertEqual (close_invoked, 1)
-
-        del g
-        self.assertEqual (close_invoked, 1)
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/810-rhbz811650.py b/python/t/810-rhbz811650.py
deleted file mode 100644
index c37abac..0000000
--- a/python/t/810-rhbz811650.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2012 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-import unittest
-import os
-import guestfs
-
-class Test810RHBZ811650 (unittest.TestCase):
-    def test_rhbz811650 (self):
-        g = guestfs.GuestFS (python_return_dict=True)
-
-        g.disk_create ("rhbz811650.img", "raw", 500 * 1024 * 1024)
-
-        # Deliberate error: the disk format is supposed to be raw.
-        g.add_drive ("rhbz811650.img", format="qcow2");
-
-        # Because error() wasn't being called, guestfs_last_error
-        # would return NULL, causing a segfault in the Python bindings
-        # (RHBZ#811650).
-        self.assertRaises (RuntimeError, g.launch)
-
-    def tearDown (self):
-        os.unlink ("rhbz811650.img")
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/820-rhbz912499.py b/python/t/820-rhbz912499.py
deleted file mode 100644
index e8f1d4b..0000000
--- a/python/t/820-rhbz912499.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2014 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-# Test that SELinux relabelling code doesn't regress.
-# See: https://bugzilla.redhat.com/912499#c10
-#      https://bugzilla.redhat.com/1075164#c7
-
-from subprocess import check_output
-import unittest
-import random
-import string
-import re
-import os
-import platform
-import guestfs
-
-try:
-    import libvirt
-except:
-    print ("skipping test: could not import python-libvirt")
-    exit (77)
-
-# If the backend is not libvirt, skip the test.
-backend = guestfs.GuestFS().get_backend()
-rex = re.compile ("^libvirt")
-if not rex.match (backend):
-    print ("skipping test: backend is not libvirt")
-    exit (77)
-
-# If the architecture doesn't support IDE, skip the test.
-machine = platform.machine ()
-rex = re.compile ("i.86")
-if machine != "x86_64" and not rex.match (machine):
-    print ("skipping test: arch is not x86 and does not support IDE")
-    exit (77)
-
-conn = libvirt.open (None)
-
-# Check we're using the version of libvirt-python that has c_pointer() methods.
-if not "c_pointer" in dir (conn):
-    print ("skipping test: libvirt-python doesn't support c_pointer()")
-    exit (77)
-
-class Test820RHBZ912499 (unittest.TestCase):
-    def setUp (self):
-        # Create a test disk.
-        self.filename = os.getcwd () + "/820-rhbz912499.img"
-        guestfs.GuestFS().disk_create (self.filename, "raw", 1024*1024*1024)
-
-        # Create a new domain.  This won't work, it will just hang when
-        # booted.  But that's sufficient for the test.
-        self.domname = ''.join (random.choice (string.ascii_uppercase)
-                                for _ in range (8))
-        self.domname = "tmp-" + self.domname
-
-        self.xml = """
-<domain type='qemu'>
-  <name>%s</name>
-  <memory>1048576</memory>
-  <vcpu>1</vcpu>
-  <os>
-    <type>hvm</type>
-    <boot dev='hd'/>
-  </os>
-  <devices>
-    <disk type='file' device='disk'>
-      <driver name='qemu' type='raw'/>
-      <source file='%s'/>
-      <target dev='hda' bus='ide'/>
-    </disk>
-  </devices>
-</domain>
-""" % (self.domname, self.filename)
-
-    def test_rhbz912499 (self):
-        dom = conn.createXML (self.xml,
-                              libvirt.VIR_DOMAIN_START_AUTODESTROY)
-        self.assertIsNotNone (dom)
-
-        print ("temporary domain %s is running" % self.domname)
-
-        # Libvirt should have labelled the disk.
-        print ("before starting libguestfs")
-        before = check_output (["ls", "-Z", self.filename])
-        print ("disk label = %s" % before)
-
-        # Now see if we can open the domain with libguestfs without
-        # disturbing the label.
-        g = guestfs.GuestFS ()
-        r = g.add_libvirt_dom (dom, readonly = 1)
-        self.assertEqual (r, 1)
-        g.launch ()
-
-        print ("after starting libguestfs")
-        after = check_output (["ls", "-Z", self.filename])
-        print ("disk label = %s" % after)
-
-        self.assertEqual (before, after)
-
-    def tearDown (self):
-        os.unlink (self.filename)
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/910-libvirt.py b/python/t/910-libvirt.py
deleted file mode 100644
index 1d70371..0000000
--- a/python/t/910-libvirt.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# libguestfs Python bindings
-# Copyright (C) 2014 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-# The Python bindings for add_libvirt_dom require the libvirt-python
-# library to support a new method (.c_pointer()).  Ensure this keeps
-# working by testing it.  See:
-# https://bugzilla.redhat.com/show_bug.cgi?id=1075164
-
-import unittest
-import os
-import guestfs
-
-guestsdir = os.environ['guestsdir']
-
-try:
-    import libvirt
-except:
-    print ("could not import python-libvirt")
-    exit (77)
-
-conn = libvirt.open ("test:///%s/guests.xml" % guestsdir)
-
-# Check we're using the version of libvirt-python that has c_pointer() methods.
-if not "c_pointer" in dir (conn):
-    print ("skipping test: libvirt-python doesn't support c_pointer()")
-    exit (77)
-
-class Test910Libvirt (unittest.TestCase):
-    def test_libvirt (self):
-        dom = conn.lookupByName ("blank-disk")
-
-        g = guestfs.GuestFS ()
-
-        r = g.add_libvirt_dom (dom, readonly=1)
-        self.assertEqual (r, 1)
-
-if __name__ == '__main__':
-    unittest.main ()
diff --git a/python/t/__init__.py b/python/t/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/python/t/test010Load.py b/python/t/test010Load.py
new file mode 100644
index 0000000..1e6ea4d
--- /dev/null
+++ b/python/t/test010Load.py
@@ -0,0 +1,22 @@
+# libguestfs Python bindings
+# Copyright (C) 2009 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+
+class Test010Load (unittest.TestCase):
+    def test_import (self):
+        import guestfs
diff --git a/python/t/test070OptArgs.py b/python/t/test070OptArgs.py
new file mode 100644
index 0000000..2cf1ea9
--- /dev/null
+++ b/python/t/test070OptArgs.py
@@ -0,0 +1,36 @@
+# libguestfs Python bindings
+# Copyright (C) 2010 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+import os
+import guestfs
+
+class Test070OptArgs (unittest.TestCase):
+    def setUp (self):
+        self.g = guestfs.GuestFS (python_return_dict=True)
+
+    def test_no_optargs (self):
+        self.g.add_drive ("/dev/null")
+
+    def test_one_optarg (self):
+        self.g.add_drive ("/dev/null", readonly = True)
+
+    def test_two_optargs (self):
+        self.g.add_drive ("/dev/null", iface = "virtio", format = "raw")
+
+    def tearDown (self):
+        self.g.close ()
diff --git a/python/t/test080Version.py b/python/t/test080Version.py
new file mode 100644
index 0000000..d8ce1cb
--- /dev/null
+++ b/python/t/test080Version.py
@@ -0,0 +1,43 @@
+# libguestfs Python bindings
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+import sys
+import os
+import guestfs
+
+if sys.version_info >= (3, 0):
+    cl = int
+else:
+    cl = long
+
+class Test080Version (unittest.TestCase):
+    def setUp (self):
+        self.g = guestfs.GuestFS (python_return_dict=True)
+        self.version = self.g.version ()
+
+    def test_major (self):
+        self.assertEqual (self.version['major'], 1)
+
+    def test_minor (self):
+        self.assertIsInstance (self.version['minor'], cl)
+
+    def test_release (self):
+        self.assertIsInstance (self.version['release'], cl)
+
+    def test_extra (self):
+        self.assertIsInstance (self.version['extra'], str)
diff --git a/python/t/test090RetValues.py b/python/t/test090RetValues.py
new file mode 100644
index 0000000..7ff51f0
--- /dev/null
+++ b/python/t/test090RetValues.py
@@ -0,0 +1,134 @@
+# libguestfs Python bindings
+# Copyright (C) 2013-2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test all the different return values.
+
+import unittest
+import guestfs
+
+
+class Test090PythonRetValues (unittest.TestCase):
+    def test_rint (self):
+        g = guestfs.GuestFS ()
+
+        self.assertAlmostEqual (g.internal_test_rint ("10"), 10, places=1)
+
+        self.assertRaises (RuntimeError, g.internal_test_rinterr)
+
+
+    def test_rint64 (self):
+        g = guestfs.GuestFS ()
+
+        self.assertAlmostEqual (g.internal_test_rint64 ("10"), 10L, places=1)
+
+        self.assertRaises (RuntimeError, g.internal_test_rint64err)
+
+
+    def test_rbool (self):
+        g = guestfs.GuestFS ()
+
+        self.assertTrue (g.internal_test_rbool ("true"))
+        self.assertFalse (g.internal_test_rbool ("false"))
+
+        self.assertRaises (RuntimeError, g.internal_test_rboolerr)
+
+
+    def test_rconststring (self):
+        g = guestfs.GuestFS ()
+
+        self.assertEqual (g.internal_test_rconststring ("test"), "static string")
+
+        self.assertRaises (RuntimeError, g.internal_test_rconststringerr)
+
+
+    def test_rconstoptstring (self):
+        g = guestfs.GuestFS ()
+
+        self.assertEqual (g.internal_test_rconstoptstring ("test"), "static string")
+
+        # this never fails
+        self.assertIsNone (g.internal_test_rconstoptstringerr ())
+
+
+    def test_rstring (self):
+        g = guestfs.GuestFS ()
+
+        self.assertEqual (g.internal_test_rstring ("test"), "test")
+
+        self.assertRaises (RuntimeError, g.internal_test_rstringerr)
+
+
+    def test_rstringlist (self):
+        g = guestfs.GuestFS ()
+
+        self.assertEqual (g.internal_test_rstringlist ("0"), [])
+        self.assertEqual (g.internal_test_rstringlist ("5"), ["0", "1", "2", "3", "4"])
+
+        self.assertRaises (RuntimeError, g.internal_test_rstringlisterr)
+
+
+    def test_rstruct (self):
+        g = guestfs.GuestFS ()
+
+        s = g.internal_test_rstruct ("unused")
+        self.assertIsInstance (s, dict)
+        self.assertEqual (s["pv_name"], "pv0")
+
+        self.assertRaises (RuntimeError, g.internal_test_rstructerr)
+
+
+    def test_rstructlist (self):
+        g = guestfs.GuestFS ()
+
+        self.assertEqual (g.internal_test_rstructlist ("0"), [])
+        l = g.internal_test_rstructlist ("5")
+        self.assertIsInstance (l, list)
+        self.assertEqual (len (l), 5)
+        for i in range (0, 5):
+            self.assertIsInstance (l[i], dict)
+            self.assertEqual (l[i]["pv_name"], "pv%d" % i)
+
+        self.assertRaises (RuntimeError, g.internal_test_rstructlisterr)
+
+
+    def test_rhashtable_list (self):
+        g = guestfs.GuestFS (python_return_dict=False)
+
+        self.assertEqual (g.internal_test_rhashtable ("0"), [])
+        r = g.internal_test_rhashtable ("5")
+        self.assertEqual (r, [ ("0","0"), ("1","1"), ("2","2"),
+                               ("3","3"), ("4","4") ])
+
+        self.assertRaises (RuntimeError, g.internal_test_rhashtableerr)
+
+
+    def test_rhashtable_dict (self):
+        g = guestfs.GuestFS (python_return_dict=True)
+
+        self.assertEqual (g.internal_test_rhashtable ("0"), {})
+        r = g.internal_test_rhashtable ("5")
+        self.assertEqual (r, {"0": "0", "1": "1", "2": "2", "3": "3", "4": "4"})
+
+        self.assertRaises (RuntimeError, g.internal_test_rhashtableerr)
+
+
+    def test_rbufferout (self):
+        g = guestfs.GuestFS ()
+
+        self.assertEqual (g.internal_test_rbufferout ("test"), b'test')
+
+        self.assertRaises (RuntimeError, g.internal_test_rbufferouterr)
diff --git a/python/t/test100Launch.py b/python/t/test100Launch.py
new file mode 100644
index 0000000..8cd2a54
--- /dev/null
+++ b/python/t/test100Launch.py
@@ -0,0 +1,34 @@
+# libguestfs Python bindings
+# Copyright (C) 2009-2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+import os
+import guestfs
+
+class Test100Launch (unittest.TestCase):
+    def test_launch (self):
+        g = guestfs.GuestFS (python_return_dict=True)
+        g.add_drive_scratch (500 * 1024 * 1024)
+        g.launch ()
+
+        g.pvcreate ("/dev/sda")
+        g.vgcreate ("VG", ["/dev/sda"])
+        g.lvcreate ("LV1", "VG", 200)
+        g.lvcreate ("LV2", "VG", 200)
+        self.assertEqual (g.lvs (), ["/dev/VG/LV1", "/dev/VG/LV2"])
+        g.shutdown ()
+        g.close ()
diff --git a/python/t/test410CloseEvent.py b/python/t/test410CloseEvent.py
new file mode 100644
index 0000000..f541f01
--- /dev/null
+++ b/python/t/test410CloseEvent.py
@@ -0,0 +1,38 @@
+# libguestfs Python bindings
+# Copyright (C) 2011-2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+import os
+import guestfs
+
+close_invoked = 0
+
+def close_callback (ev, eh, buf, array):
+    global close_invoked
+    close_invoked += 1
+
+class Test410CloseEvent (unittest.TestCase):
+    def test_close_event (self):
+        g = guestfs.GuestFS (python_return_dict=True)
+
+        # Register a callback for the close event.
+        g.set_event_callback (close_callback, guestfs.EVENT_CLOSE)
+
+        # Close the handle.  The close callback should be invoked.
+        self.assertEqual (close_invoked, 0)
+        g.close ()
+        self.assertEqual (close_invoked, 1)
diff --git a/python/t/test420LogMessages.py b/python/t/test420LogMessages.py
new file mode 100644
index 0000000..69312ed
--- /dev/null
+++ b/python/t/test420LogMessages.py
@@ -0,0 +1,54 @@
+# libguestfs Python bindings
+# Copyright (C) 2011 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+import os
+import guestfs
+
+log_invoked = 0
+
+def log_callback (ev,eh,buf,array):
+    global log_invoked
+    log_invoked += 1
+
+    if ev == guestfs.EVENT_APPLIANCE:
+        buf = buf.rstrip()
+
+    # Log what happened.
+    print ("python event logged: event=%s eh=%d buf='%s' array=%s" %
+           (guestfs.event_to_string (ev), eh, buf, array))
+
+class Test420LogMessages (unittest.TestCase):
+    def test_log_messages (self):
+        g = guestfs.GuestFS (python_return_dict=True)
+
+        # Register an event callback for all log messages.
+        events = guestfs.EVENT_APPLIANCE | guestfs.EVENT_LIBRARY \
+                 | guestfs.EVENT_WARNING | guestfs.EVENT_TRACE
+        g.set_event_callback (log_callback, events)
+
+        # Now make sure we see some messages.
+        g.set_trace (1)
+        g.set_verbose (1)
+
+        # Do some stuff.
+        g.add_drive_ro ("/dev/null")
+        g.set_autosync (1)
+
+        g.close ()
+
+        self.assertNotEqual (log_invoked, 0)
diff --git a/python/t/test800ExplicitClose.py b/python/t/test800ExplicitClose.py
new file mode 100644
index 0000000..15b15fb
--- /dev/null
+++ b/python/t/test800ExplicitClose.py
@@ -0,0 +1,54 @@
+# libguestfs Python bindings
+# Copyright (C) 2011 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test implicit vs explicit closes of the handle (RHBZ#717786).
+
+import unittest
+import os
+import guestfs
+
+close_invoked = 0
+
+def close_callback (ev, eh, buf, array):
+    global close_invoked
+    close_invoked += 1
+
+class Test800ExplicitClose (unittest.TestCase):
+    def test_explicit_close (self):
+        g = guestfs.GuestFS (python_return_dict=True)
+
+        g.close ()              # explicit close
+        del g                   # implicit close - should be no error/warning
+
+        # Expect an exception if we call a method on a closed handle.
+        g = guestfs.GuestFS (python_return_dict=True)
+        g.close ()
+        self.assertRaises (guestfs.ClosedHandle, g.set_memsize, 512)
+        del g
+
+        # Verify that the handle is really being closed by g.close, by
+        # setting up a close event and testing that it happened.
+        g = guestfs.GuestFS (python_return_dict=True)
+
+        g.set_event_callback (close_callback, guestfs.EVENT_CLOSE)
+
+        self.assertEqual (close_invoked, 0)
+        g.close ()
+        self.assertEqual (close_invoked, 1)
+
+        del g
+        self.assertEqual (close_invoked, 1)
diff --git a/python/t/test810RHBZ811650.py b/python/t/test810RHBZ811650.py
new file mode 100644
index 0000000..6dc2da1
--- /dev/null
+++ b/python/t/test810RHBZ811650.py
@@ -0,0 +1,37 @@
+# libguestfs Python bindings
+# Copyright (C) 2012 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import unittest
+import os
+import guestfs
+
+class Test810RHBZ811650 (unittest.TestCase):
+    def test_rhbz811650 (self):
+        g = guestfs.GuestFS (python_return_dict=True)
+
+        g.disk_create ("rhbz811650.img", "raw", 500 * 1024 * 1024)
+
+        # Deliberate error: the disk format is supposed to be raw.
+        g.add_drive ("rhbz811650.img", format="qcow2");
+
+        # Because error() wasn't being called, guestfs_last_error
+        # would return NULL, causing a segfault in the Python bindings
+        # (RHBZ#811650).
+        self.assertRaises (RuntimeError, g.launch)
+
+    def tearDown (self):
+        os.unlink ("rhbz811650.img")
diff --git a/python/t/test820RHBZ912499.py b/python/t/test820RHBZ912499.py
new file mode 100644
index 0000000..4ba6f2d
--- /dev/null
+++ b/python/t/test820RHBZ912499.py
@@ -0,0 +1,94 @@
+# libguestfs Python bindings
+# Copyright (C) 2014 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test that SELinux relabelling code doesn't regress.
+# See: https://bugzilla.redhat.com/912499#c10
+#      https://bugzilla.redhat.com/1075164#c7
+
+from subprocess import check_output
+import unittest
+import random
+import string
+import os
+import sys
+import guestfs
+from .tests_helper import *
+
+ at skipUnlessArchMatches ("(i.86|x86_64)")   # If the architecture doesn't support IDE, skip the test.
+ at skipUnlessGuestfsBackendIs ('libvirt')
+ at skipUnlessLibirtHasCPointer ()
+class Test820RHBZ912499 (unittest.TestCase):
+    def setUp (self):
+        # Create a test disk.
+        self.filename = os.getcwd () + "/820-rhbz912499.img"
+        guestfs.GuestFS().disk_create (self.filename, "raw", 1024*1024*1024)
+
+        # Create a new domain.  This won't work, it will just hang when
+        # booted.  But that's sufficient for the test.
+        self.domname = ''.join (random.choice (string.ascii_uppercase)
+                                for _ in range (8))
+        self.domname = "tmp-" + self.domname
+
+        self.xml = """
+<domain type='qemu'>
+  <name>%s</name>
+  <memory>1048576</memory>
+  <vcpu>1</vcpu>
+  <os>
+    <type>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source file='%s'/>
+      <target dev='hda' bus='ide'/>
+    </disk>
+  </devices>
+</domain>
+""" % (self.domname, self.filename)
+
+    def test_rhbz912499 (self):
+        import libvirt
+
+        conn = libvirt.open (None)
+        dom = conn.createXML (self.xml,
+                              libvirt.VIR_DOMAIN_START_AUTODESTROY)
+        self.assertIsNotNone (dom)
+
+        print ("temporary domain %s is running" % self.domname)
+
+        # Libvirt should have labelled the disk.
+        print ("before starting libguestfs")
+        before = check_output (["ls", "-Z", self.filename])
+        print ("disk label = %s" % before)
+
+        # Now see if we can open the domain with libguestfs without
+        # disturbing the label.
+        g = guestfs.GuestFS ()
+        r = g.add_libvirt_dom (dom, readonly = 1)
+        self.assertEqual (r, 1)
+        g.launch ()
+
+        print ("after starting libguestfs")
+        after = check_output (["ls", "-Z", self.filename])
+        print ("disk label = %s" % after)
+
+        self.assertEqual (before, after)
+
+    def tearDown (self):
+        os.unlink (self.filename)
diff --git a/python/t/test910Libvirt.py b/python/t/test910Libvirt.py
new file mode 100644
index 0000000..f159f77
--- /dev/null
+++ b/python/t/test910Libvirt.py
@@ -0,0 +1,42 @@
+# libguestfs Python bindings
+# Copyright (C) 2014 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# The Python bindings for add_libvirt_dom require the libvirt-python
+# library to support a new method (.c_pointer()).  Ensure this keeps
+# working by testing it.  See:
+# https://bugzilla.redhat.com/show_bug.cgi?id=1075164
+
+import unittest
+import os
+import sys
+import guestfs
+from .tests_helper import *
+
+guestsdir = os.environ['guestsdir']
+
+ at skipUnlessLibirtHasCPointer ()
+class Test910Libvirt (unittest.TestCase):
+    def test_libvirt (self):
+        import libvirt
+
+        conn = libvirt.open ("test:///%s/guests.xml" % guestsdir)
+        dom = conn.lookupByName ("blank-disk")
+
+        g = guestfs.GuestFS ()
+
+        r = g.add_libvirt_dom (dom, readonly=1)
+        self.assertEqual (r, 1)
diff --git a/python/t/tests_helper.py b/python/t/tests_helper.py
new file mode 100644
index 0000000..6bbc4bc
--- /dev/null
+++ b/python/t/tests_helper.py
@@ -0,0 +1,63 @@
+# libguestfs Python bindings
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Utilities for the tests of the Python bindings.
+
+import unittest
+
+
+def skipUnlessLibirtHasCPointer ():
+    """
+    Skip the current class/method if:
+      (a) libvirt cannot be imported (e.g. not installed)
+      (b) connection objects don't have the c_pointer() method (too old)
+    """
+    try:
+        import libvirt
+    except:
+        return unittest.skip ("could not import libvirt")
+    # Check we're using the version of libvirt-python that has c_pointer() methods.
+    if not "c_pointer" in dir (libvirt.open (None)):
+        return unittest.skip ("libvirt-python doesn't support c_pointer()")
+    return lambda func: func
+
+
+def skipUnlessGuestfsBackendIs (wanted):
+    """
+    Skip the current class/method if the default backend of libguestfs
+    is not 'wanted'.
+    """
+    import guestfs
+    backend = guestfs.GuestFS ().get_backend ()
+    # Match both "backend" and "backend:etc"
+    if not (backend == wanted or backend.startswith (wanted + ":")):
+        return unittest.skip ("the current backend is not %s" % wanted)
+    return lambda func: func
+
+
+def skipUnlessArchMatches (arch_re):
+    """
+    Skip the current class/method if the current architecture does not match
+    the regexp specified.
+    """
+    import platform
+    import re
+    machine = platform.machine ()
+    rex = re.compile (arch_re)
+    if not rex.match (machine):
+        return unittest.skip ("the current architecture (%s) does not match '%s'" % (machine, arch_re))
+    return lambda func: func
-- 
2.5.0




More information about the Libguestfs mailing list