testutils.py revision 430
#
# 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
# 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 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
import unittest
import os
import sys
import subprocess
import shutil
import errno
import platform
import tempfile
# Set the path so that modules above can be found
import pkg5unittest
g_proto_area=""
""" Set up environment for doing testing.
We set PYTHONPATH and PATH so that they reference the proto
area, and clear packaging related environment variables
(every variable prefixed with PKG_).
path_to_proto should be a relative path indicating a path
to proto area of the workspace. So, if your test case is
"../../../proto"
This function looks at argv[0] to compute the ultimate
path to the proto area; this is nice because you can then
invoke test cases like normal commands; i.e.:
"python cli/t_my_test_case.py" will just work.
"""
global g_proto_area
proc = 'unknown'
if osname == 'sunos':
elif osname == 'linux':
elif osname == 'windows':
elif osname == 'darwin':
else:
print "Unable to determine appropriate proto area location."
print "This is a porting problem."
# Figure out from where we're invoking the command
else:
# Clean up relative ../../, etc. out of path to proto
print "NOTE: Adding %s to PYTHONPATH" % pkgs
#
# Because subprocesses must also source from the proto area,
# we need to set PYTHONPATH in the environment as well as
# in sys.path.
#
else:
pypath = ""
print "NOTE: Adding '%s' to head of PATH" % bins
# Use "keys"; otherwise we'll change dictionary size during iteration.
if k.startswith("PKG_"):
print "NOTE: Clearing '%s' from environment" % k
topdivider = \
",---------------------------------------------------------------------\n"
botdivider = \
"`---------------------------------------------------------------------\n"
def format_comment(comment):
if comment is not None:
comm = ""
if line == "":
continue
return comm + "\n"
else:
return "<no comment>\n\n"
str = " Output Follows:\n"
str += topdivider
if command is not None:
str += "| <no output>\n"
else:
str += botdivider
return str
def format_debug(output):
str = " Debug Buffer Follows:\n"
str += topdivider
str += "| <no debug buffer>\n"
else:
str += botdivider
return str
class DepotTracebackException(Exception):
str = "During this test, a depot Traceback was detected.\n"
str += "Log file output is:\n"
return str
class TracebackException(Exception):
debug = None):
str = ""
return str
class UnexpectedExitCodeException(Exception):
str = ""
str += " Expected exit status: %d. Got: %d." % \
return str
class PkgSendOpenException(Exception):
else:
def get_img_path(self):
def get_test_prefix(self):
return self.__test_prefix
self.__debug_buf += s
if not s.endswith("\n"):
if retcode != 0:
def get_debugbuf(self):
return self.__debug_buf
cmdline = "pkg image-create -F -a %s=%s %s" % \
if retcode == 99:
if retcode != 0:
return retcode
def image_destroy(self):
if retcode == 99:
return retcode
comment = ""):
if retcode == 99:
if out:
return retcode
# XXX may need to be smarter.
if retcode == 0:
assert arr
# retcode != 0 will be handled below
else:
if retcode == 99:
return retcode
""" Send a series of packaging commands; useful for
quickly doing a bulk-load of stuff into the repo.
We expect that the commands will all work; if not,
the transaction is abandoned. """
try:
if line == "":
continue
except (TracebackException, UnexpectedExitCodeException):
raise
""" Convenience routine to help subclasses start
depots. Returns a depotcontroller. """
# Note that this must be deferred until after PYTHONPATH
# is set up.
return dc
class ManyDepotTestCase(CliTestCase):
# Note that this must be deferred until after PYTHONPATH
# is set up.
"depot_contents%d" % i)
try:
except OSError, e:
raise e
# We pick an arbitrary base port. This could be more
# automated in the future.
"depot_logfile%d" % i)
""" Scan logpath looking for tracebacks.
Raise a DepotTracebackException if one is seen.
"""
def restart_depots(self):
try:
finally:
class SingleDepotTestCase(ManyDepotTestCase):
# Note that this must be deferred until after PYTHONPATH
# is set up.
""" A class which allows manipulation of the image directory that
SingleDepotTestCase creates. Specifically, it supports removing one
or more of the files or subdirectories inside an image (catalog,
cfg_cache, etc...) in a controlled way.
To add a new directory or file to be corrupted, it will be necessary
to update corrupt_image_create to recognize a new option in config
and perform the appropriate action (removing the directory or file
for example).
"""
self.backup_img_path = None
def __uncorrupt_img_path(self):
""" Function which restores the img_path back to the original
level. """
if self.backup_img_path:
else:
raise RuntimeError("Uncorrupting a image path that "
"was never corrupted.\n")
""" Creates two levels of directories under the original image
directory. In the first level (called bad), it builds a "corrupt
image" which means it builds subdirectories the subdirectories
speicified by subdirs (essentially determining whether a user
image or a full image will be built). It populates these
subdirectories with a partial image directory stucture as
speicified by config. As another subdirectory of bad, it
creates a subdirectory called final which represents the
directory the command was actually run from (which is why
img_path is set to that location). Exisintg image destruction
was made optional to allow testing of two images installed next
to each other (a user and full image created in the same
directory for example). """
if not self.backup_img_path:
if destroy:
for s in subdirs:
cmdline = "pkg image-create -F -a %s=%s %s" % \
elif s == ".org.opensolaris,pkg":
cmdline = "pkg image-create -U -a %s=%s %s" % \
else:
raise RuntimeError("Got unknown subdir option:"
"%s\n" % s)
# Run the command to actually create a good image
if retcode == 99:
if retcode != 0:
# This is where the actual corruption of the
# image takes place. A normal image was created
# above and this goes in and removes critical
# directories and files.
if "catalog_absent" in config or \
"catalog_empty" in config:
if "catalog_empty" in config:
if "cfg_cache_absent" in config:
if "file_absent" in config:
if "pkg_absent" in config:
if "index_absent" in config:
# Make find root start at final. (See the doc string for
# more explanation.)
if __name__ == "__main__":