src/tests/cli/t_pkg_install.py
author Shawn Walker <srw@sun.com>
Wed, 02 Dec 2009 22:07:06 -0600
changeset 1538 78ac66abc186
parent 1505 cc598d70bbbe
child 1552 ae0653294c32
permissions -rw-r--r--
12130 install/update operations should always refresh publisher metadata (when allowed) 4419 misleading error message when pkg not found because refresh failed 10976 operations should report when refresh failed if appropriate

#!/usr/bin/python
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#

#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

import testutils
if __name__ == "__main__":
        testutils.setup_environment("../../../proto")

import os
import pkg.catalog as catalog
import pkg.fmri as fmri
import pkg.portable as portable
import re
import shutil
import time
import unittest
import urllib
from stat import *

class TestPkgInstallBasics(testutils.SingleDepotTestCase):
        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        foo10 = """
            open [email protected],5.11-0
            close """

        foo11 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/lib
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.so.1 timestamp="20080731T024051Z"
            add signature pkg.sig_bit1=sig_bit_val1 pkg.sig_bit2=sig_bit_val2
            close """
        foo11_timestamp = 1217472051

        foo12 = """
            open [email protected],5.11-0
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.so.1
            close """

        afoo10 = """
            open a/[email protected],5.11-0
            close """

        boring10 = """
            open [email protected],5.11-0
            close """

        boring11 = """
            open [email protected],5.11-0
            close """

        bar10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        bar11 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        xfoo10 = """
            open [email protected],5.11-0
            close """

        xbar10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        xbar11 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """


        bar12 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        baz10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/baz mode=0555 owner=root group=bin path=/bin/baz
            close """

        deep10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        xdeep10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        ydeep10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            add dir mode=0755 owner=root group=bin path=/bin
            add file /tmp/cat mode=0555 owner=root group=bin path=/bin/cat
            close """

        a6018_1 = """
            open [email protected],5.11-0
            close """
        a6018_2 = """
            open [email protected],5.11-0
            close """
        b6018_1 = """
            open [email protected],5.11-0
            add depend type=optional fmri=a6018@1
            close """

        misc_files = [ "/tmp/libc.so.1", "/tmp/cat", "/tmp/baz" ]

        def setUp(self):
                testutils.SingleDepotTestCase.setUp(self)
                for p in self.misc_files:
                        f = open(p, "w")
                        # write the name of the file into the file, so that
                        # all files have differing contents
                        f.write(p)
                        f.close
                        self.debug("wrote %s" % p)

        def tearDown(self):
                testutils.SingleDepotTestCase.tearDown(self)
                for p in self.misc_files:
                        os.remove(p)

        def test_cli(self):
                """Test bad cli options"""

                durl = self.dc.get_depot_url()
                self.image_create(durl)

                self.pkg("-@", exit=2)
                self.pkg("-s status", exit=2)
                self.pkg("-R status", exit=2)

                self.pkg("install -@ foo", exit=2)
                self.pkg("install -vq foo", exit=2)
                self.pkg("install", exit=2)
                self.pkg("install [email protected]", exit=1)
                self.pkg("install pkg:/[email protected]", exit=1)

        def test_basics_1(self):
                """ Send empty package [email protected], install and uninstall """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.image_create(durl)

                self.pkg("list -a")
                self.pkg("list", exit=1)

                self.pkg("install foo")

                self.pkg("list")
                self.pkg("verify")

                self.pkg("uninstall foo")
                self.pkg("verify")


        def test_basics_2(self):
                """ Send package [email protected], containing a directory and a file,
                    install, search, and uninstall. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.pkg("list -a")
                self.pkg("install foo")
                self.pkg("verify")
                self.pkg("list")

                self.pkg("search -l /lib/libc.so.1")
                self.pkg("search -r /lib/libc.so.1")
                self.pkg("search -l blah", exit=1)
                self.pkg("search -r blah", exit=1)

                # check to make sure timestamp was set to correct value

                libc_path = os.path.join(self.get_img_path(), "lib/libc.so.1")
                stat = os.stat(libc_path)

                assert (stat[ST_MTIME] == self.foo11_timestamp)

                # check that verify finds changes
                now = time.time()
                os.utime(libc_path, (now, now))
                self.pkg("verify", exit=1)

                self.pkg("uninstall foo")
                self.pkg("verify")
                self.pkg("list -a")
                self.pkg("verify")


        def test_basics_3(self):
                """ Install [email protected], upgrade to [email protected], uninstall. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.pkg("install [email protected]")
                self.pkg("list [email protected]")
                self.pkg("list [email protected]", exit=1)

                self.pkg("install [email protected]")
                self.pkg("list [email protected]")
                self.pkg("list [email protected]", exit=1)
                self.pkg("list foo@1")
                self.pkg("verify")

                self.pkg("uninstall foo")
                self.pkg("list -a")
                self.pkg("verify")

        def test_basics_4(self):
                """ Add [email protected], dependent on [email protected], install, uninstall. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.foo11)
                self.pkgsend_bulk(durl, self.bar10)
                self.image_create(durl)

                self.pkg("list -a")
                self.pkg("install [email protected]")
                self.pkg("list")
                self.pkg("verify")
                self.pkg("uninstall -v bar foo")

                # foo and bar should not be installed at this point
                self.pkg("list bar", exit=1)
                self.pkg("list foo", exit=1)
                self.pkg("verify")

        def test_basics_5(self):
                """ Add [email protected], install [email protected]. """
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.xbar11)
                self.image_create(durl)
                self.pkg("install [email protected]", exit=1)

        def test_basics_6(self):
                """ Install [email protected], upgrade to [email protected].
                Boring should be left alone, while
                foo gets upgraded as needed"""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.bar10)
                self.pkgsend_bulk(durl, self.bar11)
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.foo11)
                self.pkgsend_bulk(durl, self.foo12)
                self.pkgsend_bulk(durl, self.boring10)
                self.pkgsend_bulk(durl, self.boring11)

                self.image_create(durl)

                self.pkg("install [email protected] [email protected] [email protected]")
                self.pkg("list")
                self.pkg("list [email protected] [email protected] [email protected]")
                self.pkg("install -v [email protected]") # upgrade bar
                self.pkg("list")
                self.pkg("list [email protected] [email protected] [email protected]")

        def test_image_upgrade(self):
                """ Send package [email protected], dependent on [email protected].  Install [email protected].
                    List all packages.  Upgrade image. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.foo11)
                self.pkgsend_bulk(durl, self.bar10)
                self.image_create(durl)

                self.pkg("install [email protected]")

                self.pkgsend_bulk(durl, self.foo12)
                self.pkgsend_bulk(durl, self.bar11)
                self.pkg("refresh")

                self.pkg("contents -H")
                self.pkg("list")
                self.pkg("refresh")

                self.pkg("list")
                self.pkg("verify")
                self.pkg("image-update -v")
                self.pkg("verify")

                self.pkg("list [email protected]")
                self.pkg("list [email protected]")

                self.pkg("uninstall bar foo")
                self.pkg("verify")

        def test_recursive_uninstall(self):
                """Install [email protected], dependent on [email protected], uninstall foo recursively."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.foo11)
                self.pkgsend_bulk(durl, self.bar10)
                self.image_create(durl)

                self.pkg("install [email protected]")

                # Here's the real part of the regression test;
                # at this point foo and bar are installed, and
                # bar depends on foo.  foo and bar should both
                # be removed by this action.
                self.pkg("uninstall -vr foo")
                self.pkg("list bar", exit=1)
                self.pkg("list foo", exit=1)

        def test_nonrecursive_dependent_uninstall(self):
                """Trying to remove a package that's a dependency of another
                package should fail if the uninstall isn't recursive."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.bar10)
                self.image_create(durl)

                self.pkg("install [email protected]")

                self.pkg("uninstall -v foo", exit=1)
                self.pkg("list bar")
                self.pkg("list foo")

        
        def test_bug_1338(self):
                """ Add [email protected], dependent on [email protected], install [email protected]. """

                durl = self.dc.get_depot_url()
                self.pkg("list -a")
                self.pkgsend_bulk(durl, self.bar11)
                self.image_create(durl)

                self.pkg("install [email protected]", exit=1)

        def test_bug_1338_2(self):
                """ Add [email protected], dependent on [email protected], and [email protected], dependent
                    on [email protected], install [email protected] and [email protected]. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.bar11)
                self.pkgsend_bulk(durl, self.baz10)
                self.image_create(durl)
                self.pkg("list -a")
                self.pkg("install [email protected] [email protected]")

        def test_bug_1338_3(self):
                """ Add [email protected], [email protected]. [email protected] depends on [email protected] which
                    depends on [email protected], install [email protected]. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.xbar10)
                self.pkgsend_bulk(durl, self.xdeep10)
                self.image_create(durl)

                self.pkg("install [email protected]", exit=1)

        def test_bug_1338_4(self):
                """ Add [email protected]. [email protected] depends on [email protected] which depends
                on [email protected], install [email protected]. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.ydeep10)
                self.image_create(durl)

                self.pkg("install [email protected]", exit=1)

        def test_bug_2795(self):
                """ Try to install two versions of the same package """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.pkgsend_bulk(durl, self.foo12)
                self.image_create(durl)

                self.pkg("install [email protected] [email protected]", exit=1)

        def test_bug_6018(self):
                """  From original comment in bug report:

                Consider a repository that contains:

                a@1 and a@2

                b@1 that contains an optional dependency on package a@1

                If a@1 and b@1 are installed in an image, the "pkg image-update" command
                produces the following output:

                $ pkg image-update
                No updates available for this image.

                However, "pkg install a@2" works. 
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.a6018_1)
                self.pkgsend_bulk(durl, self.a6018_2)                
                self.pkgsend_bulk(durl, self.b6018_1)                
                self.image_create(durl)
                self.pkg("install b6018@1 a6018@1")
                self.pkg("image-update")
                self.pkg("list b6018@1 a6018@2")


        def test_install_matching(self):
                """ Try to [un]install packages matching a pattern """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)
                self.pkgsend_bulk(durl, self.bar10)
                self.pkgsend_bulk(durl, self.baz10)
                self.image_create(durl)
                # don't specify versions here; we have many
                # different versions of foo, bar & baz in repo
                # when entire class is run w/ one repo instance.
                
                # first case should fail since multiple patterns
                # match the same pacakge
                self.pkg("install 'ba*' 'b*'", exit=1)
                self.pkg("install 'ba*'", exit=0)
                self.pkg("list foo", exit=0)
                self.pkg("list bar", exit=0)
                self.pkg("list baz", exit=0)
                self.pkg("uninstall 'b*' 'f*'")

        def test_bug_3770(self):
                """ Try to install two versions of the same package """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)
                self.dc.stop()
                self.pkg("install [email protected]", exit=1)
                self.dc.start()

        def test_bug_9929(self):
                """Make sure that we can uninstall/install a package that
                already has its contents on disk."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.pkg("install foo")

                self.dc.stop()
                self.pkg("uninstall foo")
                lr_path = os.path.join(self.img_path, "var","pkg","publisher",
                    "test", "last_refreshed")
                os.unlink(lr_path) 
                self.pkg("install --no-refresh foo")
                self.dc.start()

class TestPkgInstallAmbiguousPatterns(testutils.SingleDepotTestCase):

        # An "ambiguous" package name pattern is one which, because of the
        # pattern matching rules, might refer to more than one package.  This
        # may be as obvious as the pattern "SUNW*", but also like the pattern
        # "foo", where "foo" and "a/foo" both exist in the catalog.

        afoo10 = """
            open a/[email protected],5.11-0
            close """

        bfoo10 = """
            open b/[email protected],5.11-0
            close """

        bar10 = """
            open [email protected],5.11-0
            close """

        foo10 = """
            open [email protected],5.11-0
            close """

        foo11 = """
            open [email protected],5.11-0
            close """

        anotherfoo11 = """
            open another/[email protected],5.11-0
            close """

        depender10 = """
            open [email protected],5.11-0
            add depend type=require [email protected]
            close """

        depender11 = """
            open [email protected],5.11-0
            add depend type=require [email protected]
            close """

        def test_bug_4204(self):
                """Don't stack trace when printing a PlanCreationException with
                "multiple_matches" populated (on uninstall)."""
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.afoo10)
                self.pkgsend_bulk(durl, self.bfoo10)
                self.pkgsend_bulk(durl, self.bar10)
                self.image_create(durl)

                self.pkg("install foo", exit=1)
                self.pkg("install a/foo b/foo", exit=0)
                self.pkg("list")                
                self.pkg("uninstall foo", exit=1)
                self.pkg("uninstall a/foo b/foo", exit=0)

        def test_bug_6874(self):
                """Don't stack trace when printing a PlanCreationException with
                "multiple_matches" populated (on install and image-update)."""
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.afoo10)
                self.pkgsend_bulk(durl, self.bfoo10)
                self.image_create(durl)

                self.pkg("install foo", exit=1)

        def test_ambiguous_pattern_install(self):
                """An image-update should never get confused about an existing
                package being part of an ambiguous set of package names."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo10)

                self.image_create(durl)
                self.pkg("install foo")

                self.pkgsend_bulk(durl, self.anotherfoo11)
                self.pkg("refresh")
                self.pkg("image-update -v", exit=4)

        def test_ambiguous_pattern_depend(self):
                """A dependency on a package should pull in an exact name
                match."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.depender10)
                self.pkgsend_bulk(durl, self.foo10)

                self.image_create(durl)
                self.pkg("install depender")

                self.pkgsend_bulk(durl, self.foo11)
                self.pkgsend_bulk(durl, self.anotherfoo11)
                self.pkgsend_bulk(durl, self.depender11)
                self.pkg("refresh")

                self.pkg("install depender")

                # Make sure that we didn't get other/foo from the dependency.
                self.pkg("list another/foo", exit=1)

        def test_non_ambiguous_fragment(self):
                """We should be able to refer to a package by its "basename", if
                that component is unique."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.anotherfoo11)
                self.image_create(durl)

                # Right now, this is not exact, but still unambiguous
                self.pkg("install foo")

                # Create ambiguity
                self.pkgsend_bulk(durl, self.foo11)
                self.pkg("refresh")

                # This is unambiguous, should succeed
                self.pkg("install pkg:/foo")

                # This is now ambiguous, should fail
                self.pkg("install foo", exit=1)

