[pacman-dev] [PATCH 4/5] Add mtree code to test framework and basic unit tests for -Qkk.

Jeremy Heiner scalaprotractor at gmail.com
Mon Nov 11 06:47:46 EST 2013


The framework will now generate mtree data when the pmpkg.makemtree is
set to True, but only for "local" packages. Since the mtree data is
only used by -Qkk, and this change is sufficient to test that
function, there seems to be no reason to generate mtree data for other
packages. If that becomes a requirement in the future there are
comments in the code that sketch out an implemention for that.

The two new unit tests are similar to the previous -Qkk tests (005 is
like 002, and 006 is like 004), but with mtree data. So the filesystem
is actually validated against the mtree (instead of merely checking for
the warning about a lacking mtree).

Signed-off-by: Jeremy Heiner <ScalaProtractor at gmail.com>
---
 test/pacman/pmdb.py                |  3 ++
 test/pacman/pmpkg.py               | 18 ++++++++++++
 test/pacman/tests/TESTS            |  2 ++
 test/pacman/tests/querycheck005.py | 16 +++++++++++
 test/pacman/tests/querycheck006.py | 20 +++++++++++++
 test/pacman/util.py                | 57 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 116 insertions(+)
 create mode 100644 test/pacman/tests/querycheck005.py
 create mode 100644 test/pacman/tests/querycheck006.py

diff --git a/test/pacman/pmdb.py b/test/pacman/pmdb.py
index 53de91e..088e284 100644
--- a/test/pacman/pmdb.py
+++ b/test/pacman/pmdb.py
@@ -224,6 +224,9 @@ def db_write(self, pkg):
             make_section(data, "BACKUP", pkg.local_backup_entries())
             entry["files"] = "\n".join(data)
 
+            if pkg.mtreedata:
+                entry["mtree"] = pkg.mtreedata
+
             if any(pkg.install.values()):
                 entry["install"] = pkg.installfile()
 
diff --git a/test/pacman/pmpkg.py b/test/pacman/pmpkg.py
index db97449..25e841a 100644
--- a/test/pacman/pmpkg.py
+++ b/test/pacman/pmpkg.py
@@ -60,6 +60,8 @@ def __init__(self, name, version = "1.0-1"):
         # files
         self.files = []
         self.backup = []
+        self.makemtree = False # True => finalize generates mtreedata
+        self.mtreedata = "" # you can set this, but makemtree is easier
         # install
         self.install = {
             "pre_install": "",
@@ -145,6 +147,19 @@ def makepkg(self, path):
         if any(self.install.values()):
             archive_files.append((".INSTALL", self.installfile()))
 
+        # .MTREE
+        if self.mtreedata:
+            raise NotImplementedError("attempt to put mtree into tar")
+            # TODO: they work great in local dbs, but not in tar'd pkgs.
+            # it seems unlikely that any test will ever need to, but:
+            # easiest solution seems to be to hack the 'Generate package
+            # file system' loop just below to copy the attributes from
+            # the mtreedata over to the TarInfo fields. pulling the data
+            # out with re.search shouldn't be too hard. put that code
+            # over in util so it gets updated with the other mtree code.
+            # then remove the raise and uncomment the following line:
+            # archive_files.append((".MTREE", self.mtreedata))
+
         self.path = os.path.join(path, self.filename())
         util.mkdir(os.path.dirname(self.path))
 
@@ -226,6 +241,9 @@ def finalize(self):
                 name = os.path.dirname(name)
         self.files.sort()
 
+        if self.makemtree:
+            self.mtreedata = util.mtree(self.files)
+
         self.finalized = True
 
     def local_backup_entries(self):
diff --git a/test/pacman/tests/TESTS b/test/pacman/tests/TESTS
index f4e6caf..c460fe0 100644
--- a/test/pacman/tests/TESTS
+++ b/test/pacman/tests/TESTS
@@ -92,6 +92,8 @@ TESTS += test/pacman/tests/querycheck001.py
 TESTS += test/pacman/tests/querycheck002.py
 TESTS += test/pacman/tests/querycheck003.py
 TESTS += test/pacman/tests/querycheck004.py
+TESTS += test/pacman/tests/querycheck005.py
+TESTS += test/pacman/tests/querycheck006.py
 TESTS += test/pacman/tests/reason001.py
 TESTS += test/pacman/tests/remove001.py
 TESTS += test/pacman/tests/remove002.py
diff --git a/test/pacman/tests/querycheck005.py b/test/pacman/tests/querycheck005.py
new file mode 100644
index 0000000..95c776d
--- /dev/null
+++ b/test/pacman/tests/querycheck005.py
@@ -0,0 +1,16 @@
+self.description = "Query--check mtree, all there"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+    "usr/lib/libdummy.so.0",
+    "usr/lib/libdummy.so -> libdummy.so.0",
+    "usr/share/dummy/C/",
+    "usr/share/dummy/C/msgs",
+    "usr/share/dummy/en -> C"]
+pkg.makemtree = True
+self.addpkg2db("local",pkg)
+
+self.args = "-Qkk"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("!PACMAN_OUTPUT=dummy: no mtree file")
diff --git a/test/pacman/tests/querycheck006.py b/test/pacman/tests/querycheck006.py
new file mode 100644
index 0000000..879fd00
--- /dev/null
+++ b/test/pacman/tests/querycheck006.py
@@ -0,0 +1,20 @@
+self.description = "Query--check mtree, missing"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+    "usr/lib/libdummy.so.0",
+    "usr/lib/libdummy.so -> libdummy.so.0",
+    "usr/share/dummy/C/",
+    "usr/share/dummy/C/msgs",
+    "usr/share/dummy/en -> C"]
+pkg.makemtree = True
+pkg.install['post_install'] = "rm -r ../usr/share/dummy/*"
+self.addpkg2db("local",pkg)
+
+self.args = "-Qkk"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule("PACMAN_OUTPUT=/usr/share/dummy/C .No such file")
+self.addrule("PACMAN_OUTPUT=/usr/share/dummy/C/msgs .No such file")
+self.addrule("PACMAN_OUTPUT=/usr/share/dummy/en .No such file")
+self.addrule("PACMAN_OUTPUT=, 3 altered files")
diff --git a/test/pacman/util.py b/test/pacman/util.py
index beb7e3d..2158b80 100644
--- a/test/pacman/util.py
+++ b/test/pacman/util.py
@@ -20,6 +20,8 @@
 import os
 import re
 import hashlib
