[pacman-dev] [PATCH 3/3] Added tests for -Q --check (both fast(files) and full(mtree)).
Jeremy Heiner
scalaprotractor at gmail.com
Wed Oct 2 11:48:58 EDT 2013
Two new "hooks" were made available in pmtest: genhook is called after
everything is generated (just before the snapshot is taken), and
snaphook is called just after the snapshot. A hook is a list of
strings. Calling a hook is "exec"ing each string in the list.
Some helper functions were added to pmtest, notably pacmanrun and
addrule__pacman_warned. pacmanrun and rootjoin are used in a hook to
install a package and then intentionally mess it up, which then allows
the "-Qk" test output to be verified (with addrule__pacman_warned).
Signed-off-by: Jeremy Heiner <ScalaProtractor at gmail.com>
---
test/pacman/pmpkg.py | 47 ++++++++++++++++++++++++++++
test/pacman/pmtest.py | 63 +++++++++++++++++++++++++++-----------
test/pacman/tests/querycheck001.py | 18 +++++++++++
test/pacman/tests/querycheck002.py | 24 +++++++++++++++
test/pacman/tests/querycheck003.py | 24 +++++++++++++++
test/pacman/tests/querycheck004.py | 27 ++++++++++++++++
test/pacman/tests/querycheck005.py | 33 ++++++++++++++++++++
test/pacman/tests/querycheck006.py | 20 ++++++++++++
test/pacman/tests/querycheck007.py | 20 ++++++++++++
test/pacman/tests/querycheck008.py | 33 ++++++++++++++++++++
test/pacman/tests/querycheck009.py | 30 ++++++++++++++++++
test/pacman/tests/querycheck010.py | 27 ++++++++++++++++
test/pacman/util.py | 1 +
13 files changed, 349 insertions(+), 18 deletions(-)
create mode 100644 test/pacman/tests/querycheck001.py
create mode 100644 test/pacman/tests/querycheck002.py
create mode 100644 test/pacman/tests/querycheck003.py
create mode 100644 test/pacman/tests/querycheck004.py
create mode 100644 test/pacman/tests/querycheck005.py
create mode 100644 test/pacman/tests/querycheck006.py
create mode 100644 test/pacman/tests/querycheck007.py
create mode 100644 test/pacman/tests/querycheck008.py
create mode 100644 test/pacman/tests/querycheck009.py
create mode 100644 test/pacman/tests/querycheck010.py
diff --git a/test/pacman/pmpkg.py b/test/pacman/pmpkg.py
index 9c9e447..bb0facf 100644
--- a/test/pacman/pmpkg.py
+++ b/test/pacman/pmpkg.py
@@ -23,6 +23,8 @@
import shutil
from StringIO import StringIO
import tarfile
+import hashlib
+import zlib
import util
@@ -59,6 +61,7 @@ def __init__(self, name, version = "1.0-1"):
# files
self.files = []
self.backup = []
+ self.mtree = False
# install
self.install = {
"pre_install": "",
@@ -104,6 +107,33 @@ def parse_filename(name):
filename, extra = filename.split("|")
return filename
+ def mtreefile(self, info, data):
+ if self.mtree:
+ self.mtree.append(
+ "./%s uid=%d gid=%d mode=%o time=%d.%d"
+ " type=file size=%d md5digest=%s sha256digest=%s"
+ % (info.name, info.uid, info.gid, info.mode,
+ info.mtime >> 32, info.mtime & 0xFFFFFFFF,
+ info.size, hashlib.md5(data).hexdigest(),
+ hashlib.sha256(data).hexdigest()))
+
+ def mtreedir(self, info):
+ if self.mtree:
+ self.mtree.append(
+ "./%s uid=%d gid=%d mode=%o time=%d.%d"
+ " type=dir"
+ % (info.name, info.uid, info.gid, info.mode,
+ info.mtime >> 32, info.mtime & 0xFFFFFFFF))
+
+ def mtreelink(self, info):
+ if self.mtree:
+ self.mtree.append(
+ "./%s uid=%d gid=%d mode=%o time=%d.%d"
+ " type=link link=%s"
+ % (info.name, info.uid, info.gid, info.mode,
+ info.mtime >> 32, info.mtime & 0xFFFFFFFF,
+ info.linkname))
+
def makepkg(self, path):
"""Creates an Arch Linux package archive.
@@ -148,11 +178,14 @@ def makepkg(self, path):
util.mkdir(os.path.dirname(self.path))
# Generate package metadata
+ if self.mtree:
+ self.mtree = ["#mtree"]
tar = tarfile.open(self.path, "w:gz")
for name, data in archive_files:
info = tarfile.TarInfo(name)
info.size = len(data)
tar.addfile(info, StringIO(data))
+ self.mtreefile(info, data)
# Generate package file system
for name in self.files:
@@ -162,18 +195,32 @@ def makepkg(self, path):
info.mode = fileinfo["perms"]
elif fileinfo["isdir"]:
info.mode = 0755
+ elif fileinfo["islink"]:
+ info.mode = 0777
if fileinfo["isdir"]:
info.type = tarfile.DIRTYPE
tar.addfile(info)
+ self.mtreedir(info)
elif fileinfo["islink"]:
info.type = tarfile.SYMTYPE
info.linkname = fileinfo["link"]
tar.addfile(info)
+ self.mtreelink(info)
else:
# TODO wow what a hack, adding a newline to match mkfile?
filedata = name + "\n"
info.size = len(filedata)
tar.addfile(info, StringIO(filedata))
+ self.mtreefile(info, filedata)
+
+ # .MTREE
+ if self.mtree:
+ filedata = "\n".join(self.mtree)+"\n" # zlib.compress(filedata)?
+ # but that causes "Unrecognized archive format" error, and this
+ # seems to work anyway (libalpm is happy with uncompressed file)
+ info = tarfile.TarInfo(".MTREE")
+ info.size = len(filedata)
+ tar.addfile(info, StringIO(filedata))
tar.close()
diff --git a/test/pacman/pmtest.py b/test/pacman/pmtest.py
index a0a1455..0afb222 100644
--- a/test/pacman/pmtest.py
+++ b/test/pacman/pmtest.py
@@ -18,6 +18,7 @@
import os
+import re
import shlex
import shutil
import stat
@@ -99,6 +100,9 @@ def load(self):
self.localpkgs = []
self.createlocalpkgs = False
self.filesystem = []
+ self.rundir = self.rootjoin(util.TMPDIR)
+ self.genhook = []
+ self.snaphook = []
self.description = ""
self.option = {}
@@ -198,12 +202,50 @@ def generate(self):
# Done.
vprint(" Taking a snapshot of the file system")
+ for cmd in self.genhook:
+ vprint("\texec "+cmd)
+ exec cmd
for roots, dirs, files in os.walk(root):
for i in files:
filename = os.path.join(roots, i)
f = pmfile.PacmanFile(root, self.rootremove(filename))
self.files.append(f)
vprint("\t%s" % f.name)
+ for cmd in self.snaphook:
+ vprint("\texec "+cmd)
+ exec cmd
+
+ def pacmanbin(self):
+ return([self.env.pacman["bin"],
+ "--config", self.rootjoin(util.PACCONF),
+ "--root", self.env.root,
+ "--dbpath", self.rootjoin(util.PM_DBPATH),
+ "--cachedir", self.rootjoin(util.PM_CACHEDIR)])
+
+ def pacmansub(self, cmd, output):
+ vprint("\trunning: %s" % " ".join(cmd))
+ time_start = time.time()
+ retcode = subprocess.call(cmd, stdout=output, stderr=output,
+ cwd=self.rundir, env={'LC_ALL': 'C'})
+ time_end = time.time()
+ vprint("\ttime elapsed: %.2fs" % (time_end - time_start))
+ vprint("\tretcode = %s" % retcode)
+ return retcode
+
+ def pacmanrun(self, args):
+ cmd = self.env.cmdroot()
+ cmd.extend(self.pacmanbin())
+ cmd.append("--noconfirm")
+ cmd.extend(shlex.split(args))
+ output = open(self.rootjoin(util.GENFILE), 'a')
+ self.pacmansub(cmd, output)
+ output.close()
+
+ def addrule__pacman_warned(self, pkg, path, msg):
+ if not path.startswith(self.env.root):
+ path = self.rootjoin(path)
+ match = re.escape("warning: %s: %s (%s)" % (pkg.name, path, msg))
+ self.addrule("PACMAN_OUTPUT=^"+match+"$")
def run(self):
if os.path.isfile(util.PM_LOCK):
@@ -226,11 +268,7 @@ def run(self):
"--tool=memcheck", "--leak-check=full",
"--show-reachable=yes",
"--suppressions=%s" % suppfile])
- cmd.extend([pacman["bin"],
- "--config", self.rootjoin(util.PACCONF),
- "--root", root,
- "--dbpath", self.rootjoin(util.PM_DBPATH),
- "--cachedir", self.rootjoin(util.PM_CACHEDIR)])
+ cmd.extend(self.pacmanbin())
if not pacman["manual-confirm"]:
cmd.append("--noconfirm")
if pacman["debug"]:
@@ -240,28 +278,17 @@ def run(self):
output = open(self.rootjoin(util.LOGFILE), 'w')
else:
output = None
- vprint("\trunning: %s" % " ".join(cmd))
-
- # Change to the tmp dir before running pacman, so that local package
- # archives are made available more easily.
- tmpdir = self.rootjoin(util.TMPDIR)
- time_start = time.time()
- self.retcode = subprocess.call(cmd, stdout=output, stderr=output,
- cwd=tmpdir, env={'LC_ALL': 'C'})
- time_end = time.time()
- vprint("\ttime elapsed: %.2fs" % (time_end - time_start))
+ self.retcode = self.pacmansub(cmd, output)
if output:
output.close()
- vprint("\tretcode = %s" % self.retcode)
-
# Check if the lock is still there
if os.path.isfile(util.PM_LOCK):
tap.diag("\tERROR: %s not removed" % util.PM_LOCK)
os.unlink(util.PM_LOCK)
# Look for a core file
- if os.path.isfile(os.path.join(tmpdir, "core")):
+ if os.path.isfile(os.path.join(self.rundir, "core")):
tap.diag("\tERROR: pacman dumped a core file")
def check(self):
diff --git a/test/pacman/tests/querycheck001.py b/test/pacman/tests/querycheck001.py
new file mode 100644
index 0000000..8587b50
--- /dev/null
+++ b/test/pacman/tests/querycheck001.py
@@ -0,0 +1,18 @@
+self.description = "Query--check files, all there"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+
+self.addpkg(pkg)
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename()])
+
+self.args = "-Qk"
+
+self.addrule("PACMAN_RETCODE=0")
diff --git a/test/pacman/tests/querycheck002.py b/test/pacman/tests/querycheck002.py
new file mode 100644
index 0000000..c385893
--- /dev/null
+++ b/test/pacman/tests/querycheck002.py
@@ -0,0 +1,24 @@
+self.description = "Query--check files, missing a file"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+
+self.addpkg(pkg)
+
+zap = pkg.files[1]
+
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename(),
+ "os.unlink(self.rootjoin('%s'))" % zap])
+
+self.args = "-Qk"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule__pacman_warned(pkg, zap, "No such file or directory")
+self.addrule("PACMAN_OUTPUT= 1 missing file$")
diff --git a/test/pacman/tests/querycheck003.py b/test/pacman/tests/querycheck003.py
new file mode 100644
index 0000000..07e1bc9
--- /dev/null
+++ b/test/pacman/tests/querycheck003.py
@@ -0,0 +1,24 @@
+self.description = "Query--check files, missing a link"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+
+self.addpkg(pkg)
+
+zap = pkg.files[2].split(' -> ')[0]
+
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename(),
+ "os.unlink(self.rootjoin('%s'))" % zap])
+
+self.args = "-Qk"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule__pacman_warned(pkg, zap, "No such file or directory")
+self.addrule("PACMAN_OUTPUT= 1 missing file$")
diff --git a/test/pacman/tests/querycheck004.py b/test/pacman/tests/querycheck004.py
new file mode 100644
index 0000000..dcf8173
--- /dev/null
+++ b/test/pacman/tests/querycheck004.py
@@ -0,0 +1,27 @@
+self.description = "Query--check files, missing a dir"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+
+self.addpkg(pkg)
+
+zap = pkg.files[3]
+
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename(),
+ "shutil.rmtree(self.rootjoin('%s'))" % zap])
+
+self.args = "-Qk"
+
+missing = "No such file or directory"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule__pacman_warned(pkg, zap, missing)
+self.addrule__pacman_warned(pkg, pkg.files[4], missing)
+self.addrule("PACMAN_OUTPUT= 2 missing files$")
diff --git a/test/pacman/tests/querycheck005.py b/test/pacman/tests/querycheck005.py
new file mode 100644
index 0000000..e673cc6
--- /dev/null
+++ b/test/pacman/tests/querycheck005.py
@@ -0,0 +1,33 @@
+self.description = "Query--check files, missing several"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+
+self.addpkg(pkg)
+
+zap1 = pkg.files[1]
+zap2 = pkg.files[2].split(' -> ')[0]
+zap3 = pkg.files[3]
+
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename(),
+ "os.unlink(self.rootjoin('%s'))" % zap1,
+ "os.unlink(self.rootjoin('%s'))" % zap2,
+ "shutil.rmtree(self.rootjoin('%s'))" % zap3])
+
+self.args = "-Qk"
+
+missing = "No such file or directory"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule__pacman_warned(pkg, zap1, missing)
+self.addrule__pacman_warned(pkg, zap2, missing)
+self.addrule__pacman_warned(pkg, zap3, missing)
+self.addrule__pacman_warned(pkg, pkg.files[4], missing)
+self.addrule("PACMAN_OUTPUT= 4 missing files$")
diff --git a/test/pacman/tests/querycheck006.py b/test/pacman/tests/querycheck006.py
new file mode 100644
index 0000000..cf178f4
--- /dev/null
+++ b/test/pacman/tests/querycheck006.py
@@ -0,0 +1,20 @@
+self.description = "Query--check mtree, no mtree"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+pkg.mtree = False
+
+self.addpkg(pkg)
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename()])
+
+self.args = "-Qkk"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PACMAN_OUTPUT=dummy: no mtree file")
diff --git a/test/pacman/tests/querycheck007.py b/test/pacman/tests/querycheck007.py
new file mode 100644
index 0000000..d43d846
--- /dev/null
+++ b/test/pacman/tests/querycheck007.py
@@ -0,0 +1,20 @@
+self.description = "Query--check mtree, all there"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+pkg.mtree = True
+
+self.addpkg(pkg)
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename()])
+
+self.args = "-Qkk"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("!PACMAN_OUTPUT=dummy: no mtree file")
diff --git a/test/pacman/tests/querycheck008.py b/test/pacman/tests/querycheck008.py
new file mode 100644
index 0000000..ddf9260
--- /dev/null
+++ b/test/pacman/tests/querycheck008.py
@@ -0,0 +1,33 @@
+self.description = "Query--check mtree, missing several"
+
+pkg = pmpkg("dummy")
+pkg.files = [
+ "etc/dummy.conf",
+ "lib/libdummy.so.0",
+ "lib/libdummy.so -> ./libdummy.so.0",
+ "lib/dummy/",
+ "lib/dummy/stuff",
+ "bin/dummy"]
+pkg.mtree = True
+
+zap1 = pkg.files[1]
+zap2 = pkg.files[2].split(' -> ')[0]
+zap3 = pkg.files[3]
+
+self.addpkg(pkg)
+self.genhook.extend([
+ "self.pacmanrun('-U %s')" % pkg.filename(),
+ "os.unlink(self.rootjoin('%s'))" % zap1,
+ "os.unlink(self.rootjoin('%s'))" % zap2,
+ "shutil.rmtree(self.rootjoin('%s'))" % zap3])
+
+self.args = "-Qkk"
+
+missing = "No such file or directory"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule__pacman_warned(pkg, zap1, missing)
+self.addrule__pacman_warned(pkg, zap2, missing)
+self.addrule__pacman_warned(pkg, zap3, missing)
+self.addrule__pacman_warned(pkg, pkg.files[4], missing)
+self.addrule("PACMAN_OUTPUT= 4 altered files$")
diff --git a/test/pacman/tests/querycheck009.py b/test/pacman/tests/querycheck009.py
new file mode 100644
index 0000000..6caf733
--- /dev/null
+++ b/test/pacman/tests/querycheck009.py
@@ -0,0 +1,30 @@
+self.description = "Query--check mtree, bad types"
+
+pkg = pmpkg("dummy")
+pkg.mtree = True
+pkg.files = ["dummy/z"]
+for file, mangle in [
+ ("dummy/f1", ["os.unlink('%s')", "os.mkdir('%s')"]),
+ ("dummy/f2", ["os.unlink('%s')", "os.symlink('z','%s')"]),
+ ("dummy/l1 -> z", ["os.unlink('%s')", "os.mkdir('%s')"]),
+ ("dummy/l2 -> z", ["os.unlink('%s')", "util.mkfile('%s')"]),
+ ("dummy/d1/", ["os.rmdir('%s')", "util.mkfile('%s')"]),
+ ("dummy/d2/", ["os.rmdir('%s')", "os.symlink('z','%s')"])]:
+ pkg.files.append(file)
+ parsed = pkg.parse_filename(file)
+ noslash = parsed.rstrip('/')
+ err = "File type mismatch"
+ if noslash != parsed:
+ err = "Not a directory"
+ rooted = self.rootjoin(noslash)
+ for cmd in mangle:
+ self.genhook.append(cmd % rooted)
+ self.addrule__pacman_warned(pkg, parsed, err)
+
+self.addpkg(pkg)
+self.genhook.insert(0, "self.pacmanrun('-U %s')" % pkg.filename())
+
+self.args = "-Qkk"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule("PACMAN_OUTPUT= 6 altered files$")
diff --git a/test/pacman/tests/querycheck010.py b/test/pacman/tests/querycheck010.py
new file mode 100644
index 0000000..caba37b
--- /dev/null
+++ b/test/pacman/tests/querycheck010.py
@@ -0,0 +1,27 @@
+self.description = "Query--check mtree, bad perms+time+size+link"
+
+pkg = pmpkg("dummy")
+pkg.mtree = True
+pkg.files = ["dummy/"]
+for file, err, mangle in [
+ #("dummy/uid", "UID mismatch", ["os.chown('%s',?,-1)"]),#needs root
+ #("dummy/gid", "GID mismatch", ["os.chown('%s',-1,?)"]),#needs root
+ ("dummy/mode", "Permissions mismatch", ["os.chmod('%s',0400)"]),
+ ("dummy/mtime", "Modification time mismatch", ["os.utime('%s',None)"]),
+ ("dummy/size", "Size mismatch", ["util.mkfile('%s')"]),
+ ("dummy/link -> size", "Symlink path mismatch", [
+ "os.unlink('%s')", "os.symlink('z','%s')"])]:
+ pkg.files.append(file)
+ parsed = pkg.parse_filename(file)
+ rooted = self.rootjoin(parsed)
+ for cmd in mangle:
+ self.genhook.append(cmd % rooted)
+ self.addrule__pacman_warned(pkg, parsed, err)
+
+self.addpkg(pkg)
+self.genhook.insert(0, "self.pacmanrun('-U %s')" % pkg.filename())
+
+self.args = "-Qkk"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule("PACMAN_OUTPUT= 4 altered files$")
diff --git a/test/pacman/util.py b/test/pacman/util.py
index 5c9a0c0..d2df8dc 100644
--- a/test/pacman/util.py
+++ b/test/pacman/util.py
@@ -40,6 +40,7 @@
TMPDIR = "tmp"
SYNCREPO = "var/pub"
LOGFILE = "var/log/pactest.log"
+GENFILE = "var/log/testgen.log"
verbose = 0
--
1.8.4
More information about the pacman-dev
mailing list