class TestPkgInstallCircularDependencies(testutils.SingleDepotTestCase):
        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        pkg10 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/pkg2
            close
        """

        pkg20 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/pkg3
            close
        """

        pkg30 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/pkg1
            close
        """


        pkg11 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            close
        """

        pkg21 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            close
        """

        pkg31 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            close
        """

        def test_unanchored_circular_dependencies(self):
                """ check to make sure we can install
                circular dependencies w/o versions
                """

                # Send 1.0 versions of packages.
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.pkg10)
                self.pkgsend_bulk(durl, self.pkg20)
                self.pkgsend_bulk(durl, self.pkg30)

                self.image_create(durl)
                self.pkg("install pkg1")
                self.pkg("list")
                self.pkg("verify -v")

        def test_anchored_circular_dependencies(self):
                """ check to make sure we can install
                circular dependencies w/ versions
                """

                # Send 1.0 versions of packages.
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.pkg11)
                self.pkgsend_bulk(durl, self.pkg21)
                self.pkgsend_bulk(durl, self.pkg31)

                self.image_create(durl)
                self.pkg("install pkg1")
                self.pkg("list")
                self.pkg("verify -v")


class TestPkgInstallUpgrade(testutils.SingleDepotTestCase):
        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        incorp10 = """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """

        incorp20 = """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """

        incorp30 = """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """

        incorpA = """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """

        incorpB =  """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """

        iridium10 = """
            open [email protected],5.11-0
            add depend fmri=pkg:/[email protected] type=require
            close
        """
        amber10 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/lib
            add dir mode=0755 owner=root group=bin path=/etc
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.so.1
            add link path=/lib/libc.symlink target=/lib/libc.so.1
            add hardlink path=/lib/libc.hardlink target=/lib/libc.so.1
            add file /tmp/amber1 mode=0444 owner=root group=bin path=/etc/amber1
            add file /tmp/amber2 mode=0444 owner=root group=bin path=/etc/amber2
            add license /tmp/copyright1 license=copyright
            close
        """

        brass10 = """
            open [email protected],5.11-0
            add depend fmri=pkg:/bronze type=require
            close
        """

        bronze10 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/usr
            add dir mode=0755 owner=root group=bin path=/usr/bin
            add file /tmp/sh mode=0555 owner=root group=bin path=/usr/bin/sh
            add link path=/usr/bin/jsh target=./sh
            add hardlink path=/lib/libc.bronze target=/lib/libc.so.1
            add file /tmp/bronze1 mode=0444 owner=root group=bin path=/etc/bronze1
            add file /tmp/bronze2 mode=0444 owner=root group=bin path=/etc/bronze2
            add file /tmp/bronzeA1 mode=0444 owner=root group=bin path=/A/B/C/D/E/F/bronzeA1
            add depend fmri=pkg:/[email protected] type=require
            add license /tmp/copyright2 license=copyright
            close
        """

        amber20 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/usr
            add dir mode=0755 owner=root group=bin path=/usr/bin
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.so.1
            add link path=/lib/libc.symlink target=/lib/libc.so.1
            add hardlink path=/lib/libc.amber target=/lib/libc.bronze
            add hardlink path=/lib/libc.hardlink target=/lib/libc.so.1
            add file /tmp/amber1 mode=0444 owner=root group=bin path=/etc/amber1
            add file /tmp/amber2 mode=0444 owner=root group=bin path=/etc/bronze2
            add depend fmri=pkg:/[email protected] type=require
            add license /tmp/copyright2 license=copyright
            close
        """

        bronze20 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/etc
            add dir mode=0755 owner=root group=bin path=/lib
            add file /tmp/sh mode=0555 owner=root group=bin path=/usr/bin/sh
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.bronze
            add link path=/usr/bin/jsh target=./sh
            add hardlink path=/lib/libc.bronze2.0.hardlink target=/lib/libc.so.1
            add file /tmp/bronze1 mode=0444 owner=root group=bin path=/etc/bronze1
            add file /tmp/bronze2 mode=0444 owner=root group=bin path=/etc/amber2
            add license /tmp/copyright3 license=copyright
            add file /tmp/bronzeA2 mode=0444 owner=root group=bin path=/A1/B2/C3/D4/E5/F6/bronzeA2
            add depend fmri=pkg:/[email protected] type=require
            close
        """

        bronze30 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/etc
            add dir mode=0755 owner=root group=bin path=/lib
            add file /tmp/sh mode=0555 owner=root group=bin path=/usr/bin/sh
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.bronze
            add link path=/usr/bin/jsh target=./sh
            add hardlink path=/lib/libc.bronze2.0.hardlink target=/lib/libc.so.1
            add file /tmp/bronze1 mode=0444 owner=root group=bin path=/etc/bronze1
            add file /tmp/bronze2 mode=0444 owner=root group=bin path=/etc/amber2
            add license /tmp/copyright3 license=copyright
            add file /tmp/bronzeA2 mode=0444 owner=root group=bin path=/A1/B2/C3/D4/E5/F6/bronzeA2
            add depend fmri=pkg:/[email protected] type=require
            close
        """


        gold10 = """
            open [email protected],5.11-0
            add file /tmp/config1 mode=0644 owner=root group=bin path=etc/config1 preserve=true
            close
        """

        gold20 = """
            open [email protected],5.11-0
            add file /tmp/config2 mode=0644 owner=root group=bin path=etc/config2 original_name="gold:etc/config1" preserve=true
            close
        """

        gold30 =  """
            open [email protected],5.11-0
            close
        """

        silver10  = """
            open [email protected],5.11-0
            close
        """

        silver20  = """
            open [email protected],5.11-0
            add file /tmp/config2 mode=0644 owner=root group=bin path=etc/config1 original_name="gold:etc/config1" preserve=true
            close
        """
        silver30  = """
            open [email protected],5.11-0
            add file /tmp/config2 mode=0644 owner=root group=bin path=etc/config2 original_name="gold:etc/config1" preserve=true
            close
        """



        iron10 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=etc
            add file /tmp/config1 mode=0644 owner=root group=bin path=etc/foo
            add hardlink path=etc/foo.link target=foo
            close
        """
        iron20 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=etc
            add file /tmp/config2 mode=0644 owner=root group=bin path=etc/foo
            add hardlink path=etc/foo.link target=foo
            close
        """

        concorp10 = """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """

        dricon1 = """
            open dricon@1
            add dir path=/tmp mode=755 owner=root group=root
            add dir path=/etc mode=755 owner=root group=root
            add file /tmp/dricon_da path=/etc/driver_aliases mode=644 owner=root group=sys preserve=true
            add file /tmp/dricon_n2m path=/etc/name_to_major mode=644 owner=root group=sys preserve=true
            close
        """

        dricon2 = """
            open dricon@2
            add dir path=/tmp mode=755 owner=root group=root
            add dir path=/etc mode=755 owner=root group=root
            add file /tmp/dricon2_da path=/etc/driver_aliases mode=644 owner=root group=sys preserve=true
            add file /tmp/dricon_n2m path=/etc/name_to_major mode=644 owner=root group=sys preserve=true
            add driver name=zigit alias=pci8086,1234
            close
        """

        dricon3 = """
            open dricon@3
            add dir path=/tmp mode=755 owner=root group=root
            add dir path=/etc mode=755 owner=root group=root
            add file /tmp/dricon2_da path=/etc/driver_aliases mode=644 owner=root group=sys preserve=true
            add file /tmp/dricon_n2m path=/etc/name_to_major mode=644 owner=root group=sys preserve=true
            add driver name=zigit alias=pci8086,1234
            add driver name=figit alias=pci8086,1234
            close
        """

        dripol1 = """
            open dripol@1
            add dir path=/tmp mode=755 owner=root group=root
            add dir path=/etc mode=755 owner=root group=root
            add dir path=/etc/security mode=755 owner=root group=root
            add file /tmp/dricon2_da path=/etc/driver_aliases mode=644 owner=root group=sys preserve=true
            add file /tmp/dricon_n2m path=/etc/name_to_major mode=644 owner=root group=sys preserve=true
            add file /tmp/dripol1_dp path=/etc/security/device_policy mode=644 owner=root group=sys preserve=true
            add driver name=frigit policy="read_priv_set=net_rawaccess write_priv_set=net_rawaccess"
            close
        """

        dripol2 = """
            open dripol@2
            add dir path=/tmp mode=755 owner=root group=root
            add dir path=/etc mode=755 owner=root group=root
            add dir path=/etc/security mode=755 owner=root group=root
            add file /tmp/dricon2_da path=/etc/driver_aliases mode=644 owner=root group=sys preserve=true
            add file /tmp/dricon_n2m path=/etc/name_to_major mode=644 owner=root group=sys preserve=true
            add file /tmp/dripol1_dp path=/etc/security/device_policy mode=644 owner=root group=sys preserve=true
            add driver name=frigit
            close
        """

	liveroot10 = """
            open [email protected]
            add dir path=/etc mode=755 owner=root group=root
            add file /tmp/liveroot1 path=/etc/liveroot mode=644 owner=root group=sys reboot-needed=true
            close
        """
	liveroot20 = """
            open [email protected]
            add dir path=/etc mode=755 owner=root group=root
            add file /tmp/liveroot2 path=/etc/liveroot mode=644 owner=root group=sys reboot-needed=true
            close
        """

        misc_files = [
            "/tmp/amber1", "/tmp/amber2", "/tmp/bronzeA1",  "/tmp/bronzeA2",
            "/tmp/bronze1", "/tmp/bronze2",
            "/tmp/copyright1", "/tmp/copyright2",
            "/tmp/copyright3", "/tmp/copyright4",
            "/tmp/libc.so.1", "/tmp/sh", "/tmp/config1", "/tmp/config2",
            "/tmp/dricon_da", "/tmp/dricon2_da", "/tmp/dricon_n2m",
            "/tmp/dripol1_dp", "/tmp/liveroot1", "/tmp/liveroot2"
        ]

        misc_files_contents = {
            "/tmp/dricon_da": """\
wigit "pci8086,1234"
wigit "pci8086,4321"
# someother "pci8086,1234"
foobar "pci8086,9999"
""",
            "/tmp/dricon2_da": """\
zigit "pci8086,1234"
wigit "pci8086,4321"
# someother "pci8086,1234"
foobar "pci8086,9999"
""",
            "/tmp/dricon_n2m": """\
wigit 1
foobar 2
""",
            "/tmp/dripol1_dp": """\
