Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
05a4e60
python3: use six.string_types not version-dependant types
ydirson Jul 18, 2022
84d172a
python3: use "six.ensure_binary" and "six.ensure_text" for str/bytes …
ydirson Jul 18, 2022
7ac16be
Remove direct call's to file's constructor and replace them with call…
brettcannon May 25, 2007
520d419
python3: xcp.net.mac: use six.python_2_unicode_compatible for stringi…
ydirson Jul 18, 2022
a59c3ba
xcp.net.ifrename.logic: use "logger.warning", "logger.warn" is deprec…
ydirson Jul 18, 2022
0832486
python3: use raw strings for regexps, fixes insufficient quoting
ydirson Jul 18, 2022
7e14499
test_dom0: mock "open()" in a python3-compatible way
ydirson Jul 19, 2022
9c64243
ifrename: don't rely on dict ordering in tests
ydirson Jul 19, 2022
ae79078
test_cpio: ensure paths are handled as text
ydirson Jul 20, 2022
346ebc0
cpiofile: migrate last "list.sort()" call still using a "cmp" argument
ydirson Jul 26, 2022
5fd6cdf
WIP python3: fix xmlunwrap and its test to align with the use of bytes
ydirson Jul 25, 2022
67225f7
xcp.repository: switch from md5 to hashlib.md5
ydirson Jul 26, 2022
27fdfe9
WIP xcp.repository: switch from ConfigParser to configparser
ydirson Jul 26, 2022
b004cab
test: use parametrized tests
ydirson Sep 26, 2022
cdd5ee8
WIP test_accessor: check for I/O on binary files
ydirson Sep 26, 2022
71183e4
WIP test_accessor: write into copy file as binary
ydirson Sep 26, 2022
d6566dd
Pylint complements: honor len-as-condition convention
ydirson Jul 20, 2022
ac1b1b8
Pylint complements: whitespace in expressions
ydirson Jul 15, 2022
d58e988
Pylint complements: test_ifrename_logic: disable "no-member" warning
ydirson Aug 8, 2022
efeecfa
Pylint complements: avoid no-else-raise "refactor" issues
ydirson Aug 8, 2022
09ba68a
CI: also run tests with python3
ydirson Jul 26, 2022
74daac5
Introduce xcp.xcp_popen_text_kwargs and use it for Popen and open
bernhardkaindl Apr 20, 2023
2703d81
tests/test_pci.py: Test that xcp.pci can handle UTF-8 in hwinfo/pci.ids
bernhardkaindl Apr 20, 2023
4a522c3
Test that where required, xcp.pci and xcp.cmd support LC_CTYPE=C
bernhardkaindl Apr 20, 2023
0f0c19f
tests/test_cmd.py: Also test UTF-8 in stderr of the cmd
bernhardkaindl Apr 20, 2023
4463538
tests/test_cmd.py: Full test for stdin/stdout (UTF-8) using "cat"
bernhardkaindl Apr 20, 2023
75b2cf1
tests/test_pci.py: Verify the returned Dict to have expected content.
bernhardkaindl Apr 20, 2023
c636d9b
xcp.net.ip.ip_link_set_name(): Support Python3 and add testcase for it
bernhardkaindl Apr 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,54 @@ name: Unit tests
on: [push, pull_request]

