diff --git a/tests/data/all_ethN.biosdevname b/tests/data/all_ethN.biosdevname
new file mode 100644
index 00000000..63bdc506
--- /dev/null
+++ b/tests/data/all_ethN.biosdevname
@@ -0,0 +1,68 @@
+BIOS device: eth0
+Kernel name: eth0
+Permanent MAC: EC:F4:BB:C3:AF:A8
+Assigned MAC : EC:F4:BB:C3:AF:A8
+Driver: ixgbe
+Driver version: 5.9.4
+Firmware version: 0x8000095c, 19.5.12
+Bus Info: 0000:01:00.0
+PCI name : 0000:01:00.0
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 1
+SMBIOS Label: Integrated NIC 1
+sysfs Label: NIC1
+Embedded Index: 1
+
+BIOS device: eth1
+Kernel name: eth1
+Permanent MAC: EC:F4:BB:C3:AF:AA
+Assigned MAC : EC:F4:BB:C3:AF:AA
+Driver: ixgbe
+Driver version: 5.9.4
+Firmware version: 0x8000095c, 19.5.12
+Bus Info: 0000:01:00.1
+PCI name : 0000:01:00.1
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 2
+SMBIOS Label: Integrated NIC 2
+sysfs Label: NIC2
+Embedded Index: 2
+
+BIOS device: eth2
+Kernel name: eth2
+Permanent MAC: EC:F4:BB:C3:AF:AC
+Assigned MAC : EC:F4:BB:C3:AF:AC
+Driver: igb
+Driver version: 5.3.5.20
+Firmware version: 1.67, 0x80000fab, 19.5.12
+Bus Info: 0000:07:00.0
+PCI name : 0000:07:00.0
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 3
+SMBIOS Label: Integrated NIC 3
+sysfs Label: NIC3
+VPD Port: 3
+VPD Index: 1
+VPD PCI master: 0000:07:00.0
+
+BIOS device: eth3
+Kernel name: eth3
+Permanent MAC: EC:F4:BB:C3:AF:AD
+Assigned MAC : EC:F4:BB:C3:AF:AD
+Driver: igb
+Driver version: 5.3.5.20
+Firmware version: 1.67, 0x80000fab, 19.5.12
+Bus Info: 0000:07:00.1
+PCI name : 0000:07:00.1
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 4
+SMBIOS Label: Integrated NIC 4
+sysfs Label: NIC4
+VPD Port: 4
+VPD Index: 1
+VPD PCI master: 0000:07:00.1
+
diff --git a/tests/data/grub-linux.cfg b/tests/data/grub-linux.cfg
new file mode 100644
index 00000000..e98e5d19
--- /dev/null
+++ b/tests/data/grub-linux.cfg
@@ -0,0 +1,5 @@
+set default=0
+menuentry 'linux' {
+ linux /boot/vmlinuz-1 ro
+ initrd /boot/initrd.img-1
+}
diff --git a/tests/data/grub.cfg b/tests/data/grub.cfg
new file mode 100644
index 00000000..c6d2b4a1
--- /dev/null
+++ b/tests/data/grub.cfg
@@ -0,0 +1,35 @@
+serial --unit=0 --speed=115200
+terminal_input serial console
+terminal_output serial console
+set default=0
+set timeout=5
+menuentry 'XCP-ng' {
+ search --label --set root root-vgdorj
+ multiboot2 /boot/xen.gz dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G console=vga vga=mode-0x0311
+ module2 /boot/vmlinuz-4.19-xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=hvc0 console=tty0 quiet vga=785 splash plymouth.ignore-serial-consoles
+ module2 /boot/initrd-4.19-xen.img
+}
+menuentry 'XCP-ng (Serial)' {
+ search --label --set root root-vgdorj
+ multiboot2 /boot/xen.gz com1=115200,8n1 console=com1,vga dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G
+ module2 /boot/vmlinuz-4.19-xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=tty0 console=hvc0
+ module2 /boot/initrd-4.19-xen.img
+}
+menuentry 'XCP-ng in Safe Mode' {
+ search --label --set root root-vgdorj
+ multiboot2 /boot/xen.gz nosmp noreboot noirqbalance no-mce no-bootscrub no-numa no-hap no-mmcfg max_cstate=0 nmi=ignore allow_unsafe dom0_mem=7584M,max:7584M com1=115200,8n1 console=com1,vga
+ module2 /boot/vmlinuz-4.19-xen earlyprintk=xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=tty0 console=hvc0
+ module2 /boot/initrd-4.19-xen.img
+}
+menuentry 'XCP-ng (Xen 4.13.1 / Linux 4.19.0+1)' {
+ search --label --set root root-vgdorj
+ multiboot2 /boot/xen-fallback.gz dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G
+ module2 /boot/vmlinuz-fallback root=LABEL=root-vgdorj ro nolvm hpet=disable console=hvc0 console=tty0
+ module2 /boot/initrd-fallback.img
+}
+menuentry 'XCP-ng (Serial, Xen 4.13.1 / Linux 4.19.0+1)' {
+ search --label --set root root-vgdorj
+ multiboot2 /boot/xen-fallback.gz com1=115200,8n1 console=com1,vga dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G
+ module2 /boot/vmlinuz-fallback root=LABEL=root-vgdorj ro nolvm hpet=disable console=tty0 console=hvc0
+ module2 /boot/initrd-fallback.img
+}
diff --git a/tests/data/inventory/etc/xensource-inventory b/tests/data/inventory/etc/xensource-inventory
new file mode 100644
index 00000000..950472c0
--- /dev/null
+++ b/tests/data/inventory/etc/xensource-inventory
@@ -0,0 +1,23 @@
+PRIMARY_DISK='/dev/disk/by-id/scsi-123456789012345678901234567899012'
+PRODUCT_VERSION='8.2.1'
+DOM0_VCPUS='16'
+CONTROL_DOMAIN_UUID='3b1dccee-9da4-49c6-8250-e3725e0e4b2d'
+DOM0_MEM='7584'
+COMPANY_NAME_SHORT='Open Source'
+MANAGEMENT_ADDRESS_TYPE='IPv4'
+PARTITION_LAYOUT='ROOT,BACKUP,LOG,BOOT,SWAP,SR'
+PRODUCT_VERSION_TEXT='8.2'
+PRODUCT_BRAND='XCP-ng'
+INSTALLATION_UUID='b8b63475-d28c-44d4-9d1e-c38298ad3a0d'
+PRODUCT_VERSION_TEXT_SHORT='8.2'
+BRAND_CONSOLE='XCP-ng Center'
+PRODUCT_NAME='xenenterprise'
+MANAGEMENT_INTERFACE='xapi1'
+COMPANY_PRODUCT_BRAND='XCP-ng'
+PLATFORM_VERSION='3.2.1'
+BUILD_NUMBER='release/yangtze/master/58'
+PLATFORM_NAME='XCP'
+BRAND_CONSOLE_URL='https://xcp-ng.org'
+BACKUP_PARTITION='/dev/disk/by-id/scsi-123456789012345678901234567899012-part2'
+INSTALLATION_DATE='2021-08-03 16:39:24.077945'
+COMPANY_NAME='Open Source'
diff --git a/tests/data/lspci-mn b/tests/data/lspci-mn
new file mode 100644
index 00000000..4450e6d3
--- /dev/null
+++ b/tests/data/lspci-mn
@@ -0,0 +1,36 @@
+00:00.0 "0600" "1022" "1630" "1022" "1630"
+00:00.2 "0806" "1022" "1631" "1022" "1631"
+00:01.0 "0600" "1022" "1632" "" ""
+00:01.1 "0604" "1022" "1633" "" ""
+00:02.0 "0600" "1022" "1632" "" ""
+00:02.1 "0604" "1022" "1634" "" ""
+00:02.2 "0604" "1022" "1634" "" ""
+00:02.3 "0604" "1022" "1634" "" ""
+00:08.0 "0600" "1022" "1632" "" ""
+00:08.1 "0604" "1022" "1635" "" ""
+00:08.2 "0604" "1022" "1635" "" ""
+00:14.0 "0c05" "1022" "790b" -r51 "1462" "12ac"
+00:14.3 "0601" "1022" "790e" -r51 "1462" "12ac"
+00:18.0 "0600" "1022" "1448" "" ""
+00:18.1 "0600" "1022" "1449" "" ""
+00:18.2 "0600" "1022" "144a" "" ""
+00:18.3 "0600" "1022" "144b" "" ""
+00:18.4 "0600" "1022" "144c" "" ""
+00:18.5 "0600" "1022" "144d" "" ""
+00:18.6 "0600" "1022" "144e" "" ""
+00:18.7 "0600" "1022" "144f" "" ""
+01:00.0 "0604" "1002" "1478" -rc1 "" ""
+02:00.0 "0604" "1002" "1479" "" ""
+03:00.0 "0380" "1002" "7340" -rc1 "1462" "12ac"
+03:00.1 "0403" "1002" "ab38" "1462" "12ac"
+04:00.0 "0280" "8086" "2723" -r1a "8086" "0084"
+05:00.0 "0200" "10ec" "8168" -r15 "1462" "12ac"
+06:00.0 "0108" "144d" "a808" -p02 "144d" "a801"
+07:00.0 "0300" "1002" "1636" -rc6 "1462" "12ac"
+07:00.2 "1080" "1022" "15df" "1022" "15df"
+07:00.3 "0c03" "1022" "1639" -p30 "1462" "12ac"
+07:00.4 "0c03" "1022" "1639" -p30 "1462" "12ac"
+07:00.5 "0480" "1022" "15e2" -r01 "1462" "12ac"
+07:00.6 "0403" "1022" "15e3" "1462" "12ac"
+08:00.0 "0106" "1022" "7901" -r81 -p01 "1462" "12ac"
+08:00.1 "0106" "1022" "7901" -r81 -p01 "1462" "12ac"
diff --git a/tests/data/pci.ids b/tests/data/pci.ids
new file mode 100644
index 00000000..acaccbb1
--- /dev/null
+++ b/tests/data/pci.ids
@@ -0,0 +1,29 @@
+## Excerpt from /usr/share/hwdata/pci.ids
+
+# Vendors, devices and subsystems. Please keep sorted.
+
+# Syntax:
+# vendor vendor_name
+# device device_name <-- single tab
+# subvendor subdevice subsystem_name <-- two tabs
+
+1002 Advanced Micro Devices, Inc. [AMD/ATI]
+ 1314 Wrestler HDMI Audio
+ 174b 1001 PURE Fusion Mini
+ 1636 Renoir
+ 7340 Navi 14 [Radeon RX 5500/5500M / Pro 5500M]
+
+# List of known device classes, subclasses and programming interfaces
+
+# Syntax:
+# C class class_name
+# subclass subclass_name <-- single tab
+# prog-if prog-if_name <-- two tabs
+
+C 03 Display controller
+ 00 VGA compatible controller
+ 00 VGA controller
+ 01 8514 controller
+ 01 XGA compatible controller
+ 02 3D controller
+ 80 Display controller
diff --git a/tests/data/physical.biosdevname b/tests/data/physical.biosdevname
new file mode 100644
index 00000000..3e0611d7
--- /dev/null
+++ b/tests/data/physical.biosdevname
@@ -0,0 +1,68 @@
+BIOS device: em1
+Kernel name: eth0
+Permanent MAC: EC:F4:BB:C3:AF:A8
+Assigned MAC : EC:F4:BB:C3:AF:A8
+Driver: ixgbe
+Driver version: 5.9.4
+Firmware version: 0x8000095c, 19.5.12
+Bus Info: 0000:01:00.0
+PCI name : 0000:01:00.0
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 1
+SMBIOS Label: Integrated NIC 1
+sysfs Label: NIC1
+Embedded Index: 1
+
+BIOS device: em2
+Kernel name: eth1
+Permanent MAC: EC:F4:BB:C3:AF:AA
+Assigned MAC : EC:F4:BB:C3:AF:AA
+Driver: ixgbe
+Driver version: 5.9.4
+Firmware version: 0x8000095c, 19.5.12
+Bus Info: 0000:01:00.1
+PCI name : 0000:01:00.1
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 2
+SMBIOS Label: Integrated NIC 2
+sysfs Label: NIC2
+Embedded Index: 2
+
+BIOS device: em3_1
+Kernel name: eth2
+Permanent MAC: EC:F4:BB:C3:AF:AC
+Assigned MAC : EC:F4:BB:C3:AF:AC
+Driver: igb
+Driver version: 5.3.5.20
+Firmware version: 1.67, 0x80000fab, 19.5.12
+Bus Info: 0000:07:00.0
+PCI name : 0000:07:00.0
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 3
+SMBIOS Label: Integrated NIC 3
+sysfs Label: NIC3
+VPD Port: 3
+VPD Index: 1
+VPD PCI master: 0000:07:00.0
+
+BIOS device: em4_1
+Kernel name: eth3
+Permanent MAC: EC:F4:BB:C3:AF:AD
+Assigned MAC : EC:F4:BB:C3:AF:AD
+Driver: igb
+Driver version: 5.3.5.20
+Firmware version: 1.67, 0x80000fab, 19.5.12
+Bus Info: 0000:07:00.1
+PCI name : 0000:07:00.1
+PCI Slot : embedded
+SMBIOS Device Type: Ethernet
+SMBIOS Instance: 4
+SMBIOS Label: Integrated NIC 4
+sysfs Label: NIC4
+VPD Port: 4
+VPD Index: 1
+VPD PCI master: 0000:07:00.1
+
diff --git a/tests/data/repo/.treeinfo b/tests/data/repo/.treeinfo
new file mode 100644
index 00000000..e49cb4fc
--- /dev/null
+++ b/tests/data/repo/.treeinfo
@@ -0,0 +1,34 @@
+[platform]
+name = XCP
+version = 3.2.1
+
+[branding]
+name = XCP-ng
+version = 8.2.1
+
+[build]
+number = release/yangtze/master/58
+
+[keys]
+key1 = RPM-GPG-KEY-CH-8
+key2 = RPM-GPG-KEY-CH-8-LCM
+key3 = RPM-GPG-KEY-Platform-V1
+
+[general]
+name = XCP-ng-8.2.1
+family = XCP-ng
+timestamp = 1645700813.00
+variant =
+version = 8.2.1
+packagedir =
+arch = x86_64
+
+[images-x86_64]
+kernel = boot/pxelinux/mboot.c32
+initrd = boot/vmlinuz
+boot.iso = boot/xen.gz
+
+[images-xen]
+kernel = boot/pxelinux/mboot.c32
+initrd = boot/vmlinuz
+
diff --git a/tests/data/repo/XS-PACKAGES b/tests/data/repo/XS-PACKAGES
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/data/repo/XS-REPOSITORY b/tests/data/repo/XS-REPOSITORY
new file mode 100644
index 00000000..8213385d
--- /dev/null
+++ b/tests/data/repo/XS-REPOSITORY
@@ -0,0 +1,14 @@
+
+
+
+ Description
+
+
+
+
diff --git a/tests/data/repo/XS-REPOSITORY-LIST b/tests/data/repo/XS-REPOSITORY-LIST
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/data/repo/repodata/repomd.xml b/tests/data/repo/repodata/repomd.xml
new file mode 100644
index 00000000..43ef48d8
--- /dev/null
+++ b/tests/data/repo/repodata/repomd.xml
@@ -0,0 +1,55 @@
+
+
+ 1645708616
+
+ f8454f26592a0669368825d673edc18a067d8a434f2d3ceaa03cdb45e72572e8
+ 6f2d69e90edbe7b3eb83654995dc07c6e577d8fc2f9ee7ec7f4f206ed486218b
+
+ 1645708616
+ 208220
+ 1449213
+
+
+ 4e678f6ce4fc197faef2c75645d00c79ee8b70d3210aa2f692fe432ed223c695
+ cea7a040a15876aba2238f3b8910cd48ded102ff0d4976df81903a3bc4ae8586
+
+ 1645708616
+ 265582
+ 2704673
+
+
+ a19f12f68c74459bc9fc7887376408b4c8dc9e84876ebbf3301afec79f110a7b
+ 46a83a4100e33249a95462d7ed54cb71ee4a178db8f2346b83f1ba5f1a5d47dc
+
+ 1645708616
+ 204512
+ 1054253
+
+
+ 34a89554a4214fde5b473ddcf1d9be796801e8e8676cda860a3d032a7e8b10d8
+ 1fc99d5403906556e8fc91d2121816354cac667741f1a04f51988b5cc3e01b98
+
+ 1645708616
+ 419050
+ 1754112
+ 10
+
+
+ f4c416c2cf253741749420300109cf8a046e0cdd27c269e69795a9ecc092669b
+ 1de3d29150b9da80b10c95b913c91369f3b7d03bb2ed57eedf511038e4537c50
+
+ 1645708616
+ 323942
+ 1380352
+ 10
+
+
+ 4a192c51fff556d2f1fdbb8f90b5454558c910a50674e65b7cdfacd5f791fdb5
+ 23dbdc6ce9ece7f1d3ac3d7b31cd61b4019e96ef01903975516fd5e3083de32a
+
+ 1645708616
+ 243295
+ 988160
+ 10
+
+
diff --git a/tests/test_accessor.py b/tests/test_accessor.py
new file mode 100644
index 00000000..ade787e6
--- /dev/null
+++ b/tests/test_accessor.py
@@ -0,0 +1,21 @@
+import unittest
+
+import xcp.accessor
+
+class TestAccessor(unittest.TestCase):
+ def test_http(self):
+ raise unittest.SkipTest("comment out if you really mean it")
+ a = xcp.accessor.createAccessor("https://updates.xcp-ng.org/netinstall/8.2.1", True)
+ a.start()
+ self.assertTrue(a.access('.treeinfo'))
+ self.assertFalse(a.access('no_such_file'))
+ self.assertEqual(a.lastError, 404)
+ a.finish()
+
+ def test_file(self):
+ a = xcp.accessor.createAccessor("file://tests/data/repo/", True)
+ a.start()
+ self.assertTrue(a.access('.treeinfo'))
+ self.assertFalse(a.access('no_such_file'))
+ self.assertEqual(a.lastError, 404)
+ a.finish()
diff --git a/tests/test_biosdevname.py b/tests/test_biosdevname.py
index 07133bec..75a3a266 100644
--- a/tests/test_biosdevname.py
+++ b/tests/test_biosdevname.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+import unittest
+from mock import patch, Mock
-import unittest, sys, os, os.path as path
-from xcp.net.biosdevname import has_ppn_quirks
+from xcp.net.biosdevname import has_ppn_quirks, all_devices_all_names
class TestQuirks(unittest.TestCase):
@@ -24,6 +24,25 @@ def test_ppn_true(self):
{"SMBIOS Instance": 1}
]))
-
-if __name__ == "__main__":
- sys.exit(unittest.main())
+class TestDeviceNames(unittest.TestCase):
+ def test(self):
+ with patch("xcp.net.biosdevname.Popen") as popen_mock:
+ with open("tests/data/physical.biosdevname") as f:
+ fake_output_1 = f.read()
+ with open("tests/data/all_ethN.biosdevname") as f:
+ fake_output_2 = f.read()
+ communicate_mock = Mock(side_effect=iter([(fake_output_1, ""),
+ (fake_output_2, "")]))
+ popen_mock.return_value.communicate = communicate_mock
+ popen_mock.return_value.returncode = 0
+
+ devices = all_devices_all_names()
+
+ # check after the fact that we mocked the proper calls
+ self.assertEqual(popen_mock.call_count, 2)
+ calls = popen_mock.call_args_list
+ self.assertEqual(calls[0].args[0], ['/sbin/biosdevname', '--policy', 'physical', '-d'])
+ self.assertEqual(calls[1].args[0], ['/sbin/biosdevname', '--policy', 'all_ethN', '-d'])
+
+ self.assertEqual(devices['eth0']['BIOS device'],
+ {'all_ethN': 'eth0', 'physical': 'em1'})
diff --git a/tests/test_bootloader.py b/tests/test_bootloader.py
new file mode 100644
index 00000000..2e5700b5
--- /dev/null
+++ b/tests/test_bootloader.py
@@ -0,0 +1,59 @@
+import unittest
+import os
+import shutil
+import subprocess
+from tempfile import NamedTemporaryFile, mkdtemp
+
+from xcp.bootloader import Bootloader
+
+class TestBootloader(unittest.TestCase):
+ def test_grub2(self):
+ bl = Bootloader.readGrub2("tests/data/grub.cfg")
+ with NamedTemporaryFile("w") as temp:
+ bl.writeGrub2(temp.name)
+ # get a diff
+ proc = subprocess.Popen(["diff", "tests/data/grub.cfg", temp.name],
+ stdout = subprocess.PIPE,
+ universal_newlines=True)
+ for line in proc.stdout:
+ # FIXME: check is entirely ad-hoc, should we have a diff at all ?
+ self.assertRegexpMatches(line, r"^(5a6,13$|>)")
+
+ proc.stdout.close()
+ proc.wait()
+
+class TestLinuxBootloader(unittest.TestCase):
+ def setUp(self):
+ self.tmpdir = mkdtemp(prefix="testbl")
+ bootdir = os.path.join(self.tmpdir, "boot")
+ grubdir = os.path.join(bootdir, "grub")
+ os.makedirs(grubdir)
+ shutil.copyfile("tests/data/grub-linux.cfg", os.path.join(grubdir, "grub.cfg"))
+ with open(os.path.join(bootdir, "vmlinuz-1"), "w"):
+ pass
+ with open(os.path.join(bootdir, "vmlinuz-2"), "w"):
+ pass
+ with open(os.path.join(bootdir, "initrd.img-1"), "w"):
+ pass
+ with open(os.path.join(bootdir, "initrd.img-2"), "w"):
+ pass
+ def tearDown(self):
+ shutil.rmtree(self.tmpdir)
+ def test_grub2_newdefault(self):
+ Bootloader.newDefault("/boot/vmlinuz-2", "/boot/initrd.img-2", root=self.tmpdir)
+
+class TestBootloaderAdHoc(unittest.TestCase):
+ def setUp(self):
+ self.bl = Bootloader.readGrub2("tests/data/grub.cfg")
+
+ def test_grub(self):
+ with NamedTemporaryFile("w", delete=False) as temp:
+ self.bl.writeGrub(temp)
+ bl2 = Bootloader.readGrub(temp.name)
+ os.unlink(temp.name)
+
+ def test_extlinux(self):
+ with NamedTemporaryFile("w", delete=False) as temp:
+ self.bl.writeExtLinux(temp)
+ bl2 = Bootloader.readExtLinux(temp.name)
+ os.unlink(temp.name)
diff --git a/tests/test_cmd.py b/tests/test_cmd.py
new file mode 100644
index 00000000..c6304873
--- /dev/null
+++ b/tests/test_cmd.py
@@ -0,0 +1,54 @@
+import unittest
+from mock import patch, Mock, DEFAULT
+
+from xcp.cmd import OutputCache
+
+class TestCache(unittest.TestCase):
+ def setUp(self):
+ self.c = OutputCache()
+
+ def test_fileContents(self):
+ with patch("xcp.cmd.open") as open_mock:
+ open_mock.return_value.readlines = Mock(return_value=["line1\n", "line2\n"])
+
+ # uncached fileContents
+ data = self.c.fileContents('/tmp/foo')
+ open_mock.assert_called_once_with("/tmp/foo")
+ self.assertEqual(data, "line1\nline2\n")
+
+ # rerun as cached
+ open_mock.reset_mock()
+ data = self.c.fileContents('/tmp/foo')
+ open_mock.assert_not_called()
+ self.assertEqual(data, "line1\nline2\n")
+
+ # rerun after clearing cache
+ open_mock.reset_mock()
+ self.c.clearCache()
+ data = self.c.fileContents('/tmp/foo')
+ open_mock.assert_called_once_with("/tmp/foo")
+ self.assertEqual(data, "line1\nline2\n")
+
+ def test_runCmd(self):
+ output_data = "line1\nline2\n"
+ with patch("xcp.cmd.subprocess.Popen") as popen_mock:
+ # mock Popen .communicate and .returncode for
+ # `output_data`on stdout, nothing on stderr, and exit
+ # value of 42
+ communicate_mock = Mock(return_value=(output_data, ""))
+ popen_mock.return_value.communicate = communicate_mock
+ def communicate_side_effect(_input_text):
+ popen_mock.return_value.returncode = 42
+ return DEFAULT
+ communicate_mock.side_effect = communicate_side_effect
+
+ # uncached runCmd
+ data = self.c.runCmd(['ls', '/tmp'], True)
+ popen_mock.assert_called_once()
+ self.assertEqual(data, (42, output_data))
+
+ # rerun as cached
+ popen_mock.reset_mock()
+ data = self.c.runCmd(['ls', '/tmp'], True)
+ popen_mock.assert_not_called()
+ self.assertEqual(data, (42, output_data))
diff --git a/tests/test_cpio.py b/tests/test_cpio.py
index 33084484..84763b26 100644
--- a/tests/test_cpio.py
+++ b/tests/test_cpio.py
@@ -1,10 +1,10 @@
-#!/usr/bin/env python
-
-import unittest, sys, os, os.path as path
+import os
+import shutil
+import subprocess
+import unittest
import warnings
-from xcp.cpiofile import CpioFile, CpioInfo
-import subprocess, shutil
+from xcp.cpiofile import CpioFile, CpioInfo, CpioFileCompat, CPIO_PLAIN, CPIO_GZIPPED
try:
from hashlib import md5
@@ -53,7 +53,7 @@ def setUp(self):
self.doXZ = False
def tearDown(self):
- check_call("rm -rf archive archive.cpio*")
+ check_call("rm -rf archive archive.cpio* archive2")
# TODO check with file (like 'r:*')
# TODO use cat to check properly for pipes
@@ -66,13 +66,25 @@ def archiveExtract(self, fn, fmt='r|*'):
self.assertEqual(len(data), f.size)
self.assertEqual(self.md5data, md5(data).hexdigest())
found = True
+ arc.close()
self.assertTrue(found)
+ # extract with extractall and compare
+ arc = CpioFile.open(fn, fmt)
+ check_call("rm -rf archive2")
+ os.rename('archive', 'archive2')
+ arc.extractall()
+ check_call("diff -rq archive2 archive")
+ arc.close()
def archiveCreate(self, fn, fmt='w'):
os.unlink(fn)
arc = CpioFile.open(fn, fmt)
f = arc.getcpioinfo('archive/data')
arc.addfile(f, open('archive/data'))
+ # test recursively add "."
+ os.chdir('archive')
+ arc.add(".")
+ os.chdir("..")
# TODO add self crafted file
arc.close()
# special case for XZ, test check type (crc32)
@@ -104,5 +116,42 @@ def test_xz(self):
print 'Running test for XZ'
self.doArchive('archive.cpio.xz', 'xz')
-if __name__ == "__main__":
- unittest.main()
+ # CpioFileCompat testing
+
+ def archiveExtractCompat(self, fn, comp):
+ arc = CpioFileCompat(fn, mode="r", compression={"": CPIO_PLAIN,
+ "gz": CPIO_GZIPPED}[comp])
+ found = False
+ for f in arc.namelist():
+ info = arc.getinfo(f)
+ if info.isfile():
+ data = arc.read(f)
+ self.assertEqual(len(data), info.size)
+ self.assertEqual(self.md5data, md5(data).hexdigest())
+ found = True
+ arc.close()
+ self.assertTrue(found)
+
+ def archiveCreateCompat(self, fn, comp):
+ if os.path.exists(fn):
+ os.unlink(fn)
+ arc = CpioFileCompat(fn, mode="w", compression={"": CPIO_PLAIN,
+ "gz": CPIO_GZIPPED}[comp])
+ arc.write('archive/data')
+ arc.close()
+ self.archiveExtract(fn)
+
+ def doArchiveCompat(self, fn, fmt):
+ self.archiveExtractCompat(fn, fmt)
+
+ fn2 = "archive2" + fn[len("archive"):]
+ self.archiveCreateCompat(fn2, fmt)
+ self.archiveExtractCompat(fn2, fmt)
+
+ def test_compat_plain(self):
+ self.doArchiveCompat('archive.cpio', '')
+
+ def test_compat_gz(self):
+ # FIXME: this test exhibits "unclosed file" warnings when run
+ # under `-Wd`
+ self.doArchiveCompat('archive.cpio.gz', 'gz')
diff --git a/tests/test_dom0.py b/tests/test_dom0.py
index 2fc1746d..bf198341 100644
--- a/tests/test_dom0.py
+++ b/tests/test_dom0.py
@@ -1,9 +1,7 @@
-#!/usr/bin/env python
-
-import unittest, sys, os
+import unittest
+from mock import patch, Mock
from xcp.dom0 import default_memory, parse_mem, default_vcpus
-from mock import patch, Mock
class TestDom0(unittest.TestCase):
@@ -112,6 +110,3 @@ def test_default_vcpus(self):
for host_pcpus, mem, expected in test_values:
calculated = default_vcpus(host_pcpus, mem)
self.assertEqual(calculated, expected)
-
-if __name__ == "__main__":
- sys.exit(unittest.main())
diff --git a/tests/test_environ.py b/tests/test_environ.py
new file mode 100644
index 00000000..8b0da44e
--- /dev/null
+++ b/tests/test_environ.py
@@ -0,0 +1,8 @@
+import unittest
+import xcp.environ
+
+class TestEnviron(unittest.TestCase):
+ def test_read_inventory(self):
+ inventory = xcp.environ.readInventory(root="tests/data/inventory")
+ self.assertEqual(inventory["COMPANY_PRODUCT_BRAND"], 'XCP-ng')
+ self.assertEqual(inventory["COMPANY_NAME"], 'Open Source')
diff --git a/tests/test_ifrename_dynamic.py b/tests/test_ifrename_dynamic.py
index 2048f762..1eb28a74 100644
--- a/tests/test_ifrename_dynamic.py
+++ b/tests/test_ifrename_dynamic.py
@@ -1,7 +1,6 @@
-#!/usr/bin/env python
-
-import unittest, sys, os, os.path as path, logging
import json
+import logging
+import unittest
from copy import deepcopy
try:
@@ -175,7 +174,3 @@ def test_one_ibft_lastboot(self):
self.assertEqual(json.loads(dr.write(False)), {'lastboot': [],
'old': []})
-
-
-if __name__ == "__main__":
- sys.exit(unittest.main())
diff --git a/tests/test_ifrename_logic.py b/tests/test_ifrename_logic.py
index 326f8acb..9fa9255c 100644
--- a/tests/test_ifrename_logic.py
+++ b/tests/test_ifrename_logic.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
-
-import unittest, sys, os, os.path as path, logging
+import logging
+import sys
+import unittest
from copy import deepcopy
try:
@@ -651,6 +651,3 @@ def test_oldstate_input(self):
self.assertNotRaises(OldStateError, rename,
[], [], [], [self.s123])
-
-if __name__ == "__main__":
- sys.exit(unittest.main())
diff --git a/tests/test_ifrename_static.py b/tests/test_ifrename_static.py
index 8b72b607..16909142 100644
--- a/tests/test_ifrename_static.py
+++ b/tests/test_ifrename_static.py
@@ -1,6 +1,5 @@
-#!/usr/bin/env python
-
-import unittest, sys, os, os.path as path, logging
+import logging
+import unittest
from copy import deepcopy
try:
@@ -473,7 +472,3 @@ def test_two_valid(self):
)
self.assertEqual(sr.write(False), desired_result)
-
-
-if __name__ == "__main__":
- sys.exit(unittest.main())
diff --git a/tests/test_mac.py b/tests/test_mac.py
index 77ef2e79..310e17e3 100644
--- a/tests/test_mac.py
+++ b/tests/test_mac.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python
-
-import unittest, sys, os, os.path as path
+import unittest
from xcp.net.mac import MAC
@@ -235,6 +233,3 @@ def test_keys(self):
self.assertEqual(d[m1], "zero")
self.assertEqual(d[m2], "ascending")
self.assertEqual(d[m3], "random")
-
-if __name__ == "__main__":
- sys.exit(unittest.main())
diff --git a/tests/test_pci.py b/tests/test_pci.py
index 65fcd796..736b55de 100644
--- a/tests/test_pci.py
+++ b/tests/test_pci.py
@@ -1,8 +1,8 @@
-#!/usr/bin/env python
+import subprocess
+import unittest
+from mock import patch, Mock
-import unittest, sys, os, os.path as path
-
-from xcp.pci import PCI
+from xcp.pci import PCI, PCIIds, PCIDevices
class TestInvalid(unittest.TestCase):
@@ -56,5 +56,49 @@ def test_equality(self):
self.assertEqual(PCI("0000:00:00.0"), PCI("00:00.0"))
-if __name__ == "__main__":
- sys.exit(unittest.main())
+class TestPCIIds(unittest.TestCase):
+ def tests_nodb(self):
+ with patch("xcp.pci.os.path.exists") as exists_mock:
+ exists_mock.return_value = False
+ with self.assertRaises(Exception):
+ PCIIds.read()
+ exists_mock.assert_called_once_with("/usr/share/hwdata/pci.ids")
+
+ def tests_videoclass(self):
+ with patch("xcp.pci.os.path.exists") as exists_mock, \
+ patch("xcp.pci.open") as open_mock, \
+ open("tests/data/pci.ids") as fake_data:
+ exists_mock.return_value = True
+ open_mock.return_value.__iter__ = Mock(return_value=iter(fake_data))
+ ids = PCIIds.read()
+ exists_mock.assert_called_once_with("/usr/share/hwdata/pci.ids")
+ open_mock.assert_called_once_with("/usr/share/hwdata/pci.ids")
+ video_class = ids.lookupClass('Display controller')
+ self.assertEqual(video_class, ['03'])
+
+ with patch("xcp.pci.subprocess.Popen") as popen_mock, \
+ open("tests/data/lspci-mn") as fake_data:
+ popen_mock.return_value.stdout.__iter__ = Mock(return_value=iter(fake_data))
+ devs = PCIDevices()
+ popen_mock.assert_called_once_with(['lspci', '-mn'], bufsize = 1,
+ stdout = subprocess.PIPE)
+ sorted_devices = sorted(devs.findByClass(video_class),
+ key=lambda x: x['id'])
+ self.assertEqual(len(sorted_devices), 2)
+
+ for (video_dev,
+ num_functions,
+ vendor,
+ device,
+ ) in zip(sorted_devices,
+ (1, 5),
+ ("Advanced Micro Devices, Inc. [AMD/ATI]",
+ "Advanced Micro Devices, Inc. [AMD/ATI]"),
+ ("Navi 14 [Radeon RX 5500/5500M / Pro 5500M]",
+ "Renoir"),
+ ):
+ self.assertEqual(len(devs.findRelatedFunctions(video_dev['id'])), num_functions)
+ self.assertEqual(ids.findVendor(video_dev['vendor']), vendor)
+ self.assertEqual(ids.findDevice(video_dev['vendor'], video_dev['device']), device)
+
+ self.assertEqual(len(devs.findRelatedFunctions('00:18.1')), 7)
diff --git a/tests/test_repository.py b/tests/test_repository.py
new file mode 100644
index 00000000..833627d0
--- /dev/null
+++ b/tests/test_repository.py
@@ -0,0 +1,25 @@
+import unittest
+
+import xcp.accessor
+from xcp import repository
+from xcp.version import Version
+
+class TestRepository(unittest.TestCase):
+ def test_http(self):
+ raise unittest.SkipTest("comment out if you really mean it")
+ a = xcp.accessor.createAccessor("https://updates.xcp-ng.org/netinstall/8.2.1", True)
+ repo_ver = repository.BaseRepository.getRepoVer(a)
+ self.assertEqual(repo_ver, Version([3, 2, 1]))
+ product_ver = repository.BaseRepository.getProductVersion(a)
+ self.assertEqual(product_ver, Version([8, 2, 1]))
+ repos = repository.BaseRepository.findRepositories(a)
+ self.assertEqual(len(repos), 1)
+
+ def test_file(self):
+ a = xcp.accessor.createAccessor("file://tests/data/repo/", True)
+ repo_ver = repository.BaseRepository.getRepoVer(a)
+ self.assertEqual(repo_ver, Version([3, 2, 1]))
+ product_ver = repository.BaseRepository.getProductVersion(a)
+ self.assertEqual(product_ver, Version([8, 2, 1]))
+ repos = repository.BaseRepository.findRepositories(a)
+ self.assertEqual(len(repos), 1)
diff --git a/tests/test_xmlunwrap.py b/tests/test_xmlunwrap.py
new file mode 100644
index 00000000..f71d778f
--- /dev/null
+++ b/tests/test_xmlunwrap.py
@@ -0,0 +1,37 @@
+import unittest
+import xml.dom.minidom
+
+from xcp.xmlunwrap import (getElementsByTagName, getText, getMapAttribute,
+ getStrAttribute, XmlUnwrapError)
+
+class TestXmlUnwrap(unittest.TestCase):
+ def setUp(self):
+ a_text = """
+ text1
+ text2
+ """
+ xmldoc = xml.dom.minidom.parseString(a_text)
+ self.top_el = xmldoc.documentElement
+
+ def test(self):
+ self.assertEqual(self.top_el.tagName, "installation")
+
+ self.assertEqual([getText(el)
+ for el in getElementsByTagName(self.top_el, ["fred"])],
+ ["text1", "text2"])
+
+ x = getMapAttribute(self.top_el, ["mode"], [('test', 42), ('stuff', 77)])
+ self.assertEqual(x, 42)
+ x = getMapAttribute(self.top_el, ["made"], [('test', 42), ('stuff', 77)],
+ default='stuff')
+ self.assertEqual(x, 77)
+
+ x = getStrAttribute(self.top_el, ["mode"])
+ self.assertEqual(x, "test")
+ x = getStrAttribute(self.top_el, ["made"])
+ self.assertEqual(x, "")
+ x = getStrAttribute(self.top_el, ["made"], None)
+ self.assertEqual(x, None)
+
+ with self.assertRaises(XmlUnwrapError):
+ x = getStrAttribute(self.top_el, ["made"], mandatory=True)
diff --git a/xcp/bootloader.py b/xcp/bootloader.py
index e1af85f6..51e362e8 100644
--- a/xcp/bootloader.py
+++ b/xcp/bootloader.py
@@ -466,10 +466,10 @@ def writeExtLinux(self, dst_file = None):
if self.serial:
if self.serial.get('flow', None) is None:
- print >> fh, "serial %d %d" % (self.serial['port'],
+ print >> fh, "serial %s %s" % (self.serial['port'],
self.serial['baud'])
else:
- print >> fh, "serial %d %d %s" % (self.serial['port'],
+ print >> fh, "serial %s %s %s" % (self.serial['port'],
self.serial['baud'],
self.serial['flow'])
if self.default:
@@ -507,7 +507,7 @@ def writeGrub(self, dst_file = None):
print >> fh, "# location " + self.location
if self.serial:
- print >> fh, "serial --unit=%d --speed=%s" % (self.serial['port'],
+ print >> fh, "serial --unit=%s --speed=%s" % (self.serial['port'],
self.serial['baud'])
print >> fh, "terminal --timeout=10 console serial"
else:
@@ -540,7 +540,7 @@ def writeGrub2(self, dst_file = None):
fh = open(dst_file, 'w')
if self.serial:
- print >> fh, "serial --unit=%d --speed=%s" % (self.serial['port'],
+ print >> fh, "serial --unit=%s --speed=%s" % (self.serial['port'],
self.serial['baud'])
print >> fh, "terminal_input serial console"
print >> fh, "terminal_output serial console"
diff --git a/xcp/cmd.py b/xcp/cmd.py
index b51eaa8a..ff039484 100644
--- a/xcp/cmd.py
+++ b/xcp/cmd.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
# Copyright (c) 2013, Citrix Inc.
# All rights reserved.
#
@@ -89,12 +87,3 @@ def runCmd(self, command, with_stdout = False, with_stderr = False, inputtext =
def clearCache(self):
self.cache.clear()
-
-if __name__ == '__main__':
- c = OutputCache()
- print c.fileContents('/tmp/foo')
- print c.fileContents('/tmp/foo')
- c.clearCache()
- print c.fileContents('/tmp/foo')
- print c.runCmd(['ls', '/tmp'], True)
- print c.runCmd(['ls', '/tmp'], True)
diff --git a/xcp/cpiofile.py b/xcp/cpiofile.py
index d6163849..a490aeff 100755
--- a/xcp/cpiofile.py
+++ b/xcp/cpiofile.py
@@ -1158,6 +1158,7 @@ def xzopen(cls, name, mode="r", fileobj=None, compresslevel=6):
if fileobj is not None:
fileobj = _XZProxy(fileobj, mode)
else:
+ # FIXME: not compatible with python3 API
fileobj = lzma.LZMAFile(name, mode, options={'level': compresslevel, 'dict_size': 20 })
try:
diff --git a/xcp/net/biosdevname.py b/xcp/net/biosdevname.py
index e8166807..78995056 100644
--- a/xcp/net/biosdevname.py
+++ b/xcp/net/biosdevname.py
@@ -35,19 +35,6 @@
__ALL_POLICIES = [ "physical", "all_ethN" ]
-def __run_single_device(eth, policy = "physical"):
- """
- Run 'biosdevname -i eth' for a specified policy.
- Return (stdout, stderr, returncode) tuple.
- """
-
- proc = Popen(["/sbin/biosdevname", "--policy", policy,
- "-i"], stdout=PIPE, stderr=PIPE)
-
- stdout, stderr = proc.communicate()
-
- return ( stdout, stderr, proc.returncode )
-
def __run_all_devices(policy = "physical"):
"""
Run 'biosdevname -d' for a specified policy.
diff --git a/xcp/pci.py b/xcp/pci.py
index c1fc90e3..8b371152 100644
--- a/xcp/pci.py
+++ b/xcp/pci.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
# Copyright (c) 2013, Citrix Inc.
# All rights reserved.
#
@@ -314,17 +312,3 @@ def pci_sbdfi_to_nic(sbdfi, nics):
raise Exception("Insufficient NICs with PCI SBDF %s (Found %d, wanted at least %d)" % (value, len(matching_nics), index))
return matching_nics[index]
-
-
-if __name__ == "__main__":
- IDS = PCIIds.read()
- VIDEO_CLASS = IDS.lookupClass('Display controller')
-
- DEVS = PCIDevices()
- for video_dev in DEVS.findByClass(VIDEO_CLASS):
- print video_dev['id'], IDS.findVendor(video_dev['vendor']), \
- IDS.findDevice(video_dev['vendor'], video_dev['device'])
- print DEVS.findRelatedFunctions(video_dev['id'])
- print DEVS.findRelatedFunctions('00:1d.1')
-
-
diff --git a/xcp/xmlunwrap.py b/xcp/xmlunwrap.py
index 3256cab3..654b84bf 100644
--- a/xcp/xmlunwrap.py
+++ b/xcp/xmlunwrap.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
# Copyright (c) 2013, Citrix Inc.
# All rights reserved.
#
@@ -25,9 +23,6 @@
"""xmlunwrap - general methods to unwrap XML elements & attributes"""
-import xml.dom.minidom
-
-
class XmlUnwrapError(Exception):
pass
@@ -87,25 +82,3 @@ def getMapAttribute(el, attrs, mapping, default = None):
k_list = list(k)
return v[k_list.index(key)]
-
-if __name__ == '__main__':
-
- a_text = """
- text1
- text2
- """
- xmldoc = xml.dom.minidom.parseString(a_text)
- top_el = xmldoc.documentElement
-
- print top_el.tagName
-
- for el in getElementsByTagName(top_el, ["fred"]):
- print getText(el)
-
- print getMapAttribute(top_el, ["mode"], [('test', 42), ('stuff', 77)])
- print getMapAttribute(top_el, ["made"], [('test', 42), ('stuff', 77)], default = 'stuff')
-
- print getStrAttribute(top_el, ["mode"])
- print getStrAttribute(top_el, ["made"])
- print getStrAttribute(top_el, ["made"], None)
- print getStrAttribute(top_el, ["made"], mandatory = True)