*		read_priv_set=none		write_priv_set=none
"""

        }

        def setUp(self):
                testutils.SingleDepotTestCase.setUp(self)
                for p in self.misc_files:
                        f = open(p, "w")
                        # If no contents are specified, write the name of the
                        # file into the file, so that all files have differing
                        # contents
                        f.write(self.misc_files_contents.get(p, p))
                        f.close()
                        self.debug("wrote %s" % p)

        def tearDown(self):
                testutils.SingleDepotTestCase.tearDown(self)
                for p in self.misc_files:
                        os.remove(p)

        def test_incorp_install(self):
                """Make sure we don't round up packages we specify on
                install"""
                durl = self.dc.get_depot_url()
                first_bronze = self.pkgsend_bulk(durl, self.bronze20)
                self.pkgsend_bulk(durl, self.incorp20)
                self.pkgsend_bulk(durl, self.amber10)
                self.pkgsend_bulk(durl, self.bronze10)
                self.pkgsend_bulk(durl, self.amber20)
                self.pkgsend_bulk(durl, self.bronze20)

                # create image 
                self.image_create(durl)
                # install incorp2
                self.pkg("install [email protected]")
                # try to install version 1
                self.pkg("install [email protected]", exit=1)
                # install earliest version [email protected]
                self.pkg("install %s" % first_bronze[0])
                self.pkg("list -v %s" % first_bronze[0])
                self.pkg("install [email protected]")

        def test_upgrade1(self):

                """ Upgrade torture test.
                    Send package [email protected], bronze1.0; install bronze1.0, which
                    should cause amber to also install.
                    Send 2.0 versions of packages which contains a lot of
                    complex transactions between amber and bronze, then do
                    an image-update, and try to check the results.
                """

                # Send 1.0 versions of packages.
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.incorp10)
                self.pkgsend_bulk(durl, self.amber10)
                self.pkgsend_bulk(durl, self.bronze10)

                #
                # In version 2.0, several things happen:
                #
                # Amber and Bronze swap a file with each other in both directions.
                # The dependency flips over (Amber now depends on Bronze)
                # Amber and Bronze swap ownership of various directories.
                #
                # Bronze's 1.0 hardlink to amber's libc goes away and is replaced
                # with a file of the same name.  Amber hardlinks to that.
                #
                self.pkgsend_bulk(durl, self.incorp20)
                self.pkgsend_bulk(durl, self.amber20)
                self.pkgsend_bulk(durl, self.bronze20)

                # create image and install version 1
                self.image_create(durl)
                self.pkg("install [email protected]")
                self.pkg("install bronze")

                self.pkg("list [email protected] [email protected]")
                self.pkg("verify -v")

                # demonstrate that [email protected] prevents package movement
                self.pkg("install [email protected] [email protected]", exit=1)

                # Now image-update to get new versions of amber and bronze
                self.pkg("image-update")

                # Try to verify that it worked.
                self.pkg("list [email protected] [email protected]")
                self.pkg("verify -v")
                # make sure old implicit directories for bronzeA1 were removed
                self.assert_(not os.path.isdir(os.path.join(self.get_img_path(), "A")))
                # Remove packages
                self.pkg("uninstall amber bronze")
                self.pkg("verify -v")

                # make sure all directories are gone save /var in test image
                self.assert_(os.listdir(self.get_img_path()) ==  ["var"])

        def test_upgrade2(self):
                """ test incorporations:
                        1) install files that conflict w/ existing incorps
                        2) install package w/ dependencies that violate incorps
                        3) install incorp that violates existing incorp
                        4) install incorp that would force package backwards
                        """

                # Send all pkgs
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.incorp10)
                self.pkgsend_bulk(durl, self.incorp20)
                self.pkgsend_bulk(durl, self.incorp30)
                self.pkgsend_bulk(durl, self.iridium10)
                self.pkgsend_bulk(durl, self.concorp10)
                self.pkgsend_bulk(durl, self.amber10)
                self.pkgsend_bulk(durl, self.amber20)
                self.pkgsend_bulk(durl, self.bronze10)
                self.pkgsend_bulk(durl, self.bronze20)
                self.pkgsend_bulk(durl, self.bronze30)
                self.pkgsend_bulk(durl, self.brass10)

                self.image_create(durl)

                self.pkg("install [email protected]")
                # install files that conflict w/ existing incorps
                self.pkg("install [email protected]", exit=1)
                # install package w/ dependencies that violate incorps
                self.pkg("install [email protected]", exit=1)
                # install package w/ unspecified dependency that pulls
                # in bronze
                self.pkg("install brass")
                self.pkg("verify [email protected] [email protected]")
                # attempt to install conflicting incorporation
                self.pkg("install [email protected]", exit=1)

                # attempt to force downgrade of package w/ older incorp
                self.pkg("install [email protected]")
                self.pkg("uninstall [email protected]")
                self.pkg("install [email protected]", exit=1)

                # upgrade pkg that loses incorp. deps. in new version
                self.pkg("install [email protected]")
                self.pkg("image-update")
                self.pkg("list [email protected]")

        def test_upgrade3(self):
                """ test for editable files moving between packages or locations or both"""
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.silver10)
                self.pkgsend_bulk(durl, self.silver20)
                self.pkgsend_bulk(durl, self.silver30)
                self.pkgsend_bulk(durl, self.gold10)
                self.pkgsend_bulk(durl, self.gold20)
                self.pkgsend_bulk(durl, self.gold30)

                self.image_create(durl)

                # first test - move an editable file between packages

                self.pkg("install [email protected] [email protected]")
                self.pkg("verify -v")

                # modify config file

                str = "this file has been modified 1"
                file_path = "etc/config1"
                self.file_append(file_path, str)

               # make sure /etc/config1 contains correct string
                self.file_contains(file_path, str)

                # update packages

                self.pkg("install [email protected] [email protected]")
                self.pkg("verify -v")

                # make sure /etc/config1 contains still correct string
                self.file_contains(file_path, str)

                self.pkg("uninstall silver gold")

                # test file moving within package

                self.pkg("install [email protected]")
                self.pkg("verify -v")

                # modify config file
                str = "this file has been modified test 2"
                file_path = "etc/config1"
                self.file_append(file_path, str)

                self.pkg("install [email protected]")
                self.pkg("verify -v")

                 # make sure /etc/config2 contains correct string

                file_path = "etc/config2"
                self.file_contains(file_path, str)

                self.pkg("uninstall gold")
                self.pkg("verify -v")

                # test movement in filesystem and across packages

                self.pkg("install [email protected] [email protected]")
                self.pkg("verify -v")

                # modify config file

                file_path = "etc/config1"
                str = "this file has been modified test 3"
                self.file_append(file_path, str)

                self.file_contains(file_path, str)

                self.pkg("install [email protected] [email protected]")
                self.pkg("verify -v")
                 # make sure /etc/config2 now contains correct string
                file_path = "etc/config2"
                self.file_contains(file_path, str)

        def test_upgrade4(self):
                """ test to make sure hardlinks are correctly restored when file they point to is updated """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.iron10)
                self.pkgsend_bulk(durl, self.iron20)

                self.image_create(durl)

                self.pkg("install [email protected]")
                self.pkg("verify -v")

                self.pkg("install [email protected]")
                self.pkg("verify -v")

        def test_upgrade_liveroot(self):
                """ test to make sure upgrade of package fails if on live root
                and reboot is needed"""
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.liveroot10)
                self.pkgsend_bulk(durl, self.liveroot20)
                self.image_create(durl)

                self.pkg("--debug simulate_live_root=True install [email protected]")
                self.pkg("verify -v")
                self.pkg("--debug simulate_live_root=True install [email protected]", exit=5)
                self.pkg("--debug simulate_live_root=True uninstall liveroot", exit=5)
                # "break" liveroot@1
                self.file_append("etc/liveroot", "this file has been changed")
                self.pkg("--debug simulate_live_root=True fix liveroot", exit=5)

        def test_upgrade_driver_conflicts(self):
                """Test to make sure driver_aliases conflicts don't cause
                add_drv to fail."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.dricon1)
                self.pkgsend_bulk(durl, self.dricon2)
                self.pkgsend_bulk(durl, self.dricon3)

                self.image_create(durl)

                self.pkg("list -afv")
                self.pkg("install dricon@1")
                # This one should comment out the wigit entry in driver_aliases
                self.pkg("install dricon@2")
                da_contents = file(os.path.join(self.get_img_path(),
                    "etc/driver_aliases")).readlines()
                self.assert_("# pkg(5): wigit \"pci8086,1234\"\n" in da_contents)
                self.assert_("wigit \"pci8086,1234\"\n" not in da_contents)
                self.assert_("wigit \"pci8086,4321\"\n" in da_contents)
                self.assert_("zigit \"pci8086,1234\"\n" in da_contents)
                # This one should fail
                self.pkg("install dricon@3", exit=1)

        def test_driver_policy_removal(self):
                """Test for bug #9568 - that removing a policy for a
                driver where there is no minor node associated with it,
                works successfully.
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.dripol1)
                self.pkgsend_bulk(durl, self.dripol2)

                self.image_create(durl)

                self.pkg("list -afv")

                # Should install the frigit driver with a policy.
                self.pkg("install dripol@1")

                # Check that there is a policy entry for this
                # device in /etc/security/device_policy
                dp_contents = file(os.path.join(self.get_img_path(),
                    "etc/security/device_policy")).readlines()
                self.assert_("frigit:*\tread_priv_set=net_rawaccess\twrite_priv_set=net_rawaccess\n" in dp_contents)

                # Should reinstall the frigit driver without a policy.
                self.pkg("install dripol@2")

                # Check that there is no longer a policy entry for this
                # device in /etc/security/device_policy
                dp_contents = file(os.path.join(self.get_img_path(),
                    "etc/security/device_policy")).readlines()
                self.assert_("frigit:*\tread_priv_set=net_rawaccess\twrite_priv_set=net_rawaccess\n" not in dp_contents)

        def file_append(self, path, string):
                file_path = os.path.join(self.get_img_path(), path)
                f = file(file_path, "a+")
                f.write("\n%s\n" % string)
                f.close

        def file_contains(self, path, string):
                file_path = os.path.join(self.get_img_path(), path)
                f = file(file_path)
                for line in f:
                        if string in line:
                                f.close()
                                break
                else:
                        f.close()
                        self.assert_(False, "File %s does not contain %s" % (path, string))


class TestPkgInstallActions(testutils.SingleDepotTestCase):
        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        ftpusers_data = \
"""# ident      "@(#)ftpusers   1.6     06/11/21 SMI"
#
# List of users denied access to the FTP server, see ftpusers(4).
#
root
bin
sys
adm
"""
        group_data = \
"""root::0:
other::1:root
bin::2:root,daemon
sys::3:root,bin,adm
adm::4:root,daemon
"""
        passwd_data = \
"""root:x:0:0::/root:/usr/bin/bash
daemon:x:1:1::/:
bin:x:2:2::/usr/bin:
sys:x:3:3::/:
adm:x:4:4:Admin:/var/adm:
"""
        shadow_data = \
"""root:9EIfTNBp9elws:13817::::::
daemon:NP:6445::::::
bin:NP:6445::::::
sys:NP:6445::::::
adm:NP:6445::::::
"""

        cat_data = " "

        foo10 = """
            open [email protected],5.11-0
            close """

        only_attr10 = """
            open [email protected],5.11-0
            add set name=foo value=bar
            close """

        only_depend10 = """
            open [email protected],5.11-0
            add depend type=require [email protected],5.11-0
            close """

        only_directory10 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/bin
            close """

        only_driver10 = """
            open [email protected],5.11-0
            add driver name=zerg devlink="type=ddi_pseudo;name=zerg\\t\D"
            close """

        only_group10 = """
            open [email protected],5.11-0
            add group groupname=Kermit gid=28
            close """

        only_group_file10 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=Kermit path=/export/home/Kermit
            close """

        only_hardlink10 = """
            open [email protected],5.11-0
            add hardlink path=/cat.hardlink target=/cat
            close """

        only_legacy10 = """
            open [email protected],5.11-0
            add legacy arch=i386 category=system desc="GNU make - A utility used to build software (gmake) 3.81" hotline="Please contact your local service provider" name="gmake - GNU make" pkg=SUNWgmake vendor="Sun Microsystems, Inc." version=11.11.0,REV=2008.04.29.02.08
            close """

        only_link10 = """
            open [email protected],5.11-0
            add link path=/link target=/tmp/cat
            close """

        only_user10 = """
            open [email protected],5.11-0
            add user username=Kermit group=adm home-dir=/export/home/Kermit
            close """

        only_user_file10 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=Kermit group=adm path=/export/home/Kermit
            close """

        empty_data = ""

        misc_files = [ "empty", "ftpusers", "group", "passwd", "shadow", "cat" ]

        testdata_dir = None

        pkg_name_valid_chars = {
            "never": " `~!@#$%^&*()=[{]}\\|;:\",<>?",
            "always": "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
            "after-first": "_/-.+",
            "at-end": "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.+",
        }

        def setUp(self):

                testutils.SingleDepotTestCase.setUp(self)
                tp = self.get_test_prefix()
                self.testdata_dir = os.path.join(tp, "testdata")
                os.mkdir(self.testdata_dir)


                self.only_file10 = """
                    open [email protected],5.11-0
                    add file """ + self.testdata_dir + """/cat mode=0555 owner=root group=bin path=/cat
                    close """

                self.only_license10 = """
                    open [email protected],5.11-0
                    add license """ + self.testdata_dir + """/cat license=copyright
                    close """

                self.basics0 = """
                    open [email protected],5.11-0
                    add file """ + self.testdata_dir + """/passwd mode=0644 owner=root group=sys path=etc/passwd preserve=true
                    add file """ + self.testdata_dir + """/shadow mode=0400 owner=root group=sys path=etc/shadow preserve=true
                    add file """ + self.testdata_dir + """/group mode=0644 owner=root group=sys path=etc/group preserve=true
                    add file """ + self.testdata_dir + """/ftpusers mode=0644 owner=root group=sys path=etc/ftpd/ftpusers preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=etc/name_to_major preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=etc/driver_aliases preserve=true
                    add dir mode=0755 owner=root group=sys path=etc
                    add dir mode=0755 owner=root group=sys path=etc/ftpd
                    close """

                self.basics1 = """
                    open [email protected],5.11-0
                    add dir mode=0755 owner=root group=bin path=lib
                    add dir mode=0755 owner=root group=sys path=var
                    add dir mode=0755 owner=root group=sys path=var/svc
                    add dir mode=0755 owner=root group=sys path=var/svc/manifest
                    add dir mode=0755 owner=root group=bin path=usr
                    add dir mode=0755 owner=root group=bin path=usr/local
                    close """

                self.grouptest = """
                    open [email protected],5.11-0
                    add dir mode=0755 owner=root group=Kermit path=/usr/Kermit
                    add file """ + self.testdata_dir + """/empty mode=0755 owner=root group=Kermit path=/usr/local/bin/do_group_nothing
                    add group groupname=lp gid=8
                    add group groupname=staff gid=10
                    add group groupname=Kermit
                    add depend fmri=pkg:/[email protected] type=require
                    close """

                self.usertest10 = """
                    open [email protected],5.11-0
                    add dir mode=0755 owner=Kermit group=Kermit path=/export/home/Kermit
                    add file """ + self.testdata_dir + """/empty mode=0755 owner=Kermit group=Kermit path=/usr/local/bin/do_user_nothing
                    add depend fmri=pkg:/[email protected] type=require
                    add user username=Kermit group=Kermit home-dir=/export/home/Kermit group-list=lp group-list=staff
                    add depend fmri=pkg:/[email protected] type=require
                    add depend fmri=pkg:/[email protected] type=require
                    close """

                self.usertest11 = """
                    open [email protected],5.11-0
                    add dir mode=0755 owner=Kermit group=Kermit path=/export/home/Kermit
                    add file """ + self.testdata_dir + """/empty mode=0755 owner=Kermit group=Kermit path=/usr/local/bin/do_user_nothing
                    add depend fmri=pkg:/[email protected] type=require
                    add user username=Kermit group=Kermit home-dir=/export/home/Kermit group-list=lp group-list=staff group-list=root ftpuser=false
                    add depend fmri=pkg:/[email protected] type=require
                    add depend fmri=pkg:/[email protected] type=require
                    close """

                self.ugidtest = """
                    open [email protected],5.11-0
                    add user username=dummy group=root
                    add group groupname=dummy
                    close """

                self.silver10 = """
                    open [email protected],5.11-0
                    add file """ + self.testdata_dir + """/empty mode=0755 owner=root group=root path=/usr/local/bin/silver
                    add depend fmri=pkg:/[email protected] type=require
                    add depend fmri=pkg:/[email protected] type=require
                    close """
                self.silver20 = """
                    open [email protected],5.11-0
                    add file """ + self.testdata_dir + """/empty mode=0755 owner=Kermit group=Kermit path=/usr/local/bin/silver
                    add user username=Kermit group=Kermit home-dir=/export/home/Kermit group-list=lp group-list=staff
                    add depend fmri=pkg:/[email protected] type=require
                    add depend fmri=pkg:/[email protected] type=require
                    add depend fmri=pkg:/[email protected] type=require
                    close """

                self.devicebase = """
                    open [email protected],5.11-0
                    add dir mode=0755 owner=root group=root path=/tmp
                    add dir mode=0755 owner=root group=root path=/etc
                    add dir mode=0755 owner=root group=root path=/etc/security
                    add file """ + self.testdata_dir + """/empty mode=0600 owner=root group=root path=/etc/devlink.tab preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=/etc/name_to_major preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=/etc/driver_aliases preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=/etc/driver_classes preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=/etc/minor_perm preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=root path=/etc/security/device_policy preserve=true
                    add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=/etc/security/extra_privs preserve=true
                    close
                """

                self.devlink10 = """
                    open [email protected],5.11-0
                    add driver name=zerg devlink="type=ddi_pseudo;name=zerg\\t\D"
                    add driver name=borg devlink="type=ddi_pseudo;name=borg\\t\D" devlink="type=ddi_pseudo;name=warg\\t\D"
                    add depend type=require fmri=devicebase
                    close
                """

                self.devlink20 = """
                    open [email protected],5.11-0
                    add driver name=zerg devlink="type=ddi_pseudo;name=zerg2\\t\D" devlink="type=ddi_pseudo;name=zorg\\t\D"
                    add driver name=borg devlink="type=ddi_pseudo;name=borg\\t\D" devlink="type=ddi_pseudo;name=zork\\t\D"
                    add depend type=require fmri=devicebase
                    close
                """

                self.badhardlink1 = """
                    open [email protected],5.11-0
                    add hardlink path=foo target=bar
                    close
                """

                self.badhardlink2 = """
                    open [email protected],5.11-0
                    add file """ + self.testdata_dir + """/cat mode=0555 owner=root group=bin path=/etc/motd
                    add hardlink path=foo target=/etc/motd
                    close
                """

                self.dirshouldbelink = """
                    open [email protected],5.11-0
                    add dir mode=0755 owner=root group=bin path=foo
                    add link path=foo target=bar
                    close
                """

                for f in self.misc_files:
                        filename = os.path.join(self.testdata_dir, f)
                        file_handle = open(filename, 'wb')
                        try:
                                file_handle.write(eval("self.%s_data" % f))
                        finally:
                                file_handle.close()

        def tearDown(self):
                testutils.SingleDepotTestCase.tearDown(self)
                if self.testdata_dir:
                        shutil.rmtree(self.testdata_dir)

        def test_basics_0(self):
                """Send basic infrastructure, install and uninstall."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.basics0)
                self.pkgsend_bulk(durl, self.basics1)
                self.image_create(durl)

                self.pkg("list -a")
                self.pkg("list", exit=1)

                self.pkg("install basics")
                self.pkg("install basics1")

                self.pkg("list")
                self.pkg("verify")

                self.pkg("uninstall basics basics1")
                self.pkg("verify")

        def test_grouptest(self):
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.basics0)
                self.pkgsend_bulk(durl, self.basics1)
                self.pkgsend_bulk(durl, self.grouptest)
                self.image_create(durl)
                self.pkg("install basics")
                self.pkg("install basics1")

                self.pkg("install grouptest")
                self.pkg("verify")
                self.pkg("uninstall grouptest")
                self.pkg("verify")

        def test_usertest(self):
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.basics0)
                self.pkgsend_bulk(durl, self.basics1)
                self.pkgsend_bulk(durl, self.grouptest)
                self.pkgsend_bulk(durl, self.usertest10)
                self.image_create(durl)
                self.pkg("install basics")
                self.pkg("install basics1")

                self.pkg("install usertest")
                self.pkg("verify")
                self.pkg("contents -m usertest")

                self.pkgsend_bulk(durl, self.usertest11)
                self.pkg("refresh")
                self.pkg("install usertest")
                self.pkg("verify")
                self.pkg("contents -m usertest")

                self.pkg("uninstall usertest")
                self.pkg("verify")

        def test_minugid(self):
                """Ensure that an unspecified uid/gid results in the first
                unused."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.ugidtest)
                self.image_create(durl)

                os.mkdir(os.path.join(self.get_img_path(), "etc"))
                os.mkdir(os.path.join(self.get_img_path(), "etc/ftpd"))
                for f in self.misc_files:
                        dir = "etc"
                        if f == "ftpusers":
                                dir = "etc/ftpd"
                        filename = os.path.join(self.get_img_path(), dir, f)
                        file_handle = open(filename, 'wb')
                        exec("%s_path = \"%s\"" % (f, filename))
                        try:
                                file_handle.write(eval("self.%s_data" % f))
                        finally:
                                file_handle.close()

                self.pkg("install ugidtest")
                passwd_file = file(passwd_path)
                for line in passwd_file:
                        if line.startswith("dummy"):
                                self.assert_(line.startswith("dummy:x:5:"))
                passwd_file.close()
                group_file = file(group_path)
                for line in group_file:
                        if line.startswith("dummy"):
                                self.assert_(line.startswith("dummy::5:"))
                group_file.close()

        def test_upgrade_with_user(self):
                """Ensure that we can add a user and change file ownership to
                that user in the same delta (mysql tripped over this early on
                in IPS development)."""
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.basics0)
                self.pkgsend_bulk(durl, self.basics1)
                self.pkgsend_bulk(durl, self.silver10)
                self.pkgsend_bulk(durl, self.silver20)
                self.pkgsend_bulk(durl, self.grouptest)
                self.image_create(durl)
                self.pkg("install [email protected]")
                self.pkg("install [email protected]")
                self.pkg("install [email protected]")
                self.pkg("list [email protected]")
                self.pkg("verify -v")
                self.pkg("install [email protected]")
                self.pkg("verify -v")

        def test_invalid_open(self):
                """Send a invalid package definition (invalid fmri); expect
                failure."""

                durl = self.dc.get_depot_url()

                for char in self.pkg_name_valid_chars["never"]:
                        invalid_name = "invalid%[email protected],5.11-0" % char
                        self.pkgsend(durl, "open '%s'" % invalid_name, exit=1)

                for char in self.pkg_name_valid_chars["after-first"]:
                        invalid_name = "%[email protected],5.11-0" % char
                        if char == "-":
                                cmd = "open -- '%s'" % invalid_name
                        else:
                                cmd = "open '%s'" % invalid_name
                        self.pkgsend(durl, cmd, exit=1)

                        invalid_name = "invalid/%[email protected],5.11-0" % char
                        cmd = "open '%s'" % invalid_name
                        self.pkgsend(durl, cmd, exit=1)

        def test_valid_open(self):
                """Send a invalid package definition (valid fmri); expect
                success."""

                durl = self.dc.get_depot_url()
                for char in self.pkg_name_valid_chars["always"]:
                        valid_name = "%svalid%s/%spkg%[email protected],5.11-0" % (char,
                            char, char, char)
                        self.pkgsend(durl, "open '%s'" % valid_name)
                        self.pkgsend(durl, "close -A")

                for char in self.pkg_name_valid_chars["after-first"]:
                        valid_name = "v%salid%[email protected],5.11-0" % (char, char)
                        self.pkgsend(durl, "open '%s'" % valid_name)
                        self.pkgsend(durl, "close -A")

                for char in self.pkg_name_valid_chars["at-end"]:
                        valid_name = "validpkg%[email protected],5.11-0" % char
                        self.pkgsend(durl, "open '%s'" % valid_name)
                        self.pkgsend(durl, "close -A")

        def test_devlink(self):
                # driver actions are not valid except on OpenSolaris
                if portable.util.get_canonical_os_name() != "sunos":
                        return

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.devicebase)
                self.pkgsend_bulk(durl, self.devlink10)
                self.pkgsend_bulk(durl, self.devlink20)
                self.image_create(durl)

                def readfile():
                        dlf = file(os.path.join(self.get_img_path(),
                            "etc/devlink.tab"))
                        dllines = dlf.readlines()
                        dlf.close()
                        return dllines

                def writefile(dllines):
                        dlf = file(os.path.join(self.get_img_path(),
                            "etc/devlink.tab"), "w")
                        dlf.writelines(dllines)
                        dlf.close()

                def assertContents(dllines, contents):
                        actual = re.findall("name=([^\t;]*)",
                            "\n".join(dllines), re.M)
                        self.assert_(set(actual) == set(contents))

                # Install
                self.pkg("install [email protected]")
                self.pkg("verify -v")

                dllines = readfile()

                # Verify that three entries got added
                self.assert_(len(dllines) == 3)

                # Verify that the tab character got written correctly
                self.assert_(dllines[0].find("\t") > 0)

                # Upgrade
                self.pkg("install [email protected]")
                self.pkg("verify -v")

                dllines = readfile()

                # Verify that there are four entries now
                self.assert_(len(dllines) == 4)

                # Verify they are what they should be
                assertContents(dllines, ["zerg2", "zorg", "borg", "zork"])

                # Remove
                self.pkg("uninstall devlinktest")
                self.pkg("verify -v")

                # Install again
                self.pkg("install [email protected]")

                # Diddle with it
                dllines = readfile()
                for i, line in enumerate(dllines):
                        if line.find("zerg") != -1:
                                dllines[i] = "type=ddi_pseudo;name=zippy\t\D\n"
                writefile(dllines)

                # Upgrade
                self.pkg("install [email protected]")

                # Verify that we spewed a message on upgrade
                self.assert_(self.output.find("not found") != -1)
                self.assert_(self.output.find("name=zerg") != -1)

                # Verify the new set
                dllines = readfile()
                self.assert_(len(dllines) == 5)
                assertContents(dllines,
                    ["zerg2", "zorg", "borg", "zork", "zippy"])

                self.pkg("uninstall devlinktest")

                # Null out the "zippy" entry
                writefile([])

                # Install again
                self.pkg("install [email protected]")

                # Diddle with it
                dllines = readfile()
                for i, line in enumerate(dllines):
                        if line.find("zerg") != -1:
                                dllines[i] = "type=ddi_pseudo;name=zippy\t\D\n"
                writefile(dllines)

                # Remove
                self.pkg("uninstall devlinktest")

                # Verify that we spewed a message on removal
                self.assert_(self.output.find("not found") != -1)
                self.assert_(self.output.find("name=zerg") != -1)

                # Verify that the one left behind was the one we overwrote.
                dllines = readfile()
                self.assert_(len(dllines) == 1)
                assertContents(dllines, ["zippy"])

                # Null out the "zippy" entry, but add the "zerg" entry
                writefile(["type=ddi_pseudo;name=zerg\t\D\n"])

                # Install ... again
                self.pkg("install [email protected]")

                # Make sure we didn't get a second zerg line
                dllines = readfile()
                self.failUnless(len(dllines) == 3, msg=dllines)
                assertContents(dllines, ["zerg", "borg", "warg"])

                # Now for the same test on upgrade
                dllines.append("type=ddi_pseudo;name=zorg\t\D\n")
                writefile(dllines)

                self.pkg("install [email protected]")
                dllines = readfile()
                self.failUnless(len(dllines) == 4, msg=dllines)
                assertContents(dllines, ["zerg2", "zorg", "borg", "zork"])

        def test_uninstall_without_perms(self):
                """Test for bug 4569"""
                durl = self.dc.get_depot_url()

                pkg_list = [self.foo10, self.only_attr10, self.only_depend10,
                    self.only_directory10, self.only_file10,
                    self.only_group10, self.only_hardlink10, self.only_legacy10,
                    self.only_license10, self.only_link10, self.only_user10]

                # driver actions are not valid except on OpenSolaris
                if portable.util.get_canonical_os_name() == 'sunos':
                        pkg_list += [self.only_driver10]

                self.pkgsend_bulk(durl, "".join(pkg_list) + self.devicebase + \
                    self.basics0 + self.basics1)

                self.image_create(durl)

                name_pat = re.compile("^\s+open\s+(\S+)\@.*$")

                def __manually_check_deps(name, install=True, exit=0):
                        cmd = "install --no-refresh"
                        if not install:
                                cmd = "uninstall"
                        if name == "only_depend" and not install:
                                self.pkg("uninstall foo", exit=exit)
                        elif name == "only_driver":
                                self.pkg("%s devicebase" % cmd, exit=exit)
                        elif name == "only_group":
                                self.pkg("%s basics" % cmd, exit=exit)
                        elif name == "only_hardlink":
                                self.pkg("%s only_file" % cmd, exit=exit)
                        elif name == "only_user":
                                if install:
                                        self.pkg("%s basics" % cmd, exit=exit)
                                        self.pkg("%s only_group" % cmd, exit=exit)
                                else:
                                        self.pkg("%s only_group" % cmd, exit=exit)
                                        self.pkg("%s basics" % cmd, exit=exit)
                for p in pkg_list:
                        name_mat = name_pat.match(p.splitlines()[1])
                        pname = name_mat.group(1)
                        __manually_check_deps(pname, exit=[0,4])
                        self.pkg("install --no-refresh %s" % pname,
                            su_wrap=True, exit=1)
                        self.pkg("install %s" % pname, su_wrap=True,
                            exit=1)
                        self.pkg("install --no-refresh %s" % pname)
                        self.pkg("uninstall %s" % pname, su_wrap=True,
                            exit=1)
                        self.pkg("uninstall %s" % pname)
                        __manually_check_deps(pname, install=False)

                for p in pkg_list:
                        name_mat = name_pat.match(p.splitlines()[1])
                        pname = name_mat.group(1)
                        __manually_check_deps(pname, exit=[0,4])
                        self.pkg("install --no-refresh %s" % pname)

                for p in pkg_list:
                        self.pkgsend_bulk(durl, p)
                self.pkgsend_bulk(durl, self.devicebase + self.basics0 + \
                    self.basics1)

                self.pkg("image-update --no-refresh", su_wrap=True, exit=4)
                self.pkg("refresh")
                self.pkg("image-update", su_wrap=True, exit=1)
                # Should fail since user doesn't have permission to refresh
                # publisher metadata.
                self.pkg("refresh --full", su_wrap=True, exit=1)
                self.pkg("refresh --full")
                self.pkg("image-update --no-refresh", su_wrap=True,
                    exit=1)
                self.pkg("image-update")

        def test_bug_3222(self):
                """ Verify that a timestamp of '0' for a passwd file will not
                    cause further package operations to fail.  This can happen
                    when there are time synchronization issues within a virtual
                    environment or in other cases. """
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.basics0)
                self.pkgsend_bulk(durl, self.only_user10)
                self.pkgsend_bulk(durl, self.only_user_file10)
                self.pkgsend_bulk(durl, self.only_group10)
                self.pkgsend_bulk(durl, self.only_group_file10)
                self.pkgsend_bulk(durl, self.grouptest)
                self.pkgsend_bulk(durl, self.usertest10)
                self.image_create(durl)
                fname = os.path.join(self.get_img_path(), "etc", "passwd")
                self.pkg("install basics")

                # This should work regardless of whether a user is installed
                # at the same time as the file in a package, or if the user is
                # installed first and then files owned by that user are
                # installed.
                plists = [["grouptest", "usertest"],
                    ["only_user", "only_user_file"],
                    ["only_group", "only_group_file"]]
                for plist in plists:
                        for pname in plist:
                                os.utime(fname, (0, 0))
                                self.pkg("install %s" % pname)
                                self.pkg("verify")

                        for pname in reversed(plist):
                                os.utime(fname, (0, 0))
                                self.pkg("uninstall %s" % pname)
                                self.pkg("verify")

        def test_bad_hardlinks(self):
                """A couple of bogus hard link target tests."""

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.badhardlink1)
                self.pkgsend_bulk(durl, self.badhardlink2)
                self.image_create(durl)

                # A package which tries to install a hard link to a target that
                # doesn't exist shouldn't stack trace, but exit sanely.
                self.pkg("install badhardlink1", exit=1)

                # A package which tries to install a hard link to a target
                # specified as an absolute path should install that link
                # relative to the image root.
                self.pkg("install badhardlink2")
                ino1 = os.stat(os.path.join(self.get_img_path(), "foo")).st_ino
                ino2 = os.stat(os.path.join(self.get_img_path(), "etc/motd")).st_ino
                self.assert_(ino1 == ino2)

        def test_bad_links(self):
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.dirshouldbelink)
                self.image_create(durl)

                self.pkg("install dirshouldbelink", exit=1)