+import subprocess
+import sys
 
 import tap
 
@@ -93,6 +95,11 @@ def mkfile(base, name, data="", utime=False):
 
     if info["islink"]:
         os.symlink(info["link"], path)
+        if utime:
+            if sys.hexversion < 0x03030000:
+                subprocess.call(["touch","-ht","196912311905.55",path])
+            else:
+                os.utime(path, (355,355), follow_symlinks=False)
     else:
         writedata(path, data)
         if utime:
@@ -158,6 +165,56 @@ def mkmd5sum(data):
 
 
 #
+# mtree
+# obviously not a full implementation of the spec (e.g. no
+# quoting of paths), but just enough for a few tests.
+# freebsd mtree(5) has a bit more detail than arch or openbsd.
+# scripts/makepkg calls bsdtar to build mtrees at line 1890.
+#
+
+def mtree(files):
+
+    lines = ["#mtree"] # no version (ala bsdtar)
+    for name in files:
+        info = getfileinfo(name)
+        filename = info["filename"]
+
+        if info["isdir"]:
+            filename = filename.rstrip("/")
+            mode = info["perms"] if info["hasperms"] else 0o755
+            attrs = ("type=dir mode=%o"
+                     % (mode))
+
+        elif info["islink"]:
+            mode = info["perms"] if info["hasperms"] else 0o777
+            attrs = ("type=link time=355.000000000"
+                     " mode=%o link=%s"
+                     % (mode, info["link"]))
+
+        else:
+            mode = info["perms"] if info["hasperms"] else 0o644
+            contents = name + "\n"
+            md5 = hashlib.md5(contents).hexdigest()
+            sha256 = hashlib.sha256(contents).hexdigest()
+            attrs = ("type=file time=355.000000000"
+                     " mode=%o size=%d md5digest=%s sha256digest=%s"
+                     % (mode, len(contents), md5, sha256))
+
+        lines.append("./%s uid=0 gid=0 %s" % (filename, attrs))
+                       
+    mtree = "\n".join(lines)+"\n"
+
+    # scripts/makepkg compresses the mtree (via bsdtar using gzip).
+    # python's gzip always opens a file (can't make it use StringIO).
+    # gzip uses zlib, but if we zlib.compress(mtree) it causes libalpm
+    # to reject the mtree with "Unrecognized archive format".
+    # fortunately libalpm reads the uncompressed mtree files just fine,
+    # so we don't have to jump through any hoops to get it compressed.
+
+    return mtree
+
+
+#
 # Miscellaneous
 #
 
-- 
1.8.4.2



More information about the pacman-dev mailing list