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)