class TestDependencies(testutils.SingleDepotTestCase):
        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        pkg10 = """
            open [email protected],5.11-0
            add depend type=optional fmri=pkg:/pkg2
            close
        """

        pkg20 = """
            open [email protected],5.11-0
            close
        """

        pkg11 = """
            open [email protected],5.11-0
            add depend type=optional fmri=pkg:/[email protected]
            close
        """

        pkg21 = """
            open [email protected],5.11-0
            close
        """

        pkg30 = """
            open [email protected],5.11-0
            add depend type=require fmri=pkg:/[email protected]
            close
        """

        pkg40 = """
            open [email protected],5.11-0
            add depend type=exclude fmri=pkg:/[email protected]
            close
        """

        pkg50 = """
            open [email protected],5.11-0
            add depend type=exclude fmri=pkg:/[email protected]
            add depend type=require fmri=pkg:/[email protected]
            close
        """
 
        pkg505 = """
            open [email protected],5.11-0
            add depend type=exclude fmri=pkg:/[email protected]
            add depend type=require fmri=pkg:/[email protected]
            close
        """
        pkg51 = """
            open [email protected],5.11-0
            add depend type=exclude fmri=pkg:/[email protected]
            add depend type=exclude fmri=pkg:/pkg2
            add depend type=require fmri=pkg:/[email protected]
            close
        """
        pkg60 = """
            open [email protected],5.11-0
            add depend type=exclude fmri=pkg:/[email protected]
            close
        """

        pkg61 = """
            open [email protected],5.11-0
            close
        """

        leaf_template = """
            open pkg%s%s@%s,5.11-0
            add depend type=require fmri=pkg:/%s_incorp
            close
        """
        leaf_expansion = [
                ("A","_0", "1.0", "A"),
                ("A","_1", "1.0", "A"),
                ("A","_2", "1.0", "A"),
                ("A","_3", "1.0", "A"),

                ("B","_0", "1.0", "B"),
                ("B","_1", "1.0", "B"),
                ("B","_2", "1.0", "B"),
                ("B","_3", "1.0", "B"),

                ("A","_0", "1.1", "A"),
                ("A","_1", "1.1", "A"),
                ("A","_2", "1.1", "A"),
                ("A","_3", "1.1", "A"),

                ("B","_0", "1.1", "B"),
                ("B","_1", "1.1", "B"),
                ("B","_2", "1.1", "B"),
                ("B","_3", "1.1", "B")
                ]

        incorps = [ """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """, 

        """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """, 

        """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """, 

        """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """, 

        """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """,

        """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """]
                    
        bug_7394_incorp = """
            open [email protected],5.11-0
            add depend type=incorporate fmri=pkg:/[email protected]
            close
        """


        def setUp(self):
                testutils.SingleDepotTestCase.setUp(self)
                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.pkg10)
                self.pkgsend_bulk(durl, self.pkg20)
                self.pkgsend_bulk(durl, self.pkg11)
                self.pkgsend_bulk(durl, self.pkg21)
                self.pkgsend_bulk(durl, self.pkg30)
                self.pkgsend_bulk(durl, self.pkg40)
                self.pkgsend_bulk(durl, self.pkg50)
                self.pkgsend_bulk(durl, self.pkg505)
                self.pkgsend_bulk(durl, self.pkg51)
                self.pkgsend_bulk(durl, self.pkg60)
                self.pkgsend_bulk(durl, self.pkg61)
                self.pkgsend_bulk(durl, self.bug_7394_incorp)

                for t in self.leaf_expansion:
                        self.pkgsend_bulk(durl, self.leaf_template % t)

                for i in self.incorps:
                        self.pkgsend_bulk(durl, i)

        def test_require_dependencies(self):
                """ exercise require dependencies"""
                durl = self.dc.get_depot_url()
                self.image_create(durl)
                self.pkg("install [email protected]")
                self.pkg("verify  [email protected]")
                self.pkg("install [email protected]")
                self.pkg("verify  [email protected] [email protected]")

        def test_exclude_dependencies(self):
                """ exercise exclude dependencies """
                durl = self.dc.get_depot_url()
                self.image_create(durl)
                # install pkg w/ exclude dep.
                self.pkg("install [email protected]")
                self.pkg("verify  [email protected]")
                # install pkg that is allowed by dep
                self.pkg("install [email protected]")
                self.pkg("verify  [email protected]")
                # try to install disallowed pkg
                self.pkg("install [email protected]", exit=1)
                self.pkg("uninstall '*'")
                # install pkg 
                self.pkg("install [email protected]")
                # try to install pkg exclude dep on already
                # installed pkg
                self.pkg("install [email protected]", exit=1)
                self.pkg("uninstall '*'")
                # install a package w/ both exclude
                # and require dependencies
                self.pkg("install pkg5")
                self.pkg("verify [email protected] [email protected] ")
                self.pkg("uninstall '*'")
                # pick pkg to install that fits constraint
                # of already installed pkg
                self.pkg("install pkg2")
                self.pkg("install pkg5")
                self.pkg("verify [email protected] [email protected] pkg2")
                self.pkg("uninstall '*'")
                # install a package that requires updating
                # existing package to avoid exclude 
                # dependency
                self.pkg("install [email protected]")
                self.pkg("install [email protected]")
                self.pkg("verify [email protected] [email protected]")
                self.pkg("uninstall '*'")
                # try to install two incompatible pkgs
                self.pkg("install [email protected] [email protected]", exit=1)

        def test_optional_dependencies(self):
                """ check to make sure that optional dependencies are enforced
                """
                durl = self.dc.get_depot_url()
                self.image_create(durl)
                self.pkg("install [email protected]")

                # pkg2 is optional, it should not have been installed
                self.pkg("list pkg2", exit=1)

                self.pkg("install [email protected]")

                # this should install [email protected] and upgrade pkg2 to [email protected]
                self.pkg("install pkg1")
                self.pkg("list [email protected]")

                self.pkg("uninstall pkg2")
                self.pkg("list pkg2", exit=1)
                # this should not install [email protected] because of the optional
                # dependency in pkg1
                self.pkg("list [email protected]")
                self.pkg("install [email protected]", exit=1)

        def test_incorporation_dependencies(self):
                """ shake out incorporation dependencies """
                durl = self.dc.get_depot_url()
                self.image_create(durl)
                self.pkg("list -a") # help w/ debugging

                # simple pkg requiring controlling incorp
                # should control pkgA_1 as well
                self.pkg("install -v [email protected] pkgA_1")
                self.pkg("list")
                self.pkg("verify [email protected] [email protected] [email protected]")
                self.pkg("image-update -v")
                self.pkg("list [email protected] [email protected] [email protected]")
                self.pkg("uninstall '*'")
                # try nested incorporations
                self.pkg("install -v [email protected] pkgA_0 pkgB_0")
                self.pkg("list")
                self.pkg("list [email protected] [email protected] [email protected] [email protected] [email protected]")
                # try to break incorporation
                self.pkg("install -v [email protected]", exit=1) # fixed by [email protected]
                # try image update
                self.pkg("image-update -v")
                self.pkg("list [email protected] [email protected] [email protected] [email protected] [email protected]")
                self.pkg("uninstall '*'")
                # what happens when incorporation specified
                # a package that isn't in the catalog
                self.pkg("install bug_7394_incorp")
                self.pkg("install pkg1", exit=1)

