[master 1/4] tests: add dd_tests

wgwoods installerbot-noreply at redhat.com
Wed Jun 24 16:29:53 UTC 2015


From: Will Woods <wwoods at redhat.com>

Add a test suite for the dd_list and dd_extract utilities (in utils/dd).

Note that there are two tests that fail here - test_dd_extract_chmod()
covers a known bug (#1222056), but test_dd_extract_libs() fails due to a
previously-unknown bug in the handling of `dd_extract --libraries`.

So, y'know. If you want proof that writing tests *does* help find/fix
bugs..  there you go!
---
 anaconda.spec.in          |   1 +
 tests/dd_tests/dd_test.py | 252 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 tests/dd_tests/dd_test.py

diff --git a/anaconda.spec.in b/anaconda.spec.in
index 93092f2..ce66ea3 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -59,6 +59,7 @@ BuildRequires: python3-bugzilla
 %endif
 BuildRequires: python3-devel
 BuildRequires: python3-nose
+BuildRequires: python-rpmfluff
 BuildRequires: systemd
 # rpm and libarchive are needed for driver disk handling
 BuildRequires: rpm-devel >= %{rpmver}
diff --git a/tests/dd_tests/dd_test.py b/tests/dd_tests/dd_test.py
new file mode 100644
index 0000000..a254eba
--- /dev/null
+++ b/tests/dd_tests/dd_test.py
@@ -0,0 +1,252 @@
+#!/usr/bin/python
+# unit tests for driver disk utilities (utils/dd)
+
+import os
+import shutil
+import unittest
+import tempfile
+import subprocess
+
+from contextlib import contextmanager
+from collections import namedtuple
+from rpmfluff import SourceFile, SimpleRpmBuild, expectedArch
+
+TOP_SRCDIR = os.environ.get("top_srcdir", "../..")
+UTILDIR = os.path.join(TOP_SRCDIR, "utils/dd")
+
+# helpers for calling the utilities
+Driver = namedtuple("Driver", "source name flags description")
+def dd_list(dd_path, kernel_ver, anaconda_ver):
+    out = subprocess.check_output([os.path.join(UTILDIR, "dd_list"),
+            '-d', dd_path, '-k', kernel_ver, '-a', anaconda_ver],
+            stderr=open('/dev/null'))
+    return [Driver(*d.split('\n',3)) for d in out.split('\n---\n')[:-1]]
+
+def dd_extract(rpm_path, outdir, kernel_ver, flags='-blmf'):
+    out = subprocess.check_output([os.path.join(UTILDIR, "dd_extract"),
+            flags, '-r', rpm_path, '-d', outdir, '-k', kernel_ver],
+            stderr=subprocess.STDOUT)
+    return out
+
+# helpers for creating RPMs to test with
+ at contextmanager
+def in_tempdir(prefix='tmp'):
+    oldcwd = os.getcwd()
+    tmpdir = tempfile.mkdtemp(prefix=prefix)
+    os.chdir(tmpdir)
+    yield
+    os.chdir(oldcwd)
+    shutil.rmtree(tmpdir)
+
+def make_rpm(outdir, name='test', version='1.0', release='1', arch=None,
+             for_anaconda_ver=None, for_kernel_ver=None,
+             payload=None):
+    p = SimpleRpmBuild(name, version, release)
+    if for_anaconda_ver:
+        p.add_provides('installer-enhancement = %s' % for_anaconda_ver)
+    if for_kernel_ver:
+        p.add_provides('kernel-modules >= %s' % for_kernel_ver)
+    if payload is None:
+        payload = []
+    for item in payload:
+        p.add_installed_file(item.path,
+                             SourceFile(item.srcpath, item.contents),
+                             **item.kwargs)
+    with in_tempdir("anaconda-test-dd."):
+        p.make()
+        rpmfile = p.get_built_rpm(arch or expectedArch)
+        outfile = os.path.join(outdir, os.path.basename(rpmfile))
+        shutil.move(rpmfile, outfile)
+    return p
+
+class RPMFile(object):
+    """simple container object for information about RPM payloads"""
+    def __init__(self, path, srcpath=None, contents='', **kwargs):
+        self.path = path
+        self.srcpath = srcpath or os.path.basename(path)
+        self.contents = contents
+        self.kwargs = kwargs
+
+binfile = RPMFile(
+    path="/usr/bin/fun",
+    contents="#!/bin/sh\necho WHEE\n",
+    mode="0755"
+)
+libfile = RPMFile(
+    path="/usr/lib/fun.so",
+    contents="I AM TOTALLY A SHARED LIBRARY",
+    mode="0755"
+)
+fwfile = RPMFile(
+    path="/lib/firmware/fun.fw",
+    contents="HELLO I AM FIRMWARE"
+)
+kofile = RPMFile(
+    path="/lib/modules/KERNELVER/extra/net/fun.ko",
+    contents="KERNEL MODULE??? YOU BETCHA"
+)
+
+# Finally, the actual test cases
+class ASelfTestCase(unittest.TestCase):
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp(prefix="dd_tests.")
+
+    def tearDown(self):
+        shutil.rmtree(self.tmpdir)
+
+    def test_rpmfluff_simple(self):
+        """check if rpmfluff is working"""
+        p = make_rpm(outdir=self.tmpdir)
+        rpmfile = os.path.basename(p.get_built_rpm(expectedArch))
+        self.assertTrue(rpmfile in os.listdir(self.tmpdir))
+
+    def test_rpmfluff_payload(self):
+        """check if rpmfluff can add files to built RPMs"""
+        p = make_rpm(outdir=self.tmpdir, payload=(binfile, kofile))
+        rpmfile = os.path.basename(p.get_built_rpm(expectedArch))
+        self.assertTrue(rpmfile in os.listdir(self.tmpdir))
+
+    def test_utils_exist(self):
+        """check that the dd utilities exist"""
+        self.assertTrue("dd_list" in os.listdir(UTILDIR))
+        self.assertTrue("dd_extract" in os.listdir(UTILDIR))
+
+class DD_List_TestCase(unittest.TestCase):
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp(prefix="dd_tests.")
+        self.k_ver = "4.1.4-333"
+        self.a_ver = "22.0"
+
+    def dd_list(self, dd_dir=None, kernel_ver=None, anaconda_ver=None):
+        return dd_list(dd_dir or self.tmpdir,
+                       kernel_ver or self.k_ver,
+                       anaconda_ver  or self.a_ver)
+
+    def tearDown(self):
+        shutil.rmtree(self.tmpdir)
+
+    def test_dd_list(self):
+        """dd_list: check output format"""
+        rpm = make_rpm(self.tmpdir, for_kernel_ver=self.k_ver)
+        drivers = self.dd_list()
+        self.assertEqual(len(drivers), 1)
+        d = drivers[0]
+        self.assertEqual(d.name, rpm.name)
+        self.assertEqual(d.description, rpm.basePackage.description)
+        self.assertTrue(d.description)
+        self.assertTrue(os.path.exists(d.source))
+        self.assertIn("modules", d.flags)
+        self.assertIn("firmwares", d.flags)
+        self.assertNotIn("binaries", d.flags)
+        self.assertNotIn("libraries", d.flags)
+
+    def test_dd_list_multiple(self):
+        """dd_list: multiple outputs for multiple packages"""
+        names = ['fun', 'even_more_fun', 'too_much_fun']
+        for name in names:
+            make_rpm(self.tmpdir, name=name, for_kernel_ver=self.k_ver)
+        drivers = self.dd_list()
+        self.assertEqual(len(drivers), len(names))
+        self.assertEqual(set(d.name for d in drivers), set(names))
+
+    def test_dd_list_binaries(self):
+        """dd_list: 'Provides:installer-enhancement' implies bins/libs"""
+        make_rpm(self.tmpdir, for_anaconda_ver=self.a_ver)
+        drivers = self.dd_list()
+        self.assertFalse(drivers == [])
+        d = drivers[0]
+        self.assertIn("binaries", d.flags)
+        self.assertIn("libraries", d.flags)
+        self.assertNotIn("modules", d.flags)
+        self.assertNotIn("firmwares", d.flags)
+
+    def test_dd_list_old_kmods(self):
+        """dd_list: ignore kmods if our kernel is too old"""
+        make_rpm(self.tmpdir, for_kernel_ver="5.0.1-555")
+        self.assertEqual(self.dd_list(), [])
+
+    def test_dd_list_z_stream_kmods(self):
+        """dd_list: accept kmods for z-stream kernels (#1207831)"""
+        make_rpm(self.tmpdir, for_kernel_ver=self.k_ver)
+        drivers = self.dd_list(kernel_ver=self.k_ver+".3")
+        self.assertNotEqual(drivers, [])
+        d = drivers[0]
+        self.assertIn("modules", d.flags)
+
+    def test_dd_list_anaconda_old(self):
+        """dd_list: ignore installer-enhancements if version doesn't match"""
+        make_rpm(self.tmpdir, for_anaconda_ver="23.0")
+        self.assertEqual(self.dd_list(), [])
+
+    def test_dd_list_no_rpms(self):
+        """dd_list: empty directory returns no results"""
+        self.assertEqual(self.dd_list(), [])
+
+    def test_dd_list_missing_dir(self):
+        """dd_list: missing directory returns no results"""
+        self.assertEqual(self.dd_list(dd_dir="/non/existent/path"), [])
+
+def listfiles(dirname):
+    return set(os.path.join(root,f)
+               for root, dirs, files in os.walk(dirname)
+               for f in files)
+
+class DD_Extract_TestCase(unittest.TestCase):
+    @classmethod
+    def setUpClass(self):
+        self.k_ver = "4.1.4-333"
+        self.a_ver = "22.0"
+        self.tmpdir = tempfile.mkdtemp(prefix="dd_tests.")
+        self.rpmpayload = (binfile, kofile, fwfile, libfile)
+        make_rpm(self.tmpdir, payload=self.rpmpayload)
+        (self.rpmfile,) = listfiles(self.tmpdir)
+
+    def setUp(self):
+        self.outdir = os.path.join(self.tmpdir, "outdir")
+        os.mkdir(self.outdir)
+
+    def dd_extract(self, flags='-bmlf'):
+        dd_extract(self.rpmfile, self.outdir, self.k_ver, flags=flags)
+        return listfiles(self.outdir)
+
+    def tearDown(self):
+        shutil.rmtree(self.outdir)
+
+    @classmethod
+    def tearDownClass(self):
+        shutil.rmtree(self.tmpdir)
+
+    def test_dd_extract(self):
+        """dd_extract: files are extracted correctly"""
+        self.dd_extract()
+        for f in self.rpmpayload:
+            self.assertEqual(f.contents, open(self.outdir+f.path).read())
+
+    def test_dd_extract_chmod(self):
+        """dd_extract: files get correct mode (#1222056)"""
+        self.dd_extract()
+        for f in self.rpmpayload:
+            if 'mode' in f.kwargs:
+                binmode = os.stat(self.outdir+f.path).st_mode
+                expectmode = int(f.kwargs['mode'],8)
+                self.assertEqual(binmode & expectmode, expectmode)
+
+    def test_dd_extract_modules(self):
+        """dd_extract: using --modules extracts only .ko files"""
+        outfiles = self.dd_extract(flags='--modules')
+        self.assertEqual(outfiles, set([self.outdir+kofile.path]))
+
+    def test_dd_extract_binaries(self):
+        """dd_extract: using --binaries extracts only /bin, /sbin, etc."""
+        outfiles = self.dd_extract(flags='--binaries')
+        self.assertEqual(outfiles, set([self.outdir+binfile.path]))
+
+    def test_dd_extract_libs(self):
+        """dd_extract: using --libraries extracts only /lib etc."""
+        outfiles = self.dd_extract(flags='--libraries')
+        self.assertEqual(outfiles, set([self.outdir+libfile.path]))
+
+    def test_dd_extract_firmware(self):
+        """dd_extract: using --firmwares extracts only /lib/firmware"""
+        outfiles = self.dd_extract(flags='--firmwares')
+        self.assertEqual(outfiles, set([self.outdir+fwfile.path]))


-- 
To view this commit on github, visit https://github.com/rhinstaller/anaconda/commit/e01037af0d911881bd86246a1ecdf42896651a53


More information about the anaconda-patches mailing list