bh@222: # Copyright (C) 2007, 2008, 2009 by Intevation GmbH bh@84: # Authors: bh@84: # Bernhard Herzog bh@84: # bh@84: # This program is free software under the GPL (>=v2) bh@84: # Read the file COPYING coming with the software for details. bh@84: bh@84: """Tests for treepkg.packager""" bh@84: bh@84: import sys bh@84: import os bh@84: import unittest bh@84: bh@84: from treepkg.run import call bh@84: from treepkg.cmdexpand import cmdexpand bh@84: from treepkg.util import writefile bh@128: from treepkg.packager import PackagerGroup, import_packager_module, \ bh@128: CyclicDependencyError bh@84: import treepkg.subversion as subversion bh@84: import treepkg bh@84: bh@84: from filesupport import FileTestMixin bh@84: bh@84: bh@84: def create_svn_repository(directory): bh@84: baseurl = "file://" + directory bh@84: call(cmdexpand("svnadmin create --fs-type fsfs $directory", bh@84: **locals())) bh@84: call(cmdexpand("svn mkdir -q -m 'create directory structure'" bh@84: " $baseurl/trunk", bh@84: **locals())) bh@84: return baseurl bh@84: bh@84: def add_svn_files(workingcopy, filedesc, commitmsg): bh@84: for name, contents in filedesc: bh@84: writefile(os.path.join(workingcopy, name), contents) bh@84: call(cmdexpand("svn add -q $name", **locals()), bh@84: cwd=workingcopy) bh@84: call(cmdexpand("svn commit -q -m $commitmsg", **locals()), bh@84: cwd=workingcopy) bh@84: bh@84: bh@84: class SourcePackager(treepkg.packager.SourcePackager): bh@84: bh@84: pkg_basename = "testpkg" bh@84: bh@84: def do_package(self): bh@84: pkgbaseversion, pkgbasedir = self.export_sources() bh@84: bh@84: pkgbasename = self.pkg_basename + "_" + pkgbaseversion bh@84: origtargz = os.path.join(self.work_dir, bh@84: pkgbasename + ".orig.tar.gz") bh@84: self.create_tarball(origtargz, self.work_dir, bh@84: os.path.basename(pkgbasedir)) bh@84: bh@84: changemsg = ("Update to SVN rev. %d" % (self.revision,)) bh@84: self.copy_debian_directory(pkgbasedir, pkgbaseversion, bh@84: changemsg) bh@84: bh@84: self.create_source_package(pkgbasedir, origtargz) bh@84: self.move_source_package(pkgbasename) bh@84: bh@84: bh@84: class RevisionPackager(treepkg.packager.RevisionPackager): bh@84: bh@84: source_packager_cls = SourcePackager bh@84: bh@84: bh@84: class PackageTrack(treepkg.packager.PackageTrack): bh@84: bh@84: revision_packager_cls = RevisionPackager bh@84: bh@84: bh@94: class PackagerTest(unittest.TestCase, FileTestMixin): bh@84: bh@94: revisions = [] bh@84: bh@84: debian_files = [ bh@84: ("debian", bh@84: [("control", """\ bh@84: Source: testpkg bh@84: Priority: optional bh@84: Maintainer: TreePKG bh@84: Standards-Version: 3.7.2 bh@84: bh@84: Package: testpkg bh@84: Architecture: all bh@116: Description: Test package for treepkg tests bh@116: German (de) internationalized (i18n) files for KDE bh@84: This package contains the German internationalized (i18n) files for bh@84: all KDE core applications. bh@84: """), bh@84: ("changelog", """\ bh@84: testpkg (0-0) unstable; urgency=low bh@84: bh@84: * Initial version bh@84: bh@84: -- TreePKG Thu, 8 Mar 2007 18:34:39 +0100 bh@84: """), bh@84: ("rules", "binary: echo binary")])] bh@84: bh@94: bh@84: def setUp(self): bh@185: self.svndir = self.create_temp_dir("svn") bh@185: self.svnworkdir = self.create_temp_dir("svnwork") bh@185: self.trackdir = self.create_files("track", self.debian_files) bh@94: self.svn_url = create_svn_repository(self.svndir) + "/trunk" bh@94: subversion.checkout(self.svn_url, self.svnworkdir) bh@95: for message, files in self.revisions: bh@95: add_svn_files(self.svnworkdir, files, message) bh@84: bh@98: def runtest(self, debrevision, group_args=None, **extra_track_args): bh@84: rootcmd = os.path.join(os.path.dirname(__file__), os.pardir, "test", bh@84: "mocksudopbuilder.py") bh@84: track = PackageTrack(name="testpkg", base_dir=self.trackdir, bh@94: svn_url=self.svn_url, pbuilderrc="", bh@84: root_cmd=[sys.executable, rootcmd], bh@84: deb_email="treepkg@example.com", bh@93: deb_fullname="treepkg tester", bh@93: **extra_track_args) bh@98: bh@98: if group_args is None: bh@98: group_args = {} bh@98: group = PackagerGroup([track], 1, **group_args) bh@84: group.check_package_tracks() bh@84: bh@95: # determine version that has been packaged. This assumes that bh@95: # check_package_tracks will leave the checkout in the revision bh@95: # that was actually packaged. bh@98: version = track.last_changed_revision() bh@95: bh@84: # Now check the source and binary package files bh@232: pkgdir = os.path.join(self.trackdir, "pkg", "%d-0" % version) bh@84: self.assertEquals(sorted(os.listdir(os.path.join(pkgdir, "src"))), bh@95: [name % locals() for name in bh@95: ["testpkg_%(version)d-%(debrevision)s.diff.gz", bh@95: "testpkg_%(version)d-%(debrevision)s.dsc", bh@95: "testpkg_%(version)d.orig.tar.gz"]]) bh@84: self.assertEquals(sorted(os.listdir(os.path.join(pkgdir, "binary"))), bh@95: [name % locals() for name in bh@95: ["testpkg_%(version)d-%(debrevision)s_all.deb", bh@95: "testpkg_%(version)d-%(debrevision)s_i386.changes"]]) bh@95: bh@95: bh@95: class TestPackager(PackagerTest): bh@95: bh@95: revisions = [ bh@95: ("Initial Revision", bh@95: [("README", "and miles to go before I sleep")]), bh@95: ] bh@93: bh@293: def test_default_pkg_revision_template(self): bh@93: self.runtest("treepkg1") bh@93: bh@293: def test_custom_pkg_revision_template(self): bh@293: self.runtest("kk1.2", pkg_revision_template="kk%(pkg_revision)d.2") bh@85: bh@98: bh@98: class TestPackagerWithMultipleRevisions(PackagerTest): bh@98: bh@98: revisions = [ bh@98: ("Initial Revision", bh@98: [("README", "and miles to go before I sleep")]), bh@98: ("Add some code", bh@98: [("program.c", "int main(void) { return 0; }")]), bh@98: ("Add some more code", bh@98: [("another.c", "int main(void) { return 1; }")]), bh@98: ] bh@98: bh@98: def test_packaging_specific_revision(self): bh@98: # Package the newest revision and then package an older one. bh@98: self.runtest("treepkg1") bh@98: self.runtest("treepkg1", group_args=dict(revision=3)) bh@98: bh@98: bh@91: class StoppingPackager(treepkg.packager.RevisionPackager): bh@91: bh@91: def package(self): bh@91: pass bh@91: bh@223: bh@91: class StoppingTrack(treepkg.packager.PackageTrack): bh@91: bh@91: def __init__(self, do_package, do_stop, instructions_file, name, trackdir): bh@91: super(StoppingTrack, self).__init__(name, trackdir, "", "", "", bh@91: "", "") bh@91: self.do_package = do_package bh@91: self.do_stop = do_stop bh@91: self.instructions_file = instructions_file bh@91: bh@190: def package_if_updated(self, revision, do_svn_update=True): bh@91: if self.do_stop: bh@91: writefile(self.instructions_file, "stop") bh@91: if self.do_package: bh@229: return StoppingPackager(self, 1, 0) bh@91: else: bh@91: return None bh@91: bh@91: bh@91: class TestPackageGroupStop(unittest.TestCase, FileTestMixin): bh@91: bh@91: def setUp(self): bh@185: self.trackdir = self.create_temp_dir("track") bh@91: self.instructions_file = os.path.join(self.trackdir, "instructions") bh@91: bh@91: def group(self, do_package=True, do_stop=True): bh@91: return PackagerGroup([StoppingTrack(do_package, do_stop, bh@91: self.instructions_file, bh@91: "test", self.trackdir)], bh@91: 1, instructions_file=self.instructions_file) bh@91: bh@91: def test_stop(self): bh@91: group = self.group(do_package=True, do_stop=True) bh@91: self.failUnless(group.check_package_tracks()) bh@91: bh@91: def test_no_stop(self): bh@91: group = self.group(do_package=True, do_stop=False) bh@91: self.failIf(group.check_package_tracks()) bh@91: bh@91: def test_instruction_removal(self): bh@91: # run once with stopping bh@91: group = self.group(do_package=True, do_stop=True) bh@91: self.failUnless(group.check_package_tracks()) bh@91: bh@91: # run again without stopping but using the same files. The bh@91: # instructions file should be removed automatically bh@91: group = self.group(do_package=True, do_stop=False) bh@91: self.failIf(group.check_package_tracks()) bh@91: bh@91: def test_stopping_without_packaging(self): bh@91: group = self.group(do_package=False, do_stop=True) bh@91: self.failUnless(group.check_package_tracks()) bh@91: bh@91: def test_stopping_between_checks(self): bh@91: group = self.group(do_package=False, do_stop=False) bh@91: # run check_package_tracks once bh@91: self.failIf(group.check_package_tracks()) bh@91: bh@91: # tell treepkg to stop bh@91: writefile(self.instructions_file, "stop") bh@91: bh@91: # check again. The check_package_tracks() may remove the bh@91: # instructions file but it must do so only the first time bh@91: self.failUnless(group.check_package_tracks()) bh@91: bh@85: bh@85: class TestPackageTrack(unittest.TestCase, FileTestMixin): bh@85: bh@85: def test_get_revision_numbers(self): bh@86: # Note: The revisions in the pkg dir are not ordered so that we bh@86: # can check whether get_revision_numbers returns a sorted list bh@86: # of revisions bh@185: trackdir = self.create_files("track", bh@185: [("pkg", bh@229: [("704195-0", bh@185: [("status", ""), bh@185: ("src", []), bh@185: ("binary", [])]), bh@229: ("702432-2", bh@185: [("status", ""), bh@185: ("src", []), bh@185: ("binary", [])])])]) bh@185: track = PackageTrack("testtrack", trackdir, "", "", "", "", "") bh@229: self.assertEquals(track.get_revision_numbers(), bh@229: [(702432, 2), (704195, 0)]) bh@87: bh@88: bh@88: class TestRevisionPackager(unittest.TestCase, FileTestMixin): bh@88: bh@88: def test_list_source_files(self): bh@185: trackdir = self.create_files("track", bh@185: [("pkg", bh@229: [("704195-31", bh@185: [("status", bh@185: ("TreePackagerStatus 0.0\n" bh@185: "status: binary_package_created\n" bh@185: "start: 2007-09-10 17:16:48\n" bh@185: "stop: 2007-09-11 00:07:36\n")), bh@185: ("src", [("test_1.0.orig.tar.gz", ""), bh@185: ("test_1.0-1.diff.gz", ""), bh@185: ("test_1.0-1.dsc", "")]), bh@185: ("binary", [])]), bh@185: ("702432-1", bh@185: [("status", ""), bh@185: ("src", []), bh@185: ("binary", [])])])]) bh@185: track = PackageTrack("testtrack", trackdir, "", "", "", "", "") bh@229: revpkg = RevisionPackager(track, 704195, 31) bh@229: srcdir = os.path.join(trackdir, "pkg", "704195-31", "src") bh@88: self.assertEquals(revpkg.list_source_files(), bh@88: [os.path.join(srcdir, filename) bh@88: for filename in ["test_1.0-1.diff.gz", bh@88: "test_1.0-1.dsc", bh@88: "test_1.0.orig.tar.gz"]]) bh@88: bh@88: def test_list_binary_files(self): bh@185: trackdir = self.create_files("track", bh@185: [("pkg", bh@185: [("704195-1", bh@185: [("status", bh@185: ("TreePackagerStatus 0.0\n" bh@185: "status: binary_package_created\n" bh@185: "start: 2007-09-10 17:16:48\n" bh@185: "stop: 2007-09-11 00:07:36\n")), bh@185: ("src", []), bh@185: ("binary", bh@185: [("test_1.0-1_i386.deb", ""), bh@185: ("test_1.0-1_i386.changes", "")])]), bh@185: ("702432-1", bh@185: [("status", ""), bh@185: ("src", []), bh@185: ("binary", [])])])]) bh@185: track = PackageTrack("testtrack", trackdir, "", "", "", "", "") bh@229: revpkg = RevisionPackager(track, 704195, 1) bh@185: bindir = os.path.join(trackdir, "pkg", "704195-1", "binary") bh@88: self.assertEquals(revpkg.list_binary_files(), bh@117: [os.path.join(bindir, filename) bh@88: for filename in ["test_1.0-1_i386.changes", bh@88: "test_1.0-1_i386.deb"]]) bh@113: bh@113: bh@113: class TestImportPackagerModule(unittest.TestCase, FileTestMixin): bh@113: bh@113: files = [("treepkg_importtest", bh@113: [("__init__.py", ""), bh@113: ("withtrack.py", "\n".join(["class PackageTrack:", bh@113: " pass", bh@113: ""])), bh@125: ("srconly.py", "\n".join(["class SourcePackager:", bh@125: " pass", bh@125: ""])), bh@125: ("srcandbin.py", "\n".join(["class SourcePackager:", bh@125: " pass", bh@125: "class BinaryPackager:", bh@125: " pass", bh@125: ""])), bh@125: ("revonly.py", "\n".join(["class RevisionPackager:", bh@113: " pass", bh@113: ""]))])] bh@113: bh@113: def setUp(self): bh@185: self.directory = self.create_files("a_module", self.files) bh@113: self.old_path = sys.path bh@113: sys.path = [self.directory] + sys.path bh@113: bh@113: def tearDown(self): bh@113: sys.path = self.old_path bh@113: bh@125: def check_class_modules(self, module, classmodules): bh@125: self.assertEquals(classmodules, bh@125: [(item[0], bh@125: sys.modules[getattr(module, item[0]).__module__]) bh@125: for item in classmodules]) bh@125: bh@113: def test_import_with_track(self): bh@113: module = import_packager_module("treepkg_importtest.withtrack") bh@125: self.check_class_modules(module, [("PackageTrack", module)]) bh@113: bh@125: def test_import_with_source_packager(self): bh@125: module = import_packager_module("treepkg_importtest.srconly") bh@125: self.check_class_modules(module, [("PackageTrack", treepkg.packager), bh@125: ("SourcePackager", module),]) bh@125: bh@125: def test_import_with_source_and_binary_packager(self): bh@125: module = import_packager_module("treepkg_importtest.srcandbin") bh@125: self.check_class_modules(module, [("PackageTrack", treepkg.packager), bh@125: ("RevisionPackager", bh@125: treepkg.packager), bh@125: ("SourcePackager", module), bh@125: ("BinaryPackager", module),]) bh@125: self.assertEquals(module.PackageTrack.revision_packager_cls, bh@125: module.RevisionPackager) bh@125: self.assertEquals(module.RevisionPackager.source_packager_cls, bh@125: module.SourcePackager) bh@125: self.assertEquals(module.RevisionPackager.binary_packager_cls, bh@125: module.BinaryPackager) bh@125: bh@125: def test_import_with_revision_packager(self): bh@125: module = import_packager_module("treepkg_importtest.revonly") bh@125: self.check_class_modules(module, [("PackageTrack", treepkg.packager), bh@125: ("RevisionPackager", module)]) bh@125: bh@125: self.assertEquals(module.PackageTrack.revision_packager_cls, bh@125: module.RevisionPackager) bh@128: bh@128: bh@128: class PackageTrackWithDependencies(treepkg.packager.PackageTrack): bh@128: bh@128: def __init__(self, name, handle_dependencies, requires, provides): bh@128: defaults = dict(base_dir="/home/builder/tracks/" + name, bh@128: svn_url="svn://example.com", bh@128: root_cmd=["false"], bh@128: pbuilderrc="/home/builder/pbuilderrc", bh@128: deb_email="treepkg@example.com", deb_fullname="treepkg", bh@128: handle_dependencies=handle_dependencies) bh@128: super(PackageTrackWithDependencies, bh@128: self).__init__(name, **defaults) bh@128: self.dependencies = (set(requires.split()), set(provides.split())) bh@128: bh@128: def determine_dependencies(self): bh@128: pass bh@128: bh@128: bh@128: class TestPackageDependencies(unittest.TestCase): bh@128: bh@128: def test_track_order(self): bh@128: P = PackageTrackWithDependencies bh@128: tracks = [P("library", True, "base-dev", "library library-dev"), bh@128: P("other", False, "cdbs base-dev", "other"), bh@128: P("base", True, "", "base base-dev"), bh@128: P("program", True, "library-dev libc", "program program-doc"), bh@128: ] bh@128: group = PackagerGroup(tracks, 3600) bh@128: sorted_tracks = group.get_package_tracks() bh@128: track_indices = dict([(track.name, index) for index, track in bh@128: enumerate(sorted_tracks)]) bh@128: def check_order(track1, track2): bh@128: self.failUnless(track_indices[track1] < track_indices[track2]) bh@128: bh@128: check_order("base", "library") bh@128: check_order("library", "program") bh@128: check_order("base", "program") bh@128: bh@128: # sanity check whether other is still there. It doesn't matter bh@128: # where bh@128: self.failUnless("other" in track_indices) bh@128: bh@128: def test_track_order_cycle(self): bh@128: P = PackageTrackWithDependencies bh@128: tracks = [P("library", True, "base-dev", "library library-dev"), bh@128: P("cycle", True, "program", "cycle"), bh@128: P("other", False, "cdbs base-dev", "other"), bh@128: P("base", True, "cycle", "base base-dev"), bh@128: P("program", True, "library-dev libc", "program program-doc"), bh@128: ] bh@128: try: bh@128: group = PackagerGroup(tracks, 3600) bh@128: sorted_tracks = group.get_package_tracks() bh@128: except CyclicDependencyError, exc: bh@128: pass bh@128: else: bh@128: self.fail("PackagerGroup did not detect cyclic dependencies")