class TestMultipleDepots(testutils.ManyDepotTestCase):
        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        foo10 = """
            open [email protected],5.11-0
            close"""

        bar10 = """
            open [email protected],5.11-0
            close"""

        moo10 = """
            open [email protected],5.11-0
            close"""

        quux10 = """
            open [email protected],5.11-0
            add depend type=optional [email protected]
            close"""

        baz10 = """
            open [email protected],5.11-0
            add depend type=require [email protected]
            close"""

        corge10 = """
            open [email protected],5.11-0
            close"""

        optional10 = """
            open [email protected],5.11-0
            close"""

        upgrade_p10 = """
            open [email protected],5.11-0
            close"""

        upgrade_p11 = """
            open [email protected],5.11-0
            close"""

        upgrade_np10 = """
            open [email protected],5.11-0
            close"""

        upgrade_np11 = """
            open [email protected],5.11-0
            close"""

        incorp_p10 = """
            open [email protected],5.11-0
            add depend type=incorporate [email protected]
            close"""

        incorp_p11 = """
            open [email protected],5.11-0
            add depend type=incorporate [email protected]
            close"""

        incorp_np10 = """
            open [email protected],5.11-0
            add depend type=incorporate [email protected]
            close"""

        incorp_np11 = """
            open [email protected],5.11-0
            add depend type=incorporate [email protected]
            close"""

        def setUp(self):
                """ Start four depots.
                    depot 1 gets foo and moo, depot 2 gets foo and bar,
                    depot 3 is empty, depot 4 gets [email protected]
                    depot1 is mapped to publisher test1 (preferred)
                    depot2 is mapped to publisher test2
                    depot3 is not mapped during setUp
                    depot4 is not mapped during setUp"""

                # Two depots are intentionally started for test2.
                testutils.ManyDepotTestCase.setUp(self, ["test1", "test2",
                    "test3", "test2"])

                durl1 = self.dcs[1].get_depot_url()
                self.pkgsend_bulk(durl1, self.foo10 + self.moo10 + \
                    self.quux10 + self.optional10 + self.upgrade_p10 + \
                    self.upgrade_np11 + self.incorp_p10 + self.incorp_p11 + \
                    self.incorp_np10 + self.incorp_np11 + self.baz10 + \
                    self.corge10)

                durl2 = self.dcs[2].get_depot_url()
                self.pkgsend_bulk(durl2, self.foo10 + self.bar10 + \
                    self.upgrade_p11 + self.upgrade_np10 + self.corge10)

                durl4 = self.dcs[4].get_depot_url()
                self.pkgsend_bulk(durl4, self.upgrade_np11)

                # Create image and hence primary publisher
                self.image_create(durl1, prefix="test1")

                # Create second publisher using depot #2
                self.pkg("set-publisher -O " + durl2 + " test2")

        def tearDown(self):
                testutils.ManyDepotTestCase.tearDown(self)

        def test_01_basics(self):
                self.pkg("list -a")

                # Install and uninstall moo (which is unique to depot 1)
                self.pkg("install moo")

                self.pkg("list")
                self.pkg("uninstall moo")

                # Install and uninstall bar (which is unique to depot 2)
                self.pkg("install bar")

                self.pkg("list")

                self.pkg("uninstall bar")

                # Install and uninstall foo (which is in both depots)
                # In this case, we should select foo from depot 1, since
                # it is preferred.
                self.pkg("install foo")

                self.pkg("list pkg://test1/foo")

                self.pkg("uninstall foo")

        def test_02_basics(self):
                """ Test install from an explicit preferred publisher """
                self.pkg("install pkg://test1/foo")
                self.pkg("list foo")
                self.pkg("list pkg://test1/foo")
                self.pkg("uninstall foo")

        def test_03_basics(self):
                """ Test install from an explicit non-preferred publisher """
                self.pkg("install pkg://test2/foo")
                self.pkg("list foo")
                self.pkg("list pkg://test2/foo")
                self.pkg("uninstall foo")

        def test_04_upgrade_preferred_to_non_preferred(self):
                """Install a package from the preferred publisher, and then
                upgrade it, failing to implicitly switching to a non-preferred
                publisher and then managing it explicitly"""
                self.pkg("list -a upgrade-p")
                self.pkg("install [email protected]")
                self.pkg("install [email protected]", exit=1)
                self.pkg("install pkg://test2/[email protected]")
                self.pkg("uninstall upgrade-p")

        def test_05_upgrade_non_preferred_to_preferred(self):
                """Install a package from a non-preferred publisher, and then
                try to upgrade it, failing to implicitly switchto the preferred 
                publisher and then succeed doing it explicitly."""
                self.pkg("list -a upgrade-np")
                self.pkg("install [email protected]")
                self.pkg("install [email protected]", exit=1)
                self.pkg("install pkg://test1/[email protected]")
                self.pkg("uninstall upgrade-np")

        def test_06_upgrade_preferred_to_non_preferred_incorporated(self):
                """Install a package from the preferred publisher, and then
                upgrade it, failing to implicitly switching to a non-preferred
                publisher, when the package is constrained by an
                incorporation, and then succeed when doing so explicitly"""

                self.pkg("list -a upgrade-p incorp-p")
                self.pkg("install [email protected]")
                self.pkg("install upgrade-p")
                self.pkg("install [email protected]", exit=1)
                self.pkg("install [email protected] pkg://test2/[email protected]")
                self.pkg("list [email protected]")
                self.pkg("uninstall '*'")


        def test_07_upgrade_non_preferred_to_preferred_incorporated(self):
                """Install a package from the preferred publisher, and then
                upgrade it, implicitly switching to a non-preferred
                publisher, when the package is constrained by an
                incorporation."""
                self.pkg("list", exit=1)
                self.pkg("list -a upgrade-np incorp-np")
                self.pkg("install [email protected]")
                self.pkg("install upgrade-np", exit=1)
                self.pkg("uninstall '*'")

        def test_08_install_repository_access(self):
                """Verify that packages can still be installed from a repository
                even when any of the other repositories are not reachable and
                --no-refresh is used."""

                # Change the second publisher to point to an unreachable URI.
                self.pkg("set-publisher --no-refresh -O http://test.invalid7 test2")

                # Verify that no packages are installed.
                self.pkg("list", exit=1)

                # Verify moo can not be installed (as only depot1 has it) since
                # test2 cannot be reached (and needs a refresh).
                self.pkg("install moo", exit=1)

                # Verify moo can be installed (as only depot1 has it) even though
                # test2 cannot be reached (and needs a refresh) if --no-refresh
                # is used.
                self.pkg("install --no-refresh moo")

                self.pkg("uninstall moo")

                # Reset the test2 publisher.
                durl2 = self.dcs[2].get_depot_url()
                self.pkg("set-publisher -O %s test2" % durl2)

                # Install v1.0 of upgrade-np from test2 to prepare for
                # image-update.
                self.pkg("install [email protected]")

                # Set test1 to point to an unreachable URI.
                self.pkg("set-publisher --no-refresh -O http://test.invalid7 test1")

                # Set test2 so that upgrade-np has a new version available
                # even though test1's repository is not accessible.
                durl4 = self.dcs[4].get_depot_url()
                self.pkg("set-publisher -O %s test2" % durl4)

                # Verify image-update does not work since test1 is unreachable
                # even though [email protected] is available from test2.
                self.pkg("image-update", exit=1)

                # Verify image-update works even though test1 is unreachable
                # since [email protected] is available from test2 if --no-refresh
                # is used.
                self.pkg("image-update --no-refresh")

                # Now reset everything for the next test.
                self.pkg("uninstall upgrade-np")
                durl1 = self.dcs[1].get_depot_url()
                self.pkg("set-publisher --no-refresh -O %s test1" % durl1)
                self.pkg("set-publisher -O %s test2" % durl2)

        def test_09_uninstall_from_wrong_publisher(self):
                """Install a package from a publisher and try to remove it
                using a different publisher name; this should fail."""
                self.pkg("install foo")
                self.pkg("uninstall pkg://test2/foo", exit=1)
                # Check to make sure that uninstalling using the explicit
                # publisher works
                self.pkg("uninstall pkg://test1/foo")

        def test_10_install_after_publisher_removal(self):
                """Install a package from a publisher that has an optional
                dependency; then change the preferred publisher and remove the
                original publisher and then verify that installing the package
                again succeeds since it is essentially a no-op."""
                self.pkg("install [email protected]")
                self.pkg("set-publisher -P test2")
                self.pkg("unset-publisher test1")
                self.pkg("list")

                # Attempting to install an already installed package should
                # be a no-op even if the corresponding publisher no longer
                # exists.
                self.pkg("install [email protected]", exit=4)

                # Image update should work if we don't see the optional dependency
                self.pkg("image-update", exit=4)

                # Add back the installed package's publisher, but using a
                # a repository with an empty catalog.  After that, attempt to
                # install the package again, which should succeed even though
                # the fmri is no longer in the publisher's catalog.
                self.pkg("set-publisher -O %s test1" % \
                    self.dcs[3].get_depot_url())
                self.pkg("install [email protected]", exit=4)
                self.pkg("info [email protected]")
                self.pkg("unset-publisher test1")

                # Add a new publisher, using the installed package publisher's
                # repository and add back the installed package's publisher, but
                # using a repository with an empty catalog.  After that, attempt
                # to install the package again, which should succeed even though
                # the package's installed publisher is known, but doesn't have
                # the package's fmri in its catalog, but the package's fmri is
                # in a different publisher's catalog.
                self.pkg("set-publisher -O %s test3" % \
                    self.dcs[1].get_depot_url())
                self.pkg("set-publisher -O %s test1" % \
                    self.dcs[3].get_depot_url())
                self.pkg("install [email protected]", exit=4)
                self.pkg("unset-publisher test1")
                self.pkg("unset-publisher test3")

                # Add a new publisher, using the installed package publisher's
                # repository.  After that, attempt to install the package again,
                # which should succeed even though the fmri is only in a
                # different publisher's catalog.
                self.pkg("set-publisher -O %s test3" % \
                    self.dcs[1].get_depot_url())
                self.pkg("install [email protected]", exit=4)
                self.pkg("unset-publisher test3")

                # Change the image metadata back to where it was, in preparation
                # for subsequent tests.
                self.pkg("set-publisher -O %s -P test1" % \
                    self.dcs[1].get_depot_url())

                # Remove the installed packages.
                self.pkg("uninstall quux")

        def test_11_uninstall_after_preferred_publisher_change(self):
                """Install a package from the preferred publisher, change the
                preferred publisher, and attempt to remove the package."""
                self.pkg("install [email protected]")
                self.pkg("set-publisher -P test2")
                self.pkg("uninstall foo")
                # Change the image metadata back to where it was, in preparation
                # for the next test.
                self.pkg("set-publisher -P test1")

        def test_12_uninstall_after_publisher_removal(self):
                """Install a package from the preferred publisher, remove the
                preferred publisher, and then evaluate whether an uninstall
                would succeed regardless of whether its publisher still exists
                or another publisher has the same fmri in its catalog."""
                self.pkg("install [email protected]")
                self.pkg("set-publisher -P test2")
                self.pkg("unset-publisher test1")

                # Attempting to uninstall should work even if the corresponding
                # publisher no longer exists.
                self.pkg("uninstall -nv foo")

                # Add back the installed package's publisher, but using a
                # a repository with an empty catalog.  After that, attempt to
                # uninstall the package again, which should succeed even though
                # the fmri is no longer in the publisher's catalog.
                self.pkg("set-publisher -O %s test1" % \
                    self.dcs[3].get_depot_url())
                self.pkg("uninstall -nv foo")
                self.pkg("unset-publisher test1")

                # Add a new publisher, using the installed package publisher's
                # repository; then add back the installed package's publisher
                # using a repository with an empty catalog.  After that, attempt
                # to uninstall the package again, which should succeed even
                # though the package's installed publisher is known, but doesn't
                # have the package's fmri in its catalog, but the package's fmri
                # is in a different publisher's catalog.
                self.pkg("set-publisher -O %s test3" % \
                    self.dcs[1].get_depot_url())
                self.pkg("set-publisher -O %s test1" % \
                    self.dcs[3].get_depot_url())
                self.pkg("uninstall -nv foo")
                self.pkg("unset-publisher test1")
                self.pkg("unset-publisher test3")

                # Add a new publisher, using the installed package publisher's
                # repository.  After that, attempt to uninstall the package
                # again, which should succeed even though the fmri is only in a
                # different publisher's catalog.
                self.pkg("set-publisher -O %s test3" % \
                    self.dcs[1].get_depot_url())
                self.pkg("uninstall -nv foo")
                self.pkg("unset-publisher test3")

                # Finally, actually remove the package.
                self.pkg("uninstall -v foo")

                # Change the image metadata back to where it was, in preparation
                # for subsequent tests.
                self.pkg("set-publisher -O %s -P test1" % \
                    self.dcs[1].get_depot_url())

        def test_13_non_preferred_multimatch(self):
                """Verify that when multiple non-preferred publishers offer the
                same package that the expected install behaviour occurs."""

                self.pkg("set-publisher -P -O %s test3" % \
                    self.dcs[3].get_depot_url())

                # make sure we look here first; tests rely on that
                self.pkg("set-publisher --search-before=test2 test1")
                self.pkg("publisher")
                # First, verify that installing a package from a non-preferred
                # publisher will cause its dependencies to be installed from the
                # same publisher if the preferred publisher does not offer them.
                self.pkg("list -a")
                self.pkg("install pkg://test1/baz")
                self.pkg("list")
                self.pkg("info baz | grep test1")
                self.pkg("info corge | grep test1")
                self.pkg("uninstall -r corge")

                # Next, verify that naming the specific publishers for a package
                # and all of its dependencies will install the package from the
                # specified sources instead of the same publisher the package is a
                # dependency of.
                self.pkg("install pkg://test1/baz pkg://test2/corge")
                self.pkg("info baz | grep test1")
                self.pkg("info corge | grep test2")
                self.pkg("uninstall -r corge")

                # Finally, cleanup for the next test.
                self.pkg("set-publisher -P test1")
                self.pkg("unset-publisher test3")

        def test_14_nonsticky_publisher(self):
                """Test various aspects of the stick/non-sticky
                behavior of publishers"""

                # For ease of debugging
                self.pkg("list -a")
                # install from non-preferred repo explicitly
                self.pkg("install pkg://test2/[email protected]")
                # Demonstrate that perferred publisher is not
                # acceptable, since test2 is sticky by default
                self.pkg("install [email protected]", exit=1) # not right repo
                # Check that we can proceed once test2 is not sticky
                self.pkg("set-publisher --non-sticky test2")
                self.pkg("install [email protected]") # should work now
                # Restore to pristine
                self.pkg("set-publisher --sticky test2")
                self.pkg("uninstall upgrade-np")
                # Repeat the test w/ preferred
                self.pkg("install upgrade-p")
                self.pkg("set-publisher -P test2")
                self.pkg("install [email protected]", exit=1) #orig pub is sticky
                self.pkg("set-publisher --non-sticky test1")  #not anymore
                self.pkg("install [email protected]")
                self.pkg("set-publisher -P --sticky test1") # restore
                self.pkg("uninstall '*'")
                # Check  that search order can be overridden w/ explicit
                # version specification...
                self.pkg("install upgrade-p")
                self.pkg("install [email protected]", exit=1)
                self.pkg("set-publisher --non-sticky test1") 
                self.pkg("install [email protected]") # find match later on 
                self.pkg("set-publisher --sticky test1")
                self.pkg("uninstall '*'")                

        def test_15_nonsticky_update(self):
                """Test to make sure image-update follows the same
                publisher selection mechanisms as pkg install"""

                # try image-update
                self.pkg("install pkg://test2/[email protected]")
                self.pkg("image-update", exit=4) 
                self.pkg("list [email protected]")
                self.pkg("set-publisher --non-sticky test2") 
                self.pkg("publisher")
                self.pkg("list -a upgrade-np")
                self.pkg("image-update") 
                self.pkg("list [email protected]")
                self.pkg("set-publisher --sticky test2")  
                self.pkg("uninstall '*'")                

        def test_16_disabled_nonsticky(self):
                """Test to make sure disabled publishers are 
                automatically made non-sticky, and after 
                being enabled keep their previous value
                of stickiness"""

                # For ease of debugging
                self.pkg("list -a")
                # install from non-preferred repo explicitly
                self.pkg("install pkg://test2/[email protected]")
                # Demonstrate that perferred publisher is not
                # acceptable, since test2 is sticky by default
                self.pkg("install [email protected]", exit=1) # not right repo
                # Disable test2 and then we should be able to proceed
                self.pkg("set-publisher --disable test2")
                self.pkg("install [email protected]")
                self.pkg("publisher")
                self.pkg("set-publisher --enable test2")
                self.pkg("publisher")
                self.pkg("publisher | egrep sticky", exit=1 )
                