jobs:
test_py2:
runs-on: ubuntu-20.04
test:
strategy:
matrix:
include:
- pyversion: '2.7'
os: ubuntu-20.04
- pyversion: '3'
os: ubuntu-latest
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Python 2.7
- name: Set up Python ${{ matrix.pyversion }}
uses: actions/setup-python@v2
with:
python-version: '2.7'
python-version: ${{ matrix.pyversion }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
# FIXME: branding.py still has no permanent home
curl https://gist.github.com/ydirson/3c36a7e19d762cc529a6c82340894ccc/raw/5ca39f621b1feab813e171f535c1aad1bd483f1d/branding.py -O -L
pip install pyliblzma
pip install -e .
command -v xz

- name: Test
run: |
pytest --cov -rP
coverage xml
coverage html
coverage html -d htmlcov-tests --include="tests/*"
diff-cover --html-report coverage-diff.html coverage.xml
coverage html -d htmlcov-${{ matrix.pyversion }}
coverage html -d htmlcov-tests-${{ matrix.pyversion }} --include="tests/*"
diff-cover --compare-branch=origin/master --html-report coverage-diff-${{ matrix.pyversion }}.html coverage.xml

- name: Pylint
run: |
pylint --version
pylint --exit-zero xcp/ tests/ setup.py
pylint --exit-zero --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" xcp/ tests/ setup.py > pylint.txt
diff-quality --violations=pylint --html-report pylint-diff.html pylint.txt
diff-quality --compare-branch=origin/master --violations=pylint --html-report pylint-diff-${{ matrix.pyversion }}.html pylint.txt

- uses: actions/upload-artifact@v3
with:
name: Coverage and pylint reports
path: |
coverage-diff.html
pylint-diff.html
htmlcov
htmlcov-tests
coverage-diff-${{ matrix.pyversion }}.html
pylint-diff-${{ matrix.pyversion }}.html
htmlcov-${{ matrix.pyversion }}
htmlcov-tests-${{ matrix.pyversion }}
5 changes: 5 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ diff_cover
mock
pytest
pytest-cov
parameterized
# dependencies also in setup.py until they can be used
six
future

# python-2.7 only
configparser ; python_version < "3.0"
pyliblzma ; python_version < "3.0"
Empty file added tests/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions tests/data/pci.ids
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
1314 Wrestler HDMI Audio
174b 1001 PURE Fusion Mini
1636 Renoir
67b0 Hawaii XT / Grenada XT [Radeon R9 290X/390X]
1787 2020 R9 290X IceQ X² Turbo
7340 Navi 14 [Radeon RX 5500/5500M / Pro 5500M]

# List of known device classes, subclasses and programming interfaces
Expand Down
Binary file added tests/data/repo/boot/isolinux/mboot.c32
Binary file not shown.
37 changes: 29 additions & 8 deletions tests/test_accessor.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
import unittest
import hashlib
from tempfile import NamedTemporaryFile

from parameterized import parameterized_class

import xcp.accessor

@parameterized_class([{"url": "file://tests/data/repo/"},
{"url": "https://updates.xcp-ng.org/netinstall/8.2.1"}])
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)
def test_access(self):
a = xcp.accessor.createAccessor(self.url, 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)
def test_file_binfile(self):
BINFILE = "boot/isolinux/mboot.c32"
a = xcp.accessor.createAccessor(self.url, True)
a.start()
self.assertTrue(a.access('.treeinfo'))
self.assertFalse(a.access('no_such_file'))
self.assertEqual(a.lastError, 404)
self.assertTrue(a.access(BINFILE))
inf = a.openAddress(BINFILE)
with NamedTemporaryFile("wb") as outf:
while True:
data = inf.read()
if not data: # EOF
break
outf.write(data)
outf.flush()
hasher = hashlib.md5()
with open(outf.name, "rb") as bincontents:
while True:
data = bincontents.read()
if not data: # EOF
break
hasher.update(data)
csum = hasher.hexdigest()
self.assertEqual(csum, "eab52cebc3723863432dc672360f6dac")
a.finish()
7 changes: 7 additions & 0 deletions tests/test_biosdevname.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import subprocess
import unittest
from mock import patch, Mock

from xcp import xcp_popen_text_kwargs
from xcp.net.biosdevname import has_ppn_quirks, all_devices_all_names

class TestQuirks(unittest.TestCase):
Expand Down Expand Up @@ -40,6 +42,11 @@ def test(self):

# check after the fact that we mocked the proper calls
self.assertEqual(popen_mock.call_count, 2)
popen_mock.assert_called_with(['/sbin/biosdevname', '--policy', 'all_ethN', '-d'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
**xcp_popen_text_kwargs)

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'])
Expand Down
32 changes: 26 additions & 6 deletions tests/test_cmd.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import subprocess
import unittest
from mock import patch, Mock, DEFAULT

from xcp import xcp_popen_text_kwargs
from xcp.cmd import OutputCache

from .xcptestlib import set_c_locale

set_c_locale()

class TestCache(unittest.TestCase):
def setUp(self):
self.c = OutputCache()
Expand Down Expand Up @@ -30,12 +36,14 @@ def test_fileContents(self):
self.assertEqual(data, "line1\nline2\n")

def test_runCmd(self):
output_data = "line1\nline2\n"
output_data = "output with\nUTF-8:\u25b6\U0001f601\n"
stderr_data = "error with\nUTF-8:\u2614\U0001f629\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
# `output_data` on stdout, `stderr_data` on stderr, and an exit
# value of 42
communicate_mock = Mock(return_value=(output_data, ""))
communicate_mock = Mock(return_value=(output_data, stderr_data))
popen_mock.return_value.communicate = communicate_mock
def communicate_side_effect(_input_text):
popen_mock.return_value.returncode = 42
Expand All @@ -44,11 +52,23 @@ def communicate_side_effect(_input_text):

# uncached runCmd
data = self.c.runCmd(['ls', '/tmp'], True)
popen_mock.assert_called_once()
popen_mock.assert_called_once_with(["ls", "/tmp"],
bufsize=1,
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
**xcp_popen_text_kwargs)
self.assertEqual(data, (42, output_data))

# rerun as cached
popen_mock.reset_mock()
data = self.c.runCmd(['ls', '/tmp'], True)
data = self.c.runCmd(['ls', '/tmp'], with_stdout=True, with_stderr=True)
popen_mock.assert_not_called()
self.assertEqual(data, (42, output_data))
self.assertEqual(data, (42, output_data, stderr_data))

def test_runCmdCatStdin(self):
"""Call cat with a given UTF-8 input text and expect it to be returned"""
stdin = "output with\nUTF-8:\u25b6\U0001f601"
ret = self.c.runCmd("cat", inputtext=stdin, with_stdout=True, with_stderr=True)
self.assertEqual(ret, (0, stdin, ""))
4 changes: 2 additions & 2 deletions tests/test_cpio.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ def writeRandomFile(fn, size, start=b'', add=b'a'):
with open(fn, 'wb') as f:
m = md5()
m.update(start)
assert(len(add) != 0)
assert add
while size > 0:
d = m.digest()
if size < len(d):
d=d[:size]
d = d[:size]
f.write(d)
size -= len(d)
m.update(add)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_dom0.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def mock_version(open_mock, version):
(2*1024, 4*1024, 8*1024), # Above max
]

