-
Notifications
You must be signed in to change notification settings - Fork 346
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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!
- Loading branch information
Showing
1 changed file
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
@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])) |