class TestImageCreateCorruptImage(testutils.SingleDepotTestCaseCorruptImage):
        """
        If a new essential directory is added to the format of an image it will
        be necessary to update this test suite. To update this test suite,
        decide in what ways it is necessary to corrupt the image (removing the
        new directory or file, or removing the some or all of contents of the
        new directory for example). Make the necessary changes in
        testutils.SingleDepotTestCaseCorruptImage to allow the needed
        corruptions, then add new tests to the suite below. Be sure to add
        tests for both Full and User images, and perhaps Partial images if
        situations are found where these behave differently than Full or User
        images.
        """

        # Only start/stop the depot once (instead of for every test)
        persistent_depot = True

        foo11 = """
            open [email protected],5.11-0
            add dir mode=0755 owner=root group=bin path=/lib
            add file /tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.so.1
            close """

        misc_files = [ "/tmp/libc.so.1" ]

        PREFIX = "unset PKG_IMAGE; cd %s"

        def setUp(self):
                testutils.SingleDepotTestCaseCorruptImage.setUp(self)
                for p in self.misc_files:
                        f = open(p, "w")
                        # write the name of the file into the file, so that
                        # all files have differing contents
                        f.write(p)
                        f.close()
                        self.debug("wrote %s" % p)

        def tearDown(self):
                testutils.SingleDepotTestCaseCorruptImage.tearDown(self)
                for p in self.misc_files:
                        os.remove(p)

        def pkg(self, command, exit=0, comment=""):
                testutils.SingleDepotTestCaseCorruptImage.pkg(self, command,
                    exit=exit, comment=comment, prefix=self.PREFIX % self.dir)

        # For each test:
        # A good image is created at $basedir/image
        # A corrupted image is created at $basedir/image/bad (called bad_dir
        #     in subsequent notes) in verious ways
        # The $basedir/image/bad/final directory is created and PKG_IMAGE
        #     is set to that dirctory.

        # Tests simulating a corrupted Full Image

        def test_empty_var_pkg(self):
                """ Creates an empty bad_dir. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher", "cfg_cache", "file", "pkg", "index"]),
                    ["var/pkg"])

                self.pkg("install [email protected]")

        def test_var_pkg_missing_publisher(self):
                """ Creates bad_dir with only the publisher and known/state
                dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher_absent", "known_absent"]),
                    ["var/pkg"])

                self.pkg("install [email protected]")

        def test_var_pkg_missing_cfg_cache(self):
                """ Creates bad_dir with only the cfg_cache file missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["cfg_cache_absent"]), ["var/pkg"])

                self.pkg("install [email protected]")

        def test_var_pkg_missing_file(self):
                """ Creating bad_dir with only the file dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["file_absent"]), ["var/pkg"])

                self.pkg("install [email protected]")

        def test_var_pkg_missing_pkg(self):
                """ Creates bad_dir with only the pkg dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(["pkg_absent"]),
                    ["var/pkg"])

                self.pkg("install [email protected]")

        def test_var_pkg_missing_index(self):
                """ Creates bad_dir with only the index dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(["index_absent"]),
                    ["var/pkg"])

                self.pkg("install [email protected]")

        def test_var_pkg_missing_publisher_empty(self):
                """ Creates bad_dir with all dirs and files present, but
                with an empty publisher and state/known dir.
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher_empty", "known_empty"]), ["var/pkg"])

                # This is expected to fail because it will see an empty
                # publisher directory and not rebuild the files as needed
                self.pkg("install --no-refresh [email protected]", exit=1)
                self.pkg("install [email protected]")

        def test_var_pkg_missing_publisher_empty_hit_then_refreshed_then_hit(
            self):
                """ Creates bad_dir with all dirs and files present, but with an
                with an empty publisher and state/known dir. This is to ensure
                that refresh will work, and that an install after the refresh
                also works.
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher_empty", "known_empty"]), ["var/pkg"])

                self.pkg("install --no-refresh [email protected]", exit=1)
                self.pkg("refresh")
                self.pkg("install [email protected]")


        def test_var_pkg_left_alone(self):
                """ Sanity check to ensure that the code for creating
                a bad_dir creates a good copy other than what's specified
                to be wrong. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(), ["var/pkg"])

                self.pkg("install [email protected]")

        # Tests simulating a corrupted User Image

        # These tests are duplicates of those above but instead of creating
        # a corrupt full image, they create a corrupt User image.

        def test_empty_ospkg(self):
                """ Creates a corrupted image at bad_dir by creating empty
                bad_dir.  """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher", "cfg_cache", "file", "pkg", "index"]),
                    [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

        def test_ospkg_missing_publisher(self):
                """ Creates a corrupted image at bad_dir by creating bad_dir
                with only the publisher and known/state dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher_absent", "known_absent"]),
                        [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

        def test_ospkg_missing_cfg_cache(self):
                """ Creates a corrupted image at bad_dir by creating
                bad_dir with only the cfg_cache file missing.  """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["cfg_cache_absent"]), [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

        def test_ospkg_missing_file(self):
                """ Creates a corrupted image at bad_dir by creating
                bad_dir with only the file dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(["file_absent"]),
                    [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

        def test_ospkg_missing_pkg(self):
                """ Creates a corrupted image at bad_dir by creating
                bad_dir with only the pkg dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(["pkg_absent"]),
                    [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

        def test_ospkg_missing_index(self):
                """ Creates a corrupted image at bad_dir by creating
                bad_dir with only the index dir missing. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(["index_absent"]),
                    [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

        def test_ospkg_missing_publisher_empty(self):
                """ Creates a corrupted image at bad_dir by creating bad_dir
                with all dirs and files present, but with an empty publisher
                and known/state dir. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher_empty", "known_empty"]),
                    [".org.opensolaris,pkg"])

                self.pkg("install --no-refresh [email protected]", exit=1)

        def test_ospkg_missing_publisher_empty_hit_then_refreshed_then_hit(self):
                """ Creates bad_dir with all dirs and files present, but with
                an empty publisher and known/state dir. This is to ensure that
                refresh will work, and that an install after the refresh also
                works.
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["publisher_empty", "known_empty"]),
                    [".org.opensolaris,pkg"])

                self.pkg("install --no-refresh [email protected]", exit=1)
                self.pkg("refresh")
                self.pkg("install [email protected]")

        def test_ospkg_left_alone(self):
                """ Sanity check to ensure that the code for creating
                a bad_dir creates a good copy other than what's specified
                to be wrong. """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(),
                    [".org.opensolaris,pkg"])

                self.pkg("install [email protected]")

# Tests for checking what happens when two images are installed side by side.

        def test_var_pkg_missing_cfg_cache_ospkg_also_missing_alongside(self):
                """ Each bad_dir is missing a cfg_cache
                These 3 tests do nothing currently because trying to install an
                image next to an existing image in not currently possible.  The
                test cases remain against the day that such an arrangement is
                possible.
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["cfg_cache_absent"]), [".org.opensolaris,pkg"])
                self.dir = self.corrupt_image_create(durl,
                    set(["cfg_cache_absent"]), ["var/pkg"], destroy=False)

                self.pkg("install [email protected]")


        def test_var_pkg_ospkg_missing_cfg_cache_alongside(self):
                """ Complete Full image besides a User image missing cfg_cache
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl, set(), ["var/pkg"])
                self.dir = self.corrupt_image_create(durl,
                    set(["cfg_cache_absent"]), [".org.opensolaris,pkg"],
                    destroy=False)

                self.pkg("install [email protected]")

        def test_var_pkg_missing_cfg_cache_ospkg_alongside(self):
                """ Complete User image besides a Full image missing cfg_cache
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, self.foo11)
                self.image_create(durl)

                self.dir = self.corrupt_image_create(durl,
                    set(["cfg_cache_absent"]), ["var/pkg"])
                self.dir = self.corrupt_image_create(durl, set(),
                    [".org.opensolaris,pkg"], destroy=False)

                self.pkg("install [email protected]")