with patch("__builtin__.open") as open_mock:
with patch("xcp.dom0.open") as open_mock:
for host_gib, dom0_mib, _ in test_values:
mock_version(open_mock, '2.8.0')
expected = dom0_mib * 1024;
Expand All @@ -39,7 +39,7 @@ def mock_version(open_mock, version):

open_mock.assert_called_with("/etc/xensource-inventory")

with patch("__builtin__.open") as open_mock:
with patch("xcp.dom0.open") as open_mock:
for host_gib, _, dom0_mib in test_values:
mock_version(open_mock, '2.9.0')
expected = dom0_mib * 1024;
Expand Down
4 changes: 2 additions & 2 deletions tests/test_ifrename_dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ def test_pci_matching_invert(self):
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", kname="eth1",
ppn="", label="")])

self.assertEqual(dr.rules,[
self.assertEqual(set(dr.rules), set([
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0")
])
]))

def test_pci_missing(self):

Expand Down
1 change: 1 addition & 0 deletions tests/test_ifrename_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ def test_ibft_nic_to_ibft(self):


class TestInputSanitisation(unittest.TestCase):
# pylint: disable=no-member

def setUp(self):
"""
Expand Down
24 changes: 12 additions & 12 deletions tests/test_ifrename_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,10 @@ def test_pci_matching(self):

sr.generate(self.state)

self.assertEqual(sr.rules,[
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth0")
])
self.assertEqual(set(sr.rules), set([
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth0")
]))

def test_pci_matching_invert(self):

Expand All @@ -389,10 +389,10 @@ def test_pci_matching_invert(self):

sr.generate(self.state)

self.assertEqual(sr.rules,[
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0")
])
self.assertEqual(set(sr.rules), set([
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0")
]))

def test_pci_matching_mixed(self):

Expand All @@ -403,10 +403,10 @@ def test_pci_matching_mixed(self):

sr.generate(self.state)

self.assertEqual(sr.rules,[
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1")
])
self.assertEqual(set(sr.rules), set([
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1")
]))

def test_pci_missing(self):

Expand Down
45 changes: 45 additions & 0 deletions tests/test_ip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Unit test for xcp/net/ip.py
import unittest
from subprocess import PIPE

from mock import Mock, patch

import xcp.net.ip
from xcp import xcp_popen_text_kwargs


class TestIp(unittest.TestCase):
def test_ip_link_set_name(self):
with patch("xcp.net.ip.Popen") as popen_mock:

# Setup the return values and return codes returned by popen_mock:
ip_link_show_lo_stdout = (
"1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state"
"UNKNOWN mode DEFAULT group default qlen 1000"
)
communicate_mock = Mock(
side_effect=iter([(ip_link_show_lo_stdout, ""), ("", "")])
)
popen_mock.return_value.communicate = communicate_mock
popen_mock.return_value.returncode = 0

# Call the testee function with xcp.net.ip.Popen() mocked using popen_mock:
xcp.net.ip.ip_link_set_name("lo", "lo0")

# check the number or calls to Popen() by done by ip_link_set_name()
self.assertEqual(popen_mock.call_count, 4)

# check the captured regular arguments passed to Popen() by ip_link_set_name()
calls = popen_mock.call_args_list
self.assertEqual(calls[0].args, (["ip", "link", "show", "lo"],))
self.assertEqual(calls[1].args, (["ip", "link", "set", "lo", "down"],))
self.assertEqual(calls[2].args, (["ip", "link", "set", "lo", "name", "lo0"],))
self.assertEqual(calls[3].args, (["ip", "link", "set", "lo0", "up"],))

# check the captured keyword arguments passed to Popen() by ip_link_set_name()
xcp_popen_text_kwargs_stdout = xcp_popen_text_kwargs.copy()
xcp_popen_text_kwargs_stdout["stdout"] = PIPE
self.assertEqual(calls[0].kwargs, xcp_popen_text_kwargs_stdout)
self.assertEqual(calls[1].kwargs, xcp_popen_text_kwargs)
self.assertEqual(calls[2].kwargs, xcp_popen_text_kwargs)
self.assertEqual(calls[3].kwargs, xcp_popen_text_kwargs)
Loading