class TestPkgInstallObsolete(testutils.SingleDepotTestCase):
        """Test cases for obsolete packages."""

        persistent_depot = True

        def setUp(self):
                testutils.SingleDepotTestCase.setUp(self)

        def test_basic(self):
                foo1 = """
                    open foo@1
                    add dir path=usr mode=0755 owner=root group=root
                    close
                """
                # Obsolete packages can have metadata
                foo2 = """
                    open foo@2
                    add set name=pkg.obsolete value=true
                    add set name=pkg.summary value="A test package"
                    close
                """

                fbar = """
                    open fbar@1
                    add depend type=require fmri=foo@2
                    close
                """

                qbar = """
                    open qbar@1
                    add depend type=require fmri=qux@2
                    close
                """

                qux1 = """
                    open qux@1
                    add dir path=usr mode=0755 owner=root group=root
                    close
                """

                qux2 = """
                    open qux@2
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=foo@1
                    close
                """

                fred1 = """
                    open fred@1
                    add depend type=require fmri=foo
                    close
                """
                fred2 = """
                    open fred@2
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, foo1)
                self.pkgsend_bulk(durl, foo2)
                self.pkgsend_bulk(durl, fbar)
                self.pkgsend_bulk(durl, qbar)
                self.pkgsend_bulk(durl, qux1)
                self.pkgsend_bulk(durl, qux2)
                self.pkgsend_bulk(durl, fred1)


                self.image_create(durl)

                # First install the non-obsolete version of foo
                self.pkg("install foo@1")
                self.pkg("list foo@1")

                # Now install the obsolete version, and ensure it disappears (5)
                self.pkg("install foo")
                self.pkg("list foo", exit=1)

                # Explicitly installing an obsolete package succeeds, but
                # results in nothing on the system. (1)
                self.pkg("install foo@2", exit=4)
                self.pkg("list foo", exit=1)

                # Installing a package with a dependency on an obsolete package
                # fails. (2)
                self.pkg("install fbar", exit=1)

                # Installing a package with a dependency on a renamed package
                # succeeds, leaving the first package and the renamed package on
                # the system, as well as the empty, pre-renamed package. (3)
                self.pkg("install qbar")
                self.pkg("list qbar")
                self.pkg("list foo@1")
                self.pkg("list qux | grep -- --r--")
                self.pkg("uninstall '*'") #clean up for next test
                # A simple rename test: First install the pre-renamed version of
                # qux.  Then install the renamed version, and see that the new
                # package is installed, and the renamed package is installed,
                # but marked renamed.  (4)
                self.pkg("install qux@1")
                self.pkg("install qux")
                self.pkg("list foo@1")
                self.pkg("list qux | grep -- --r--")
                self.pkg("uninstall '*'") #clean up for next test

                # Install a package that's going to be obsoleted and a package
                # that depends on it.  Update the package to its obsolete
                # version and see that it fails.  (6, sorta)
                self.pkg("install foo@1 fred@1")
                self.pkg("install foo@2", exit=1)
                # now add a version of fred that doesn't require foo, and
                # show that update works
                self.pkgsend_bulk(durl, fred2)
                self.pkg("refresh")
                self.pkg("install foo@2")

        def test_basic_7a(self):
                """Upgrade a package to a version with a dependency on a renamed
                package.  A => A' (-> Br (-> C))"""

                t7ap1_1 = """
                    open t7ap1@1
                    close
                """

                t7ap1_2 = """
                    open t7ap1@2
                    add depend type=require fmri=t7ap2
                    close
                """

                t7ap2_1 = """
                    open t7ap2@1
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=t7ap3
                    close
                """

                t7ap3_1 = """
                    open t7ap3@1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t7ap1_1)
                self.image_create(durl)

                self.pkg("install t7ap1")

                self.pkgsend_bulk(durl, t7ap1_2)
                self.pkgsend_bulk(durl, t7ap2_1)
                self.pkgsend_bulk(durl, t7ap3_1)

                self.pkg("refresh")
                self.pkg("image-update")
                self.pkg("list -af")
                self.pkg("list t7ap2 | grep -- --r--")
                self.pkg("list t7ap3")

        def test_basic_7b(self):
                """Upgrade a package to a version with a dependency on a renamed
                package.  Like 7a except package A starts off depending on B.

                A (-> B) => A' (-> Br (-> C))"""

                t7bp1_1 = """
                    open t7bp1@1
                    add depend type=require fmri=t7bp2
                    close
                """

                t7bp1_2 = """
                    open t7bp1@2
                    add depend type=require fmri=t7bp2
                    close
                """

                t7bp2_1 = """
                    open t7bp2@1
                    close
                """

                t7bp2_2 = """
                    open t7bp2@1
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=t7bp3
                    close
                """

                t7bp3_1 = """
                    open t7bp3@1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t7bp1_1)
                self.pkgsend_bulk(durl, t7bp2_1)
                self.image_create(durl)

                self.pkg("install t7bp1")

                self.pkgsend_bulk(durl, t7bp1_2)
                self.pkgsend_bulk(durl, t7bp2_2)
                self.pkgsend_bulk(durl, t7bp3_1)

                self.pkg("refresh")
                self.pkg("image-update")
                self.pkg("list t7bp2 | grep -- --r--")
                self.pkg("list t7bp3")

        def test_basic_7c(self):
                """Upgrade a package to a version with a dependency on a renamed
                package.  Like 7b, except package A doesn't change.

                A (-> B) => A (-> Br (-> C))"""

                t7cp1_1 = """
                    open t7cp1@1
                    add depend type=require fmri=t7cp2
                    close
                """

                t7cp2_1 = """
                    open t7cp2@1
                    close
                """

                t7cp2_2 = """
                    open t7cp2@2
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=t7cp3
                    close
                """

                t7cp3_1 = """
                    open t7cp3@1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t7cp1_1)
                self.pkgsend_bulk(durl, t7cp2_1)
                self.image_create(durl)

                self.pkg("install t7cp1")

                self.pkgsend_bulk(durl, t7cp2_2)
                self.pkgsend_bulk(durl, t7cp3_1)

                self.pkg("refresh")
                self.pkg("image-update")

                self.pkg("list t7cp2 | grep -- --r--")
                self.pkg("list t7cp3")

        def test_basic_6a(self):
                """Upgrade a package to a version with a dependency on an
                obsolete package.  This version is unlikely to happen in real
                life."""

                t6ap1_1 = """
                    open t6ap1@1
                    close
                """

                t6ap1_2 = """
                    open t6ap1@2
                    add depend type=require fmri=t6ap2
                    close
                """

                t6ap2_1 = """
                    open t6ap2@1
                    add set name=pkg.obsolete value=true
                    close
                """


                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t6ap1_1)
                self.image_create(durl)

                self.pkg("install t6ap1")

                self.pkgsend_bulk(durl, t6ap1_2)
                self.pkgsend_bulk(durl, t6ap2_1)

                self.pkg("refresh")
                self.pkg("image-update", exit=4) # does nothing
                self.pkg("list t6ap1")

        def test_basic_6b(self):
                """Install a package with a dependency, and image-update after
                publishing updated packages for both, but where the dependency
                has become obsolete."""

                t6ap1_1 = """
                    open t6ap1@1
                    add depend type=require fmri=t6ap2
                    close
                """

                t6ap1_2 = """
                    open t6ap1@2
                    add depend type=require fmri=t6ap2
                    close
                """

                t6ap2_1 = """
                    open t6ap2@1
                    close
                """

                t6ap2_2 = """
                    open t6ap2@2
                    add set name=pkg.obsolete value=true
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t6ap1_1)
                self.pkgsend_bulk(durl, t6ap2_1)
                self.image_create(durl)

                self.pkg("install t6ap1")
                self.pkg("list")

                self.pkgsend_bulk(durl, t6ap1_2)
                self.pkgsend_bulk(durl, t6ap2_2)

                self.pkg("refresh")
                self.pkg("image-update")
                self.pkg("list t6ap1@2 t6ap2@1")

        def test_basic_8a(self):
                """Upgrade a package to an obsolete leaf version when another
                depends on it."""

                t8ap1_1 = """
                    open t8ap1@1
                    close
                """

                t8ap1_2 = """
                    open t8ap1@2
                    add set name=pkg.obsolete value=true
                    close
                """

                t8ap2_1 = """
                    open t8ap2@1
                    add depend type=require fmri=t8ap1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t8ap1_1)
                self.pkgsend_bulk(durl, t8ap2_1)
                self.image_create(durl)

                self.pkg("install t8ap2")

                self.pkgsend_bulk(durl, t8ap1_2)

                self.pkg("refresh")
                self.pkg("image-update", exit=4) # does nothing
                self.pkg("list  t8ap2@1")

        def test_basic_13a(self):
                """Publish an package with a dependency, then publish both as
                obsolete, image-update, and see that both packages have gotten
                removed."""

                t13ap1_1 = """
                    open t13ap1@1
                    add depend type=require fmri=t13ap2
                    close
                """

                t13ap1_2 = """
                    open t13ap1@2
                    add set name=pkg.obsolete value=true
                    close
                """

                t13ap2_1 = """
                    open t13ap2@1
                    close
                """

                t13ap2_2 = """
                    open t13ap2@2
                    add set name=pkg.obsolete value=true
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t13ap1_1)
                self.pkgsend_bulk(durl, t13ap2_1)
                self.image_create(durl)

                self.pkg("install t13ap1")

                self.pkgsend_bulk(durl, t13ap1_2)
                self.pkgsend_bulk(durl, t13ap2_2)

                self.pkg("refresh")
                self.pkg("image-update")
                self.pkg("list", exit=1)

        def test_basic_11(self):
                """Install a package with an ambiguous name, where only one
                match is non-obsolete."""

                t11p1 = """
                    open netbeans@1
                    add set name=pkg.obsolete value=true
                    close
                """

                t11p2 = """
                    open developer/netbeans@1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t11p1)
                self.pkgsend_bulk(durl, t11p2)
                self.image_create(durl)

                self.pkg("install netbeans")
                self.pkg("list pkg:/developer/netbeans")
                self.pkg("list pkg:/netbeans", exit=1)

        def test_basic_11a(self):
                """Install a package using an ambiguous name where
                pkg is renamed to another package, but not the
                conflicting one"""

                t11p1 = """
                    open netbonze@1
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=SUNWnetbonze
                    close
                """

                t11p2 = """
                    open developer/netbonze@1
                    close
                """

                t11p3 = """
                    open SUNWnetbonze@1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t11p1)
                self.pkgsend_bulk(durl, t11p2)
                self.pkgsend_bulk(durl, t11p3)
                self.image_create(durl)

                self.pkg("install netbonze", exit=1)

        def test_basic_11b(self):
                """Install a package using an ambiguous name where only one
                match is non-renamed, and the renamed match is renamed to the
                other."""

                t11p1 = """
                    open netbooze@1
                    close
                """

                t11p2 = """
                    open netbooze@2
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=developer/netbooze
                    close
                """

                t11p3 = """
                    open developer/netbooze@2
                    close
                """

                t11p4 = """
                    open developer/netbooze@3
                    add depend type=require fmri=developer/missing
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t11p1)
                self.pkgsend_bulk(durl, t11p2)
                self.pkgsend_bulk(durl, t11p3)
                self.pkgsend_bulk(durl, t11p4)
                self.image_create(durl)

                self.pkg("install netbooze")
                self.pkg("list pkg:/developer/netbooze")
                self.pkg("list pkg:/netbooze")


        def test_basic_12(self):
                """Upgrade a package across a rename to an ambiguous name."""

                t12p1_1 = """
                    open netbeenz@1
                    close
                """

                t12p1_2 = """
                    open netbeenz@2
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=pkg:/developer/netbeenz
                    close
                """

                t12p2_1 = """
                    open developer/netbeenz@1
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, t12p1_1)
                self.image_create(durl)

                self.pkg("install netbeenz")

                self.pkgsend_bulk(durl, t12p1_2)
                self.pkgsend_bulk(durl, t12p2_1)

                self.pkg("refresh")
                self.pkg("image-update -v")
                self.pkg("list pkg:/developer/netbeenz | grep -- -----")
                self.pkg("list pkg:/netbeenz | grep -- --r--")

        def test_remove_renamed(self):
                """If a renamed package has nothing depending on it, it should
                be removed."""

                p1_1 = """
                    open remrenA@1
                    close
                """

                p1_2 = """
                    open remrenA@2
                    add set name=pkg.renamed value=true
                    add depend type=require fmri=pkg:/remrenB
                    close
                """

                p2_1 = """
                    open remrenB@1
                    close
                """

                p3_1 = """
                    open remrenC@1
                    add depend type=require fmri=pkg:/remrenA
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, p1_1)
                self.image_create(durl)

                self.pkg("install remrenA")

                self.pkgsend_bulk(durl, p1_2)
                self.pkgsend_bulk(durl, p2_1)
                self.pkgsend_bulk(durl, p3_1)

                self.pkg("refresh")
                self.pkg("image-update")
                self.pkg("list remrenA", exit=1)

                # But if there is something depending on the renamed package, it
                # can't be removed.
                self.pkg("pkg uninstall remrenB")

                self.pkg("install remrenA@1 remrenC")
                self.pkg("image-update")
                self.pkg("list remrenA")

        def test_incorp_1(self):
                """We should be able to incorporate an obsolete package."""

                p1_1 = """
                    open inc1p1@1
                    add depend type=incorporate fmri=inc1p2@1
                    close
                """

                p2_1 = """
                    open inc1p2@1
                    add set name=pkg.obsolete value=true
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, p1_1)
                self.pkgsend_bulk(durl, p2_1)
                self.image_create(durl)

                self.pkg("install inc1p1")
                self.pkg("install inc1p2", exit=4)

                self.pkg("list inc1p2", exit=1)

        def test_incorp_2(self):
                """We should be able to continue incorporating a package when it
                becomes obsolete on upgrade."""

                p1_1 = """
                    open inc2p1@1
                    add depend type=incorporate fmri=inc2p2@1
                    close
                """

                p1_2 = """
                    open inc2p1@2
                    add depend type=incorporate fmri=inc2p2@2
                    close
                """

                p2_1 = """
                    open inc2p2@1
                    close
                """

                p2_2 = """
                    open inc2p2@2
                    add set name=pkg.obsolete value=true
                    close
                """

                durl = self.dc.get_depot_url()
                self.pkgsend_bulk(durl, p1_1)
                self.pkgsend_bulk(durl, p2_1)
                self.image_create(durl)

                self.pkg("install inc2p1 inc2p2")

                self.pkgsend_bulk(durl, p1_2)
                self.pkgsend_bulk(durl, p2_2)

                self.pkg("refresh")
                self.pkg("list -afv")
                self.pkg("image-update -v")
                self.pkg("list inc2p2", exit=1)


class TestPkgInstallMultiObsolete(testutils.ManyDepotTestCase):
        """Tests involving obsolete packages and multiple publishers."""

        obs = """
            open stem@1
            add set name=pkg.obsolete value=true
            close
        """

        nonobs = """
            open stem@1
            close
        """

        persistent_depot = True

        def setUp(self):
                testutils.ManyDepotTestCase.setUp(self, ["test1", "test2"])

        def test_01(self):
                """If an obsolete package is found in a preferred publisher and
                a non-obsolete package of the same name is found in a
                non-preferred publisher, pick the preferred pub as usual """

                durl1 = self.dcs[1].get_depot_url()
                durl2 = self.dcs[2].get_depot_url()

                self.pkgsend_bulk(durl1, self.obs)
                self.pkgsend_bulk(durl2, self.nonobs)

                self.image_create(durl1, prefix="test1")
                self.pkg("set-publisher -O " + durl2 + " test2")
                self.pkg("list -a")

                self.pkg("install stem", exit=4) # noting to do since it's obs
                # We should choose the obsolete package, which means nothing
                # gets installed.
                self.pkg("list", exit=1)

        def test_02(self):
                """Same as test_01, but now we have ambiguity in the package
                names.  While at first blush we might follow the same rule as in
                test_01 (choose the preferred publisher), in this case, we can't
                figure out which package from the preferred publisher we want,
                so the choice already isn't as straightforward, so we choose the
                non-obsolete package."""

                lobs = """
                    open some/stem@1
                    add set name=pkg.obsolete value=true
                    close
                """

                durl1 = self.dcs[1].get_depot_url()
                durl2 = self.dcs[2].get_depot_url()

                self.pkgsend_bulk(durl1, self.obs + lobs)
                self.pkgsend_bulk(durl2, self.nonobs + lobs)

                self.image_create(durl1, prefix="test1")
                self.pkg("set-publisher -O " + durl2 + " test2")

                self.pkg("install stem", exit=1)


if __name__ == "__main__":
        unittest.main()