1968N/A#!/usr/bin/python
1968N/A# -*- coding: utf-8 -*-
1968N/A#
1968N/A# CDDL HEADER START
1968N/A#
1968N/A# The contents of this file are subject to the terms of the
1968N/A# Common Development and Distribution License (the "License").
1968N/A# You may not use this file except in compliance with the License.
1968N/A#
1968N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1968N/A# or http://www.opensolaris.org/os/licensing.
1968N/A# See the License for the specific language governing permissions
1968N/A# and limitations under the License.
1968N/A#
1968N/A# When distributing Covered Code, include this CDDL HEADER in each
1968N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1968N/A# If applicable, add the following below this CDDL HEADER, with the
1968N/A# fields enclosed by brackets "[]" replaced with your own identifying
1968N/A# information: Portions Copyright [yyyy] [name of copyright owner]
1968N/A#
1968N/A# CDDL HEADER END
1968N/A#
1968N/A
1968N/A#
3339N/A# Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
1968N/A#
1968N/A
3339N/Afrom . import testutils
1968N/Aif __name__ == "__main__":
1968N/A testutils.setup_environment("../../../proto")
1968N/Aimport pkg5unittest
1968N/A
1968N/Aimport copy
1968N/Aimport os
1968N/Aimport pwd
2097N/Aimport re
1968N/Aimport shutil
1968N/Aimport signal
3234N/Aimport six
1968N/Aimport stat
1968N/Aimport tempfile
1968N/Aimport time
1968N/Aimport unittest
1968N/A
1968N/Afrom pkg import misc, portable
1968N/Aimport pkg.config as cfg
1968N/Aimport pkg.portable as portable
1968N/A
1968N/A# The Thai word for package.
1968N/ATH_PACKAGE = u'บรรจุภัณฑ์'
1968N/A
1968N/A
1968N/Aclass TestProperty(pkg5unittest.Pkg5TestCase):
1968N/A """Class to test the functionality of the pkg.config Property classes.
1968N/A """
1968N/A
1968N/A def __verify_init(self, propcls, propname, glist, blist):
1968N/A # 'glist' contains the list of good values to try.
1968N/A for defval, expval in glist:
1968N/A # Check init.
1968N/A p = propcls(propname, default=defval)
1968N/A self.assertEqual(p.value, expval)
1968N/A
1968N/A # Check set.
1968N/A p = propcls(propname)
1968N/A p.value = defval
1968N/A self.assertEqual(p.value, expval)
1968N/A
1968N/A # 'blist' contains the list of bad values to try.
1968N/A for badval in blist:
1968N/A # Check init.
1968N/A self.assertRaises(cfg.InvalidPropertyValueError,
1968N/A propcls, propname, default=badval)
1968N/A
1968N/A # Check set.
1968N/A p = cfg.PropBool(propname)
1968N/A self.assertRaises(cfg.InvalidPropertyValueError,
1968N/A setattr, p, "value", badval)
1968N/A
1968N/A def __verify_equality(self, propcls, eqlist, nelist):
1968N/A # Check eq.
1968N/A for entry in eqlist:
1968N/A (p1name, p1def), (p2name, p2def) = entry
1968N/A p1 = propcls(p1name, default=p1def)
1968N/A p2 = propcls(p2name, default=p2def)
1968N/A # This ensures that both __eq__ and __ne__ are tested
1968N/A # properly.
1968N/A self.assertTrue(p1 == p2)
1968N/A self.assertFalse(p1 != p2)
1968N/A
1968N/A # Check ne.
1968N/A for entry in nelist:
1968N/A (p1name, p1def), (p2name, p2def) = entry
1968N/A p1 = propcls(p1name, default=p1def)
1968N/A p2 = propcls(p2name, default=p2def)
1968N/A # This ensures that both __eq__ and __ne__ are tested
1968N/A # properly.
1968N/A self.assertTrue(p1 != p2)
1968N/A self.assertFalse(p1 == p2)
1968N/A
1968N/A def __verify_stringify(self, propcls, propname, explist, debug=False):
1968N/A for val, expstr in explist:
1968N/A # Verify that the stringified form of the property's
1968N/A # value matches what is expected.
1968N/A p1 = propcls(propname, default=val)
3234N/A self.assertEqual(six.text_type(p1), expstr)
3339N/A if six.PY2:
3339N/A self.assertEqual(str(p1), expstr.encode("utf-8"))
3339N/A else:
3339N/A # str() call in Python 3 must return str (unicode).
3339N/A self.assertEqual(str(p1), expstr)
1968N/A
1968N/A # Verify that a property value's stringified form
1968N/A # provides can be parsed into an exact equivalent
1968N/A # in native form (e.g. list -> string -> list).
1968N/A p2 = propcls(propname)
3234N/A p2.value = six.text_type(p1)
1968N/A self.assertEqual(p1.value, p2.value)
1968N/A self.assertEqualDiff(str(p1), str(p2))
1968N/A
1968N/A p2.value = str(p1)
1968N/A self.assertEqual(p1.value, p2.value)
1968N/A self.assertEqualDiff(str(p1), str(p2))
1968N/A
2097N/A def __verify_ex_stringify(self, ex):
2097N/A encs = str(ex)
2097N/A self.assertNotEqual(len(encs), 0)
3234N/A unis = six.text_type(ex)
2097N/A self.assertNotEqual(len(unis), 0)
3339N/A if six.PY2:
3339N/A self.assertEqualDiff(encs, unis.encode("utf-8"))
3339N/A else:
3339N/A self.assertEqualDiff(encs, unis)
2097N/A
1968N/A def test_base(self):
1968N/A """Verify base property functionality works as expected."""
1968N/A
1968N/A propcls = cfg.Property
1968N/A
1968N/A # Verify invalid names aren't permitted.
1968N/A for n in ("contains\na new line", "contains\ttab",
1968N/A "contains/slash", "contains\rcarriage return",
1968N/A "contains\fform feed", "contains\vvertical tab",
1968N/A "contains\\backslash", "", TH_PACKAGE):
1968N/A self.assertRaises(cfg.InvalidPropertyNameError,
1968N/A propcls, n)
1968N/A
1968N/A # Verify spaces are permitted.
1968N/A propcls("has space")
1968N/A
1968N/A # Verify property objects are sorted by name and that other
1968N/A # objects are sorted after.
1968N/A plist = [propcls(n) for n in ("c", "d", "a", "b")]
1968N/A plist.extend(["g", "e", "f"])
1968N/A plist.sort()
1968N/A self.assertEqual(
1968N/A [getattr(p, "name", p) for p in plist],
1968N/A ["a", "b", "c", "d", "e", "f", "g"]
1968N/A )
1968N/A
1968N/A # Verify equality is always False when comparing a property
1968N/A # object to a different object and that objects that are not
1968N/A # properties don't cause a traceback.
1968N/A p1 = propcls("property")
1968N/A self.assertFalse(p1 == "property")
1968N/A self.assertTrue(p1 != "property")
1968N/A self.assertFalse(p1 == None)
1968N/A self.assertTrue(p1 != None)
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, ""), ("", ""), ("foo", "foo"), (123, "123"),
1968N/A (False, "False"), (TH_PACKAGE, TH_PACKAGE)]
1968N/A blist = [
1968N/A [], #
1968N/A {}, # Expect strings; not objects.
1968N/A object(), #
1968N/A ]
1968N/A self.__verify_init(propcls, "def", glist, blist)
1968N/A
1968N/A glist = [
1968N/A (None, ""), # None should become "".
1968N/A ("", ""), # "" should equal "".
1968N/A ("foo", "foo"), # simple strings should match.
1968N/A (123, "123"), # int should become str.
1968N/A (False, "False"), # boolean should become str.
1968N/A (TH_PACKAGE, TH_PACKAGE), # UTF-8 data.
1968N/A ("\xfe", "\xfe") # Passthrough of 8-bit data.
1968N/A # (That is not valid UTF-8.)
1968N/A ]
1968N/A blist = [
1968N/A [], #
1968N/A {}, # Other data types or objects not expected.
1968N/A object() #
1968N/A ]
1968N/A self.__verify_init(propcls, "def", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("def", ""), ("def", None)),
1968N/A (("def", "bob cat"), ("def", "bob cat")),
1968N/A (("def", TH_PACKAGE), ("def", TH_PACKAGE)),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("def", "bob cat"), ("str2", "bob cat")),
1968N/A (("def", "lynx"), ("str2", "bob cat")),
1968N/A (("def", u'ซ'), ("str2", TH_PACKAGE)),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A
1968N/A # Verify base stringify works as expected.
1968N/A self.__verify_stringify(propcls, "property", [(None, ""),
1968N/A ("", ""), (TH_PACKAGE, TH_PACKAGE)])
1968N/A
1968N/A # Verify base copy works as expected.
1968N/A p1 = propcls("p1", "v1")
1968N/A p2 = copy.copy(p1)
1968N/A self.assertEqual(p1.name, p2.name)
1968N/A self.assertEqual(p1.value, p2.value)
1968N/A self.assertNotEqual(id(p1), id(p2))
1968N/A
1968N/A def test_bool(self):
1968N/A """Verify boolean properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropBool
1968N/A p = propcls("bool")
1968N/A self.assertEqual(p.value, False)
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, False), ("", False), (False, False),
1968N/A ("False", False), ("True", True)]
1968N/A blist = [("bogus", 123, "-true-", "\n")]
1968N/A self.__verify_init(propcls, "bool", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("bool", True), ("bool", True)),
1968N/A (("bool", "True"), ("bool", True)),
1968N/A (("bool", "true"), ("bool", True)),
1968N/A (("bool", "TrUE"), ("bool", True)),
1968N/A (("bool", False), ("bool", False)),
1968N/A (("bool", "False"), ("bool", False)),
1968N/A (("bool", "false"), ("bool", False)),
1968N/A (("bool", "FaLsE"), ("bool", False)),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("bool", True), ("bool2", True)),
1968N/A (("bool", True), ("bool", False)),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "bool", [(True, "True"),
1968N/A (False, "False")])
1968N/A
1968N/A def test_defined(self):
1968N/A """Verify defined properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropDefined
1968N/A p = propcls("def")
1968N/A self.assertEqual(p.value, "")
1968N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "def", [("", ""),
1968N/A ("bob cat", "bob cat"), (TH_PACKAGE, TH_PACKAGE)])
1968N/A
1968N/A # Verify allowed value functionality permits expected values.
1968N/A p = propcls("def", allowed=["", "<pathname>", "<exec:pathname>",
1968N/A "<smffmri>"])
1968N/A for v in ("/abs/path", "exec:/my/binary",
1968N/A "svc:/application/pkg/server:default", ""):
1968N/A p.value = v
1968N/A
1968N/A # Verify allowed value functionality denies unexpected values.
1968N/A p = propcls("def", allowed=["<abspathname>"],
1968N/A default="/abs/path")
1968N/A for v in ("not/abs/path", "../also/not/not/abs", ""):
3158N/A self.debug("p: {0}".format(v))
1968N/A self.assertRaises(cfg.InvalidPropertyValueError,
1968N/A setattr, p, "value", v)
1968N/A
1968N/A def test_int(self):
1968N/A """Verify integer properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropInt
1968N/A p = propcls("int")
1968N/A self.assertEqual(p.value, 0)
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, 0), ("", 0), (1, 1),
1968N/A ("16384", 16384)]
1968N/A blist = [("bogus", "-true-", "\n")]
1968N/A self.__verify_init(propcls, "int", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("int", 0), ("int", 0)),
1968N/A (("int", "16384"), ("int", 16384)),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("int", 256), ("int2", 256)),
1968N/A (("int", 0), ("int", 256)),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
2348N/A # Verify minimum works as expected.
2348N/A p = propcls("int", minimum=-1)
2348N/A self.assertEqual(p.minimum, -1)
2348N/A self.assertRaises(cfg.InvalidPropertyValueError,
2348N/A setattr, p, "value", -100)
2348N/A p.value = 4294967295
2348N/A self.assertEqual(p.value, 4294967295)
2348N/A
2348N/A # Verify maximum works as expected.
2348N/A p = propcls("int", maximum=65535)
2348N/A self.assertEqual(p.maximum, 65535)
2348N/A self.assertRaises(cfg.InvalidPropertyValueError,
2348N/A setattr, p, "value", 42944967295)
2348N/A p.value = 65535
2348N/A self.assertEqual(p.value, 65535)
2348N/A
2348N/A # Verify maximum and minimum work together.
2348N/A p = propcls("int", maximum=1, minimum=-1)
2348N/A self.assertRaises(cfg.InvalidPropertyValueError,
2348N/A setattr, p, "value", -2)
2348N/A self.assertRaises(cfg.InvalidPropertyValueError,
2348N/A setattr, p, "value", 2)
2348N/A
2348N/A # Verify maximum and minimum are copied when object is.
2348N/A np = copy.copy(p)
2348N/A self.assertEqual(np.maximum, 1)
2348N/A self.assertEqual(np.minimum, -1)
2348N/A self.assertRaises(cfg.InvalidPropertyValueError,
2348N/A setattr, np, "value", -2)
2348N/A self.assertRaises(cfg.InvalidPropertyValueError,
2348N/A setattr, np, "value", 2)
2348N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "int", [(0, "0"),
1968N/A (4294967296, "4294967296")])
1968N/A
1968N/A def test_exceptions(self):
1968N/A """Verify that exception classes can be initialized as expected,
1968N/A and when stringified return a non-zero-length string.
1968N/A """
1968N/A
1968N/A # Verify the expected behavior of all ConfigError classes.
1968N/A for excls in (cfg.PropertyConfigError,
2097N/A cfg.PropertyMultiValueError,
2097N/A cfg.InvalidPropertyValueError, cfg.UnknownPropertyError,
2097N/A cfg.UnknownPropertyValueError, cfg.UnknownSectionError):
1968N/A # Verify that exception can't be created without
1968N/A # specifying section or property.
1968N/A self.assertRaises(AssertionError, excls)
1968N/A
1968N/A # Verify that exception can be created with just
1968N/A # section or property, or both, and that expected
1968N/A # value is set. In addition, verify that the
2097N/A # stringified form or unicode object is equal
1968N/A # and not zero-length.
1968N/A ex1 = excls(section="section")
1968N/A self.assertEqual(ex1.section, "section")
1968N/A
1968N/A ex2 = excls(prop="property")
1968N/A self.assertEqual(ex2.prop, "property")
1968N/A
1968N/A ex3 = excls(section="section", prop="property")
1968N/A self.assertEqual(ex3.section, "section")
1968N/A self.assertEqual(ex3.prop, "property")
1968N/A
1968N/A if excls == cfg.PropertyConfigError:
1968N/A # Can't stringify base class.
1968N/A continue
3339N/A list(map(self.__verify_ex_stringify, (ex1, ex2, ex3)))
1968N/A
2097N/A if excls != cfg.UnknownPropertyValueError:
2097N/A continue
2097N/A
2097N/A ex4 = excls(section="section", prop="property",
2097N/A value="value")
2097N/A self.assertEqual(ex4.section, "section")
2097N/A self.assertEqual(ex4.prop, "property")
2097N/A self.assertEqual(ex4.value, "value")
2097N/A self.__verify_ex_stringify(ex4)
2097N/A
2097N/A for excls in (cfg.InvalidSectionNameError,
2097N/A cfg.InvalidSectionTemplateNameError):
2097N/A # Verify that exception can't be created without
2097N/A # specifying section.
2097N/A self.assertRaises(AssertionError, excls, None)
2097N/A
2097N/A # Verify that exception can be created with just section
2097N/A # and that expected value is set. In addition, verify
2097N/A # that the stringified form or unicode object is equal
2097N/A # and not zero-length.
2097N/A ex1 = excls("section")
2097N/A self.assertEqual(ex1.section, "section")
2097N/A self.__verify_ex_stringify(ex1)
2097N/A
2097N/A for excls in (cfg.InvalidPropertyNameError,
2097N/A cfg.InvalidPropertyTemplateNameError):
2097N/A # Verify that exception can't be created without
2097N/A # specifying prop.
2097N/A self.assertRaises(AssertionError, excls, None)
2097N/A
2097N/A # Verify that exception can be created with just prop
2097N/A # and that expected value is set. In addition, verify
2097N/A # that the stringified form or unicode object is equal
2097N/A # and not zero-length.
2097N/A ex1 = excls("prop")
2097N/A self.assertEqual(ex1.prop, "prop")
2097N/A self.__verify_ex_stringify(ex1)
1968N/A
1968N/A def test_list(self):
1968N/A """Verify list properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropList
1968N/A p = propcls("list")
1968N/A self.assertEqual(p.value, [])
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [
1968N/A ([1, 2, None], ["1", "2", ""]),
1968N/A ([TH_PACKAGE, "bob cat", "profit"], [TH_PACKAGE, "bob cat",
1968N/A "profit"]),
1968N/A ([1, "???", "profit"], ["1", "???", "profit"]),
1968N/A ([False, True, "false"], ["False", "True", "false"]),
1968N/A ([TH_PACKAGE, "profit"], [TH_PACKAGE, "profit"]),
1968N/A (["\xfe", "bob cat"], ["\xfe", "bob cat"]),
1968N/A ]
1968N/A blist = [[[]], [{}], [object()], '[__import__("sys").exit(-1)]',
1968N/A '{}', 123]
1968N/A self.__verify_init(propcls, "list", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("list", [None]), ("list", [""])),
1968N/A (("list", ["box", "cat"]), ("list", ["box", "cat"])),
1968N/A (("list", [TH_PACKAGE, "profit"]),
1968N/A ("list", [TH_PACKAGE, "profit"])),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("list", ["bob cat"]), ("list2", ["bob cat"])),
1968N/A (("list", ["lynx"]), ("list2", ["bob cat"])),
1968N/A (("list", [TH_PACKAGE]),
1968N/A ("list", [TH_PACKAGE, "profit"])),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form and that stringified form can be used
1968N/A # to set value.
3339N/A if six.PY2:
3339N/A self.__verify_stringify(propcls, "list", [
3339N/A ([""], "['']"),
3339N/A (["box", "cat"], "['box', 'cat']"),
3339N/A # List literal form uses unicode_escape.
3339N/A ([TH_PACKAGE, "profit"],
3339N/A u"[u'{0}', 'profit']".format(
3339N/A TH_PACKAGE.encode("unicode_escape"))),
3339N/A (["\xfe", "bob cat"], "['\\xfe', 'bob cat']"),
3339N/A ])
3339N/A else:
3339N/A # unicode representation in Python 3 is not using
3339N/A # escape sequence
3339N/A self.__verify_stringify(propcls, "list", [
3339N/A ([""], "['']"),
3339N/A (["box", "cat"], "['box', 'cat']"),
3339N/A ([TH_PACKAGE, "profit"],
3339N/A "['{0}', 'profit']".format(
3339N/A TH_PACKAGE)),
3339N/A (["þ", "bob cat"], "['þ', 'bob cat']"),
3339N/A ])
1968N/A
1968N/A # Verify allowed value functionality permits expected values.
1968N/A p = propcls("list", allowed=["", "<pathname>",
1968N/A "<exec:pathname>", "<smffmri>"])
1968N/A p.value = ["/abs/path", "exec:/my/binary",
1968N/A "svc:/application/pkg/server:default", ""]
1968N/A
1968N/A # Verify allowed value functionality denies unexpected values.
1968N/A p = propcls("list", allowed=["<pathname>"],
2152N/A default=["/export/repo"])
1968N/A self.assertRaises(cfg.InvalidPropertyValueError,
1968N/A setattr, p, "value", ["exec:/binary", "svc:/application",
1968N/A ""])
1968N/A self.assertRaises(cfg.InvalidPropertyValueError,
1968N/A setattr, p, "value", [])
1968N/A
1968N/A # Verify that any iterable can be used to assign the property's
1968N/A # value and the result will still be a list.
1968N/A p = propcls("list")
1968N/A expected = ["bob cat", "lynx", "tiger"]
1968N/A
1968N/A # List.
1968N/A p.value = ["bob cat", "lynx", "tiger"]
1968N/A self.assertEqual(p.value, expected)
1968N/A
1968N/A # Set.
1968N/A p.value = set(("bob cat", "lynx", "tiger"))
1968N/A self.assertEqual(p.value, list(set(expected)))
1968N/A
1968N/A # Tuple.
1968N/A p.value = ("bob cat", "lynx", "tiger")
1968N/A self.assertEqual(p.value, expected)
1968N/A
1968N/A # Generator.
1968N/A p.value = (v for v in expected)
1968N/A self.assertEqual(p.value, expected)
1968N/A
1968N/A def test_publisher(self):
1968N/A """Verify publisher properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropPublisher
1968N/A p = propcls("pub")
1968N/A self.assertEqual(p.value, "")
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, ""), ("", ""), ("example.com", "example.com"),
1968N/A ("sub.sub.Example.Com", "sub.sub.Example.Com"),
1968N/A ("bob-cat", "bob-cat")]
1968N/A blist = [(".startperiod", "!@&*#$&*(@badchars", "\n", object())]
1968N/A self.__verify_init(propcls, "pub", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("pub", ""), ("pub", None)),
1968N/A (("pub", "bobcat"), ("pub", "bobcat")),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("pub", "bobcat"), ("pub2", "bobcat")),
1968N/A (("pub", "lynx"), ("pub2", "bobcat")),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "int", [("", ""),
1968N/A ("bobcat", "bobcat")])
1968N/A
1968N/A def test_simple_list(self):
1968N/A """Verify simple list properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropSimpleList
1968N/A p = propcls("slist")
1968N/A self.assertEqual(p.value, [])
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [
1968N/A ([1, 2, None], ["1", "2", ""]),
1968N/A ([TH_PACKAGE, "bob cat", "profit"],
1968N/A [TH_PACKAGE, "bob cat", "profit"]),
1968N/A ([1, "???", "profit"], ["1", "???", "profit"]),
1968N/A ([False, True, "false"], ["False", "True", "false"]),
1968N/A ([TH_PACKAGE, "profit"], [TH_PACKAGE, "profit"]),
1968N/A ]
1968N/A blist = [
1968N/A [[]], [{}], [object()], # Objects not expected.
1968N/A 123, # Numbers not expected.
3339N/A [b"\xfe"], # Arbitrary 8-bit data is not
3339N/A b"\xfe", # supported.
1968N/A ]
1968N/A
1968N/A self.__verify_init(propcls, "slist", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("slist", [None]), ("slist", [""])),
1968N/A (("slist", ["box", "cat"]), ("slist", ["box", "cat"])),
1968N/A (("slist", [TH_PACKAGE, "profit"]),
1968N/A ("slist", [TH_PACKAGE, "profit"])),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("slist", ["bob cat"]), ("slist2", ["bob cat"])),
1968N/A (("slist", ["lynx"]), ("slist2", ["bob cat"])),
1968N/A (("slist", [TH_PACKAGE]),
1968N/A ("slist", [TH_PACKAGE, "profit"])),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form (note that a simple list isn't able to
1968N/A # preserve zero-length string values whenever it is the only
1968N/A # value in the list).
1968N/A self.__verify_stringify(propcls, "slist", [
1968N/A (["box", "cat"], "box,cat"),
1968N/A ([TH_PACKAGE, "profit"], u'บรรจุภัณฑ์,profit'),
1968N/A ], debug=True)
1968N/A
1968N/A def test_puburi(self):
1968N/A """Verify publisher URI properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropPubURI
1968N/A p = propcls("uri")
1968N/A self.assertEqual(p.value, "")
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, ""), ("", ""), ("http://example.com/",
1968N/A "http://example.com/"), ("file:/abspath", "file:/abspath")]
1968N/A blist = ["bogus://", {}, object(), 123, "http://@&*#($badchars",
1968N/A "http:/baduri", "example.com", {}, []]
1968N/A self.__verify_init(propcls, "str", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("uri", ""), ("uri", None)),
1968N/A (("uri", "http://example.com"),
1968N/A ("uri", "http://example.com")),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("uri", "http://example.com"),
1968N/A ("uri2", "http://example.com")),
1968N/A (("uri", "http://example.org/"),
1968N/A ("uri", "http://example.net/")),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "uri", [("", ""),
1968N/A ("http://example.com", "http://example.com"),
1968N/A ("http://example.org/", "http://example.org/")])
1968N/A
1968N/A def test_puburi_list(self):
1968N/A """Verify publisher URI list properties work as expected."""
1968N/A
2097N/A propcls = cfg.PropPubURIList
2097N/A
1968N/A # Verify default if no initial value provided.
2097N/A p = propcls("uri_list")
2097N/A self.assertEqual(p.value, [])
2097N/A
2097N/A # Verify that all expected values are accepted at init and
2097N/A # during set and that the value is set as expected. Also
2097N/A # verify that bad values are rejected both during init and
2097N/A # set.
2097N/A glist = [(None, []), ("", []), ("['http://example.com/']",
2097N/A ["http://example.com/"]), (["file:/abspath"],
2097N/A ["file:/abspath"])]
2097N/A blist = [["bogus://"], [{}], [object()], [123],
2097N/A ["http://@&*#($badchars"], ["http:/baduri"],
2097N/A ["example.com"]]
2097N/A self.__verify_init(propcls, "uri_list", glist, blist)
2097N/A
2097N/A # Verify equality works as expected.
2097N/A eqlist = [
2097N/A # Equal because property names and values match.
2097N/A (("uri_list", ""), ("uri_list", [])),
2097N/A (("uri_list", ["http://example.com", "file:/abspath"]),
2097N/A ("uri_list", ["http://example.com", "file:/abspath"])),
2097N/A ]
2097N/A nelist = [
2097N/A # Not equal because property names and/or values do not
2097N/A # match.
2097N/A (("uri_list", ["http://example.com", "file:/abspath"]),
2097N/A ("uri_list2", ["http://example.com", "file:/abspath"])),
2097N/A (("uri_list", ["http://example.com", "file:/abspath"]),
2097N/A ("uri_list", ["http://example.net/"])),
2097N/A ]
2097N/A self.__verify_equality(propcls, eqlist, nelist)
2097N/A
2097N/A # Verify stringified form.
2097N/A self.__verify_stringify(propcls, "uri", [("", "[]"),
2097N/A (["http://example.com", "file:/abspath"],
2097N/A "['http://example.com', 'file:/abspath']"),
2097N/A (["file:/abspath"], "['file:/abspath']")])
2097N/A
2097N/A def test_simple_puburi_list(self):
2097N/A """Verify publisher URI list properties work as expected."""
2097N/A
2097N/A propcls = cfg.PropSimplePubURIList
2097N/A
2097N/A # Verify default if no initial value provided.
1968N/A p = propcls("uri_list")
1968N/A self.assertEqual(p.value, [])
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, []), ("", []), ("http://example.com/",
1968N/A ["http://example.com/"]), (["file:/abspath"],
1968N/A ["file:/abspath"])]
1968N/A blist = [["bogus://"], [{}], [object()], [123],
1968N/A ["http://@&*#($badchars"], ["http:/baduri"],
1968N/A ["example.com"]]
1968N/A self.__verify_init(propcls, "uri_list", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("uri_list", ""), ("uri_list", [])),
1968N/A (("uri_list", ["http://example.com", "file:/abspath"]),
1968N/A ("uri_list", ["http://example.com", "file:/abspath"])),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("uri_list", ["http://example.com", "file:/abspath"]),
1968N/A ("uri_list2", ["http://example.com", "file:/abspath"])),
1968N/A (("uri_list", ["http://example.com", "file:/abspath"]),
1968N/A ("uri_list", ["http://example.net/"])),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "uri", [("", ""),
1968N/A (["http://example.com", "file:/abspath"],
1968N/A "http://example.com,file:/abspath"),
1968N/A (["file:/abspath"], "file:/abspath")])
1968N/A
1968N/A def test_uuid(self):
1968N/A """Verify UUID properties work as expected."""
1968N/A
1968N/A # Verify default if no initial value provided.
1968N/A propcls = cfg.PropUUID
1968N/A p = propcls("uuid")
1968N/A self.assertEqual(p.value, "")
1968N/A
1968N/A # Verify that all expected values are accepted at init and
1968N/A # during set and that the value is set as expected. Also
1968N/A # verify that bad values are rejected both during init and
1968N/A # set.
1968N/A glist = [(None, ""), ("", ""),
1968N/A ("16fd2706-8baf-433b-82eb-8c7fada847da",
1968N/A "16fd2706-8baf-433b-82eb-8c7fada847da")]
1968N/A blist = [[], {}, object(), "16fd2706-8baf-433b-82eb", "123",
1968N/A "badvalue"]
1968N/A self.__verify_init(propcls, "uuid", glist, blist)
1968N/A
1968N/A # Verify equality works as expected.
1968N/A eqlist = [
1968N/A # Equal because property names and values match.
1968N/A (("uuid", ""), ("uuid", None)),
1968N/A (("uuid", "16fd2706-8baf-433b-82eb-8c7fada847da"),
1968N/A ("uuid", "16fd2706-8baf-433b-82eb-8c7fada847da")),
1968N/A ]
1968N/A nelist = [
1968N/A # Not equal because property names and/or values do not
1968N/A # match.
1968N/A (("uuid", ""), ("uuid2", None)),
1968N/A (("uuid", "16fd2706-8baf-433b-82eb-8c7fada847da"),
1968N/A ("uuid", "5a912a99-86dd-cb06-8ff0-b6bdfb74d0f6")),
1968N/A ]
1968N/A self.__verify_equality(propcls, eqlist, nelist)
1968N/A
1968N/A # Verify stringified form.
1968N/A self.__verify_stringify(propcls, "str", [("", ""),
1968N/A ("16fd2706-8baf-433b-82eb-8c7fada847da",
1968N/A "16fd2706-8baf-433b-82eb-8c7fada847da")])
1968N/A
1968N/A
2097N/Aclass TestPropertyTemplate(pkg5unittest.Pkg5TestCase):
2097N/A """Class to test the functionality of the pkg.config PropertyTemplate
2097N/A class.
2097N/A """
2097N/A
2097N/A def test_base(self):
2097N/A """Verify base property template functionality works as
2097N/A expected.
2097N/A """
2097N/A
2097N/A propcls = cfg.PropertyTemplate
2097N/A
2097N/A # Verify invalid names aren't permitted.
2097N/A for n in ("", re.compile("^$"), "foo.*("):
2097N/A self.assertRaises(cfg.InvalidPropertyTemplateNameError,
2097N/A propcls, n)
2097N/A
2097N/A prop = propcls("^facet\..*$")
2097N/A self.assertEqual(prop.name, "^facet\..*$")
2097N/A
2097N/A def test_create_match(self):
2097N/A """Verify that create and match operations work as expected."""
2097N/A
2097N/A proptemp = cfg.PropertyTemplate("^facet\..*$")
2097N/A
2097N/A # Verify match will match patterns as expected.
2097N/A self.assertEqual(proptemp.match("facet.devel"), True)
2097N/A self.assertEqual(proptemp.match("facet"), False)
2097N/A
2097N/A # Verify create raises an assert if name doesn't match
2097N/A # template pattern.
2097N/A self.assertRaises(AssertionError, proptemp.create, "notallowed")
2097N/A
2097N/A # Verify create returns expected property.
2097N/A expected_props = [
2097N/A ({}, { "value": "" }),
2097N/A ({ "prop_type": cfg.Property, "value_map": { "None": None }
2097N/A }, { "value": "" } ),
2097N/A ({ "default": True, "prop_type": cfg.PropBool},
2097N/A { "value": True }),
2097N/A ({ "allowed": ["always", "never"], "default": "never",
2097N/A "prop_type": cfg.PropDefined },
2097N/A { "allowed": ["always", "never"], "value": "never" }),
2097N/A ]
2097N/A for args, exp_attrs in expected_props:
2097N/A proptemp = cfg.PropertyTemplate("name", **args)
2097N/A extype = args.get("prop_type", cfg.Property)
2097N/A
2097N/A prop = proptemp.create("name")
3339N/A self.assertTrue(isinstance(prop, extype))
2097N/A
2097N/A for attr in exp_attrs:
2097N/A self.assertEqual(getattr(prop, attr),
2097N/A exp_attrs[attr])
2097N/A
2097N/A
1968N/Aclass TestPropertySection(pkg5unittest.Pkg5TestCase):
1968N/A """Class to test the functionality of the pkg.config PropertySection
1968N/A classes.
1968N/A """
1968N/A
1968N/A def __verify_stringify(self, cls, explist):
1968N/A for val, expstr in explist:
3234N/A self.assertEqual(six.text_type(cls(val)), expstr)
3339N/A if six.PY2:
3339N/A self.assertEqual(str(cls(val)), expstr.encode(
3339N/A "utf-8"))
3339N/A else:
3339N/A # str() call in Python 3 must return str (unicode).
3339N/A self.assertEqual(str(cls(val)), expstr)
1968N/A
1968N/A def test_base(self):
1968N/A """Verify base section functionality works as expected."""
1968N/A
1968N/A seccls = cfg.PropertySection
1968N/A
1968N/A # Verify invalid names aren't permitted.
1968N/A for n in ("contains\na new line", "contains\ttab",
1968N/A "contains/slash", "contains\rcarriage return",
1968N/A "contains\fform feed", "contains\vvertical tab",
1968N/A "contains\\backslash", "", TH_PACKAGE,
1968N/A "CONFIGURATION"):
1968N/A self.assertRaises(cfg.InvalidSectionNameError,
1968N/A seccls, n)
1968N/A
1968N/A # Verify spaces are permitted.
1968N/A seccls("has space")
1968N/A
1968N/A # Verify section objects are sorted by name and that other
1968N/A # objects are sorted after.
1968N/A slist = [seccls(n) for n in ("c", "d", "a", "b")]
1968N/A slist.extend(["g", "e", "f"])
1968N/A slist.sort()
1968N/A self.assertEqual(
1968N/A [getattr(s, "name", s) for s in slist],
1968N/A ["a", "b", "c", "d", "e", "f", "g"]
1968N/A )
1968N/A
1968N/A # Verify equality is always False when comparing a section
1968N/A # object to a different object and that objects that are not
1968N/A # sections don't cause a traceback.
1968N/A s1 = seccls("section")
1968N/A self.assertFalse(s1 == "section")
1968N/A self.assertTrue(s1 != "section")
1968N/A self.assertFalse(s1 == None)
1968N/A self.assertTrue(s1 != None)
1968N/A
1968N/A # Verify base stringify works as expected.
1968N/A self.__verify_stringify(seccls, [("section", "section")])
1968N/A
1968N/A # Verify base copy works as expected.
1968N/A s1 = seccls("s1")
1968N/A s2 = copy.copy(s1)
1968N/A self.assertEqual(s1.name, s2.name)
1968N/A self.assertNotEqual(id(s1), id(s2))
1968N/A
1968N/A def test_add_get_remove_props(self):
1968N/A """Verify add_property, get_property, get_index, get_properties,
1968N/A and remove_property works as expected.
1968N/A """
1968N/A
1968N/A propcls = cfg.Property
1968N/A sec = cfg.PropertySection("section")
1968N/A
1968N/A # Verify that attempting to retrieve an unknown property
1968N/A # raises an exception.
1968N/A self.assertRaises(cfg.UnknownPropertyError,
1968N/A sec.get_property, "p1")
1968N/A
2097N/A # Verify that attempting to remove an unknown property raises
2097N/A # an exception.
2097N/A self.assertRaises(cfg.UnknownPropertyError,
2097N/A sec.remove_property, "p1")
1968N/A
1968N/A # Verify that a property cannot be added twice.
1968N/A p1 = propcls("p1", default="1")
1968N/A sec.add_property(p1)
1968N/A self.assertRaises(AssertionError, sec.add_property, p1)
1968N/A
1968N/A # Verify that get_properties returns expected value.
1968N/A p2 = propcls("p2", default="2")
1968N/A sec.add_property(p2)
1968N/A p3 = propcls("p3", default="3")
1968N/A sec.add_property(p3)
1968N/A
1968N/A returned = sorted(
1968N/A (p.name, p.value)
1968N/A for p in sec.get_properties()
1968N/A )
1968N/A expected = [("p1", "1"), ("p2", "2"), ("p3", "3")]
1968N/A self.assertEqualDiff(returned, expected)
1968N/A
1968N/A # Verify that get_index returns expected value.
1968N/A exp_idx = {
1968N/A "p1": "1",
1968N/A "p2": "2",
1968N/A "p3": "3",
1968N/A }
1968N/A self.assertEqual(sec.get_index(), exp_idx)
1968N/A
1968N/A
2097N/Aclass TestPropertySectionTemplate(pkg5unittest.Pkg5TestCase):
2097N/A """Class to test the functionality of the pkg.config PropertyTemplate
2097N/A class.
2097N/A """
2097N/A
2097N/A def test_base(self):
2097N/A """Verify base property section template functionality works as
2097N/A expected.
2097N/A """
2097N/A
2097N/A seccls = cfg.PropertySectionTemplate
2097N/A
2097N/A # Verify invalid names aren't permitted.
2097N/A for n in ("", re.compile("^$"), "foo.*("):
2097N/A self.assertRaises(cfg.InvalidSectionTemplateNameError,
2097N/A seccls, n)
2097N/A
2097N/A sec = seccls("^authority_.*$")
2097N/A self.assertEqual(sec.name, "^authority_.*$")
2097N/A
2097N/A def test_create_match(self):
2097N/A """Verify that create and match operations work as expected."""
2097N/A
2097N/A sectemp = cfg.PropertySectionTemplate("^authority_.*$")
2097N/A
2097N/A # Verify match will match patterns as expected.
2097N/A self.assertEqual(sectemp.match("authority_example.com"), True)
2097N/A self.assertEqual(sectemp.match("authority"), False)
2097N/A
2097N/A # Verify create raises an assert if name doesn't match
2097N/A # template pattern.
2097N/A self.assertRaises(AssertionError, sectemp.create, "notallowed")
2097N/A
2097N/A # Verify create returns expected section.
2097N/A exp_props = [
2097N/A cfg.Property("prop"),
2097N/A cfg.PropBool("bool"),
2097N/A cfg.PropList("list"),
2097N/A cfg.PropertyTemplate("multi_value", prop_type=cfg.PropList),
2097N/A ]
2097N/A sectemp = cfg.PropertySectionTemplate("name",
2097N/A properties=exp_props)
2097N/A sec = sectemp.create("name")
3339N/A self.assertTrue(isinstance(sec, cfg.PropertySection))
2097N/A
2097N/A expected = sorted([
2097N/A (p.name, type(p)) for p in exp_props
2097N/A ])
2097N/A returned = sorted([
2097N/A (p.name, type(p)) for p in sec.get_properties()
2097N/A ])
2097N/A self.assertEqualDiff(expected, returned)
2097N/A
2097N/A
1968N/Aclass _TestConfigBase(pkg5unittest.Pkg5TestCase):
1968N/A
1968N/A _defs = {
1968N/A 0: [cfg.PropertySection("first_section", properties=[
1968N/A cfg.PropBool("bool_basic"),
1968N/A cfg.PropBool("bool_default", default=True),
1968N/A cfg.PropInt("int_basic"),
1968N/A cfg.PropInt("int_default", default=14400),
1968N/A cfg.PropPublisher("publisher_basic"),
1968N/A cfg.PropPublisher("publisher_default",
1968N/A default="example.com"),
1968N/A cfg.Property("str_basic"),
1968N/A cfg.Property("str_escape", default=";, &, (, ), |, ^, <, "
1968N/A ">, nl\n, sp , tab\t, bs\\, ', \", `"),
1968N/A cfg.Property("str_default", default=TH_PACKAGE),
1968N/A cfg.PropDefined("str_allowed", allowed=["<pathname>",
1968N/A "<exec:pathname>", "<smffmri>", "builtin"],
1968N/A default="builtin"),
1968N/A cfg.PropDefined("str_noneallowed", allowed=["", "bob cat"]),
1968N/A cfg.PropList("list_basic"),
1968N/A cfg.PropList("list_default", default=[TH_PACKAGE, "bob cat",
1968N/A "profit"]),
1968N/A cfg.PropList("list_allowed", allowed=["<pathname>",
1968N/A "builtin"], default=["builtin"]),
1968N/A cfg.PropList("list_noneallowed", allowed=["", "always",
1968N/A "never"]),
1968N/A ]),
1968N/A cfg.PropertySection("second_section", properties=[
1968N/A cfg.PropSimpleList("simple_list_basic"),
1968N/A cfg.PropSimpleList("simple_list_default", default=["bar",
1968N/A "foo", TH_PACKAGE]),
1968N/A cfg.PropSimpleList("simple_list_allowed",
1968N/A allowed=["<pathname>", "builtin"],
1968N/A default=["builtin"]),
1968N/A cfg.PropSimpleList("simple_list_noneallowed",
1968N/A allowed=["", "<pathname>", "builtin"]),
1968N/A cfg.PropPubURI("uri_basic"),
1968N/A cfg.PropPubURI("uri_default",
1968N/A default="http://example.com/"),
2097N/A cfg.PropSimplePubURIList("urilist_basic"),
2097N/A cfg.PropSimplePubURIList("urilist_default",
1968N/A default=["http://example.com/", "file:/example/path"]),
1968N/A cfg.PropUUID("uuid_basic"),
1968N/A cfg.PropUUID("uuid_default",
1968N/A default="16fd2706-8baf-433b-82eb-8c7fada847da"),
1968N/A ]),
1968N/A ],
1968N/A 1: [cfg.PropertySection("first_section", properties=[
1968N/A cfg.PropBool("bool_basic"),
1968N/A cfg.Property("str_basic"),
1968N/A ]),
1968N/A ],
1968N/A }
1968N/A
2097N/A _templated_defs = {
2097N/A 0: [cfg.PropertySection("facet", properties=[
2097N/A cfg.PropertyTemplate("^facet\..*", prop_type=cfg.PropBool)
2097N/A ]),
2097N/A ],
2097N/A 1: [cfg.PropertySectionTemplate("^authority_.*", properties=[
2097N/A cfg.PropPublisher("prefix")
2097N/A ])
2097N/A ],
2097N/A }
2097N/A
1968N/A _initial_state = {
1968N/A 0: {
1968N/A "first_section": {
1968N/A "bool_basic": False,
1968N/A "bool_default": True,
1968N/A "int_basic": 0,
1968N/A "int_default": 14400,
1968N/A "publisher_basic": "",
1968N/A "publisher_default": "example.com",
1968N/A "str_basic": "",
1968N/A "str_escape": ";, &, (, ), |, ^, <, >, nl\n, sp , tab\t, " \
1968N/A "bs\\, ', \", `",
1968N/A "str_default": TH_PACKAGE,
1968N/A "str_allowed": "builtin",
1968N/A "str_noneallowed": "",
1968N/A "list_basic": [],
1968N/A "list_default": [TH_PACKAGE, "bob cat", "profit"],
1968N/A "list_allowed": ["builtin"],
1968N/A "list_noneallowed": [],
1968N/A },
1968N/A "second_section": {
1968N/A "simple_list_basic": [],
1968N/A "simple_list_default": ["bar", "foo", TH_PACKAGE],
1968N/A "simple_list_allowed": ["builtin"],
1968N/A "simple_list_noneallowed": [],
1968N/A "uri_basic": "",
1968N/A "uri_default": "http://example.com/",
1968N/A "urilist_basic": [],
1968N/A "urilist_default": ["http://example.com/",
1968N/A "file:/example/path"],
1968N/A "uuid_basic": "",
1968N/A "uuid_default": "16fd2706-8baf-433b-82eb-8c7fada847da",
1968N/A },
1968N/A },
1968N/A 1: {
1968N/A "first_section": {
1968N/A "bool_basic": False,
1968N/A "str_basic": "",
1968N/A },
1968N/A },
1968N/A }
1968N/A
1968N/A def _verify_initial_state(self, conf, exp_version, ver_defs=None,
1968N/A exp_state=None):
1968N/A if ver_defs is None:
1968N/A try:
1968N/A ver_defs = self._defs[exp_version]
1968N/A except:
1968N/A raise RuntimeError("Version not found in "
1968N/A "definitions.")
1968N/A if exp_state is None:
1968N/A exp_state = self._initial_state[exp_version]
1968N/A
1968N/A conf_idx = conf.get_index()
1968N/A self.assertEqual(conf.version, exp_version)
1968N/A self.assertEqualDiff(exp_state, conf_idx)
1968N/A
1968N/A # Map out the type of each section and property returned and
1968N/A # verify that if it exists in the definition that the type
1968N/A # matches.
1968N/A def iter_section(parent, spath):
1968N/A # Yield any properties for this section.
1968N/A for prop in parent.get_properties():
1968N/A yield spath, type(parent), prop.name, type(prop)
1968N/A
1968N/A if not hasattr(parent, "get_sections"):
1968N/A # Class doesn't support subsections.
1968N/A return
1968N/A
1968N/A # Yield subsections.
1968N/A for secobj in parent.get_sections():
1968N/A for rval in iter_section(secobj,
1968N/A "/".join((spath, secobj.name))):
1968N/A yield rval
1968N/A
1968N/A def map_types(slist):
1968N/A tmap = {}
1968N/A for secobj in slist:
1968N/A for spath, stype, pname, ptype in iter_section(
1968N/A secobj, secobj.name):
1968N/A tmap.setdefault(spath, {
1968N/A "type": stype,
1968N/A "props": {},
1968N/A })
1968N/A tmap[spath]["props"][pname] = ptype
1968N/A return tmap
1968N/A
1968N/A if not ver_defs:
1968N/A # No version definitions to compare.
1968N/A return
1968N/A
1968N/A exp_types = map_types(ver_defs)
1968N/A act_types = map_types(conf.get_sections())
1968N/A self.assertEqualDiff(exp_types, act_types)
1968N/A
1968N/Aclass TestConfig(_TestConfigBase):
1968N/A """Class to test the functionality of the pkg.config 'flat'
1968N/A configuration classes.
1968N/A """
1968N/A
1968N/A _initial_files = {
1968N/A 0: u"""\
1968N/A[CONFIGURATION]
1968N/Aversion = 0
1968N/A
1968N/A[first_section]
1968N/Abool_basic = False
1968N/Abool_default = True
1968N/Aint_basic = 0
1968N/Aint_default = 14400
1968N/Apublisher_basic =
1968N/Apublisher_default = example.com
1968N/Astr_basic =
3158N/Astr_default = {uni_txt}
1968N/Astr_allowed = builtin
1968N/Astr_noneallowed =
1968N/Alist_basic = []
3158N/Alist_default = [u'{uni_escape}', 'bob cat', 'profit']
1968N/Alist_allowed = ['builtin']
1968N/Alist_noneallowed = []
1968N/A
1968N/A[second_section]
1968N/Asimple_list_basic =
3158N/Asimple_list_default = bar,foo,{uni_txt}
1968N/Asimple_list_allowed = builtin
1968N/Asimple_list_noneallowed =
1968N/Auri_basic =
1968N/Auri_default = http://example.com/
1968N/Aurilist_basic =
1968N/Aurilist_default = http://example.com/,file:/example/path
1968N/Auuid_basic =
1968N/Auuid_default = 16fd2706-8baf-433b-82eb-8c7fada847da
3339N/A""".format(uni_escape=TH_PACKAGE.encode("unicode_escape") if six.PY2 else TH_PACKAGE,
3158N/A uni_txt=TH_PACKAGE),
1968N/A 1: """\
1968N/A[CONFIGURATION]
1968N/Aversion = 1
1968N/A
1968N/A[first_section]
1968N/Abool_basic = False
1968N/Astr_basic =
1968N/A"""
1968N/A }
1968N/A
1968N/A def test_base(self):
1968N/A """Verify that the base Config class functionality works as
1968N/A expected.
1968N/A """
1968N/A
1968N/A # Verify that write() doesn't raise an error for base Config
1968N/A # class (it should be a no-op).
1968N/A conf = cfg.Config()
1968N/A conf.set_property("section", "property", "value")
1968N/A conf.write()
1968N/A
1968N/A #
1968N/A # Verify initial state of Config object.
1968N/A #
1968N/A
1968N/A # Verify no definitions, overrides, or version.
1968N/A conf = cfg.Config()
1968N/A self._verify_initial_state(conf, 0, {},
1968N/A exp_state={})
1968N/A
1968N/A # Same as above, but with version.
1968N/A conf = cfg.Config(version=1)
1968N/A self._verify_initial_state(conf, 1, {},
1968N/A exp_state={})
1968N/A
1968N/A # Verify no definitions with overrides.
1968N/A overrides = {
1968N/A "first_section": {
1968N/A "bool_basic": "False",
1968N/A },
1968N/A }
1968N/A conf = cfg.Config(overrides=overrides)
1968N/A self._verify_initial_state(conf, 0, {},
1968N/A exp_state=overrides)
1968N/A
1968N/A # Verify with no overrides and no version (max version found in
1968N/A # _defs should be used).
1968N/A conf = cfg.Config(definitions=self._defs)
1968N/A self._verify_initial_state(conf, 1)
1968N/A
1968N/A # Verify with no overrides and with version.
1968N/A conf = cfg.Config(definitions=self._defs, version=0)
1968N/A self._verify_initial_state(conf, 0)
1968N/A
1968N/A # Verify with overrides using native values (as opposed to
1968N/A # string values) and with version.
1968N/A overrides = {
1968N/A "first_section": {
1968N/A "bool_basic": True,
1968N/A "int_basic": 14400,
1968N/A },
1968N/A "second_section": {
1968N/A "uri_basic": "http://example.net/",
1968N/A },
1968N/A }
1968N/A conf = cfg.Config(definitions=self._defs, overrides=overrides,
1968N/A version=0)
1968N/A exp_state = copy.deepcopy(self._initial_state[0])
3234N/A for sname, props in six.iteritems(overrides):
3234N/A for pname, value in six.iteritems(props):
1968N/A exp_state[sname][pname] = value
1968N/A self._verify_initial_state(conf, 0, exp_state=exp_state)
1968N/A
1968N/A #
1968N/A # Verify stringify behaviour.
1968N/A #
1968N/A
1968N/A #
1968N/A # Test str case with and without unicode data.
1968N/A #
1968N/A conf = cfg.Config(definitions=self._defs, version=1)
1968N/A self.assertEqualDiff("""\
1968N/A[first_section]
3339N/Abool_basic = False
1968N/Astr_basic =
1968N/A
1968N/A""", str(conf))
1968N/A
1968N/A conf.set_property("first_section", "str_basic", TH_PACKAGE)
3339N/A if six.PY2:
3339N/A self.assertEqualDiff("""\
1968N/A[first_section]
3339N/Abool_basic = False
3158N/Astr_basic = {0}
1968N/A
3158N/A""".format(TH_PACKAGE.encode("utf-8")), str(conf))
3339N/A else:
3339N/A # str() must return str (unicode) in Python 3.
3339N/A self.assertEqualDiff("""\
3339N/A[first_section]
3339N/Abool_basic = False
3339N/Astr_basic = {0}
3339N/A
3339N/A""".format(TH_PACKAGE), str(conf))
1968N/A
1968N/A #
1968N/A # Test unicode case with and without unicode data.
1968N/A #
1968N/A conf = cfg.Config(definitions=self._defs, version=1)
1968N/A self.assertEqualDiff(u"""\
1968N/A[first_section]
3339N/Abool_basic = False
1968N/Astr_basic =
1968N/A
3234N/A""", six.text_type(conf))
1968N/A
1968N/A conf.set_property("first_section", "str_basic", TH_PACKAGE)
1968N/A self.assertEqualDiff(u"""\
1968N/A[first_section]
3339N/Abool_basic = False
3158N/Astr_basic = {0}
1968N/A
3234N/A""".format(TH_PACKAGE), six.text_type(conf))
2097N/A
2097N/A # Verify target is None.
2097N/A self.assertEqual(conf.target, None)
1968N/A
2097N/A def test_add_get_remove_sections(self):
1968N/A """Verify that add_section, get_section, get_sections, and
1968N/A get_index work as expected.
1968N/A """
1968N/A
1968N/A propcls = cfg.Property
1968N/A conf = cfg.Config()
1968N/A
1968N/A # Verify that attempting to retrieve an unknown section raises
1968N/A # an exception.
1968N/A self.assertRaises(cfg.UnknownSectionError, conf.get_section,
1968N/A "s1")
1968N/A
2097N/A # Verify that attempting to remove an unknown section raises
2097N/A # an exception.
2097N/A self.assertRaises(cfg.UnknownSectionError, conf.remove_section,
2097N/A "s1")
2097N/A
1968N/A # Verify that a section cannot be added twice.
1968N/A seccls = cfg.PropertySection
1968N/A s1 = seccls("s1", properties=[
1968N/A propcls("1p1", "11"),
1968N/A propcls("1p2", "12"),
1968N/A propcls("1p3", "13"),
1968N/A ])
1968N/A conf.add_section(s1)
1968N/A self.assertRaises(AssertionError, conf.add_section, s1)
1968N/A self.assertEqual(id(s1), id(conf.get_section(s1.name)))
1968N/A
1968N/A # Verify that get_sections returns expected value.
1968N/A s2 = seccls("s2", properties=[
1968N/A propcls("2p1", "21"),
1968N/A propcls("2p2", "22"),
1968N/A propcls("2p3", "23"),
1968N/A ])
1968N/A conf.add_section(s2)
1968N/A
1968N/A s3 = seccls("s3", properties=[
1968N/A propcls("3p1", "31"),
1968N/A propcls("3p2", "32"),
1968N/A propcls("3p3", "33"),
1968N/A ])
1968N/A conf.add_section(s3)
1968N/A
1968N/A returned = sorted(s.name for s in conf.get_sections())
1968N/A expected = ["s1", "s2", "s3"]
1968N/A self.assertEqualDiff(returned, expected)
1968N/A
1968N/A # Verify that get_index returns expected value.
1968N/A exp_idx = {
1968N/A "s1": {
1968N/A "1p1": "11",
1968N/A "1p2": "12",
1968N/A "1p3": "13",
1968N/A },
1968N/A "s2": {
1968N/A "2p1": "21",
1968N/A "2p2": "22",
1968N/A "2p3": "23",
1968N/A },
1968N/A "s3": {
1968N/A "3p1": "31",
1968N/A "3p2": "32",
1968N/A "3p3": "33",
1968N/A },
1968N/A }
1968N/A self.assertEqual(conf.get_index(), exp_idx)
1968N/A
1968N/A def test_file_read_write(self):
1968N/A """Verify that read and write works as expected for
1968N/A FileConfig.
1968N/A """
1968N/A
1968N/A # Verify configuration files missing state can still be loaded.
1968N/A content = """\
1968N/A[first_section]
1968N/Astr_basic = bob cat
1968N/A"""
1968N/A scpath = self.make_misc_files({ "cfg_cache": content })[0]
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs)
2097N/A
2097N/A # Verify target matches specified path.
2097N/A self.assertEqual(conf.target, scpath)
2097N/A
1968N/A self.assertEqual(conf.version, 1) # Newest version assumed.
1968N/A self.assertEqual(conf.get_property("first_section",
1968N/A "str_basic"), "bob cat")
1968N/A portable.remove(scpath)
1968N/A
1968N/A # Verify configuration files with unknown sections or properties
1968N/A # can still be loaded.
1968N/A content = u"""\
1968N/A[CONFIGURATION]
1968N/Aversion = 0
1968N/A
1968N/A[unknown_section]
3158N/Aunknown_property = {0}
3158N/A""".format(TH_PACKAGE)
1968N/A scpath = self.make_misc_files({ "cfg_cache": content })[0]
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs)
1968N/A self.assertEqual(conf.version, 0)
1968N/A self.assertEqual(conf.get_property("unknown_section",
1968N/A "unknown_property"), TH_PACKAGE)
1968N/A portable.remove(scpath)
1968N/A
1968N/A # Verify configuration files with unknown versions can still be
1968N/A # loaded.
1968N/A content = u"""\
1968N/A[CONFIGURATION]
1968N/Aversion = 2
1968N/A
1968N/A[new_section]
3158N/Anew_property = {0}
3158N/A""".format(TH_PACKAGE)
1968N/A scpath = self.make_misc_files({ "cfg_cache": content })[0]
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs)
1968N/A self.assertEqual(conf.version, 2)
1968N/A self.assertEqual(conf.get_property("new_section",
1968N/A "new_property"), TH_PACKAGE)
1968N/A portable.remove(scpath)
1968N/A
1968N/A # Verify read and write of sample files.
3234N/A for ver, content in six.iteritems(self._initial_files):
1968N/A scpath = self.make_misc_files({
1968N/A "cfg_cache": content })[0]
1968N/A
1968N/A # Verify verison of content is auto detected and that
1968N/A # initial state matches file.
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs)
1968N/A self._verify_initial_state(conf, ver)
1968N/A
1968N/A # Cleanup.
1968N/A portable.remove(scpath)
1968N/A
1968N/A # Verify that write only happens when needed and that perms are
1968N/A # retained on existing configuration files.
1968N/A scpath = self.make_misc_files({ "cfg_cache": "" })[0]
1968N/A portable.remove(scpath)
1968N/A
1968N/A # Verify that configuration files that do not already exist will
1968N/A # be created if the file doesn't exist, even if nothing has
1968N/A # changed since init.
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs, version=0)
1968N/A self.assertTrue(not os.path.isfile(scpath))
1968N/A conf.write()
1968N/A
1968N/A # Now the file should exist and have specific perms.
1968N/A bstat = os.stat(scpath)
1968N/A self.assertEqual(stat.S_IMODE(bstat.st_mode),
1968N/A misc.PKG_FILE_MODE)
1968N/A
1968N/A # Calling write again shouldn't do anything since nothing
1968N/A # has changed since the last write.
1968N/A conf.write()
1968N/A astat = os.stat(scpath)
1968N/A self.assertEqual(bstat.st_mtime, astat.st_mtime)
1968N/A
1968N/A # Calling write after init shouldn't do anything since
1968N/A # nothing has changed since init.
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs)
1968N/A astat = os.stat(scpath)
1968N/A self.assertEqual(bstat.st_mtime, astat.st_mtime)
1968N/A
1968N/A # Set a property; write should happen this time.
1968N/A conf.set_property("first_section", "int_basic", 255)
1968N/A conf.write()
1968N/A astat = os.stat(scpath)
1968N/A self.assertNotEqual(bstat.st_mtime, astat.st_mtime)
1968N/A bstat = astat
1968N/A
1968N/A # Verify that set value was written along with the rest
1968N/A # of the initial state.
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs)
1968N/A exp_state = copy.deepcopy(self._initial_state[0])
1968N/A exp_state["first_section"]["int_basic"] = 255
1968N/A self._verify_initial_state(conf, 0, exp_state=exp_state)
1968N/A
1968N/A # If overrides are set during init, the file should get
1968N/A # written.
1968N/A overrides = {
1968N/A "first_section": {
1968N/A "int_basic": 0,
1968N/A },
1968N/A }
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs,
1968N/A overrides=overrides)
1968N/A conf.write()
1968N/A astat = os.stat(scpath)
1968N/A self.assertNotEqual(bstat.st_mtime, astat.st_mtime)
1968N/A bstat = astat
1968N/A
1968N/A # Verify overrides were written.
1968N/A conf = cfg.FileConfig(scpath, definitions=self._defs,
1968N/A overrides=overrides)
1968N/A exp_state = copy.deepcopy(self._initial_state[0])
1968N/A exp_state["first_section"]["int_basic"] = 0
1968N/A self._verify_initial_state(conf, 0, exp_state=exp_state)
1968N/A
1968N/A # Verify that user-specified permissions are retained.
3194N/A os.chmod(scpath, 0o777)
1968N/A conf.set_property("first_section", "int_basic", 16384)
1968N/A conf.write()
1968N/A astat = os.stat(scpath)
3194N/A self.assertEqual(stat.S_IMODE(astat.st_mode), 0o777)
1968N/A self.assertNotEqual(bstat.st_mtime, astat.st_mtime)
1968N/A bstat = astat
1968N/A
1968N/A if portable.util.get_canonical_os_type() != "unix":
1968N/A return
1968N/A
1968N/A portable.chown(scpath, 65534, 65534)
1968N/A conf.set_property("first_section", "int_basic", 0)
1968N/A conf.write()
1968N/A astat = os.stat(scpath)
1968N/A self.assertEqual(astat.st_uid, 65534)
1968N/A self.assertEqual(astat.st_gid, 65534)
1968N/A
2097N/A def test_get_modify_properties(self):
2097N/A """Verify that get_property, set_property, get_properties,
2097N/A set_properties, add_property_value, remove_property_value,
2097N/A and remove_property work as expected.
1968N/A """
1968N/A
1968N/A # Verify no definitions, overrides, or version.
1968N/A conf = cfg.Config()
1968N/A
1968N/A # Verify unknown section causes exception.
1968N/A self.assertRaises(cfg.UnknownSectionError,
1968N/A conf.get_section, "section")
1968N/A self.assertRaises(cfg.UnknownPropertyError,
1968N/A conf.get_property, "section", "property")
1968N/A
1968N/A # Verify set automatically creates unknown sections and
1968N/A # properties.
1968N/A conf.set_property("section", "bool_prop", False)
1968N/A
1968N/A secobj = conf.get_section("section")
1968N/A self.assertEqual(secobj.name, "section")
3339N/A self.assertTrue(isinstance(secobj, cfg.PropertySection))
1968N/A
2097N/A conf.set_properties({
2097N/A "section": {
2097N/A "int_prop": 16384,
2097N/A "str_prop": "bob cat",
2097N/A },
2097N/A })
1968N/A
1968N/A # Unknown properties when set are assumed to be a string
1968N/A # and forcibly cast as one if they are int, bool, etc.
1968N/A self.assertEqual(conf.get_property("section", "bool_prop"),
1968N/A "False")
1968N/A self.assertEqual(conf.get_property("section", "int_prop"),
1968N/A "16384")
1968N/A self.assertEqual(conf.get_property("section", "str_prop"),
1968N/A "bob cat")
1968N/A
2097N/A # Verify that get_properties returns expected value.
2097N/A secobj = conf.get_section("section")
2097N/A props = [
2097N/A secobj.get_property(p)
3339N/A for p in sorted(["bool_prop", "str_prop", "int_prop"])
2097N/A ]
2097N/A expected = [(secobj, props)]
2097N/A returned = []
2097N/A for sec, secprops in conf.get_properties():
2097N/A returned.append((sec, [p for p in secprops]))
2097N/A self.assertEqual(expected, returned)
2097N/A
1968N/A # Verify unknown property causes exception.
1968N/A self.assertRaises(cfg.UnknownPropertyError,
1968N/A conf.get_property, "section", "property")
1968N/A
1968N/A # Verify with no overrides and with version.
1968N/A conf = cfg.Config(definitions=self._defs, version=0)
1968N/A
1968N/A # Verify that get returns set value when defaults are present.
1968N/A self.assertEqual(conf.get_property("first_section",
1968N/A "str_default"), TH_PACKAGE)
1968N/A conf.set_property("first_section", "str_default", "lynx")
1968N/A self.assertEqual(conf.get_property("first_section",
1968N/A "str_default"), "lynx")
1968N/A
1968N/A # Verify that Config's set_property passes through the expected
1968N/A # exception when the value given is not valid for the property.
1968N/A self.assertRaises(cfg.InvalidPropertyValueError,
1968N/A conf.set_property, "first_section", "int_basic", "badval")
1968N/A
2097N/A # Verify that setting a property that doesn't currently exist,
2097N/A # but for which there is a matching definition, will be created
2097N/A # using the definition.
2097N/A conf = cfg.Config(definitions=self._defs, version=0)
2097N/A
2097N/A # If the section is removed, then setting any property for
2097N/A # that section should cause all properties defined for that
2097N/A # section to be set with their default values using the
2097N/A # types from the definition.
2097N/A conf.remove_section("first_section")
2097N/A conf.set_property("first_section", "bool_basic", False)
2097N/A self.assertRaises(cfg.InvalidPropertyValueError,
2097N/A conf.set_property, "first_section", "bool_basic", 255)
2097N/A
2097N/A conf.set_property("first_section", "list_basic", [])
2097N/A self.assertRaises(cfg.InvalidPropertyValueError,
2097N/A conf.set_property, "first_section", "list_basic", 255)
2097N/A
2097N/A self.assertEqualDiff(
2097N/A sorted(conf.get_index()["first_section"].keys()),
2097N/A sorted(self._initial_state[0]["first_section"].keys()))
2097N/A
2097N/A # Verify that add_property_value and remove_property_value
2097N/A # raise exceptions when used with non-list properties.
2097N/A self.assertRaises(cfg.PropertyMultiValueError,
2097N/A conf.add_property_value, "first_section", "bool_basic",
2097N/A True)
2097N/A self.assertRaises(cfg.PropertyMultiValueError,
2097N/A conf.remove_property_value, "first_section", "bool_basic",
2097N/A True)
2097N/A
2097N/A # Verify that add_property_value and remove_property_value
2097N/A # work as expected for list properties.
2097N/A conf.add_property_value("first_section", "list_noneallowed",
2097N/A "always")
2097N/A self.assertEqual(conf.get_property("first_section",
2097N/A "list_noneallowed"), ["always"])
2097N/A
2097N/A conf.remove_property_value("first_section", "list_noneallowed",
2097N/A "always")
2097N/A self.assertEqual(conf.get_property("first_section",
2097N/A "list_noneallowed"), [])
2097N/A
2097N/A # Verify that remove_property_value will raise expected error
2097N/A # if property value doesn't exist.
2097N/A self.assertRaises(cfg.UnknownPropertyValueError,
2097N/A conf.remove_property_value, "first_section",
2097N/A "list_noneallowed", "nosuchvalue")
2097N/A
2097N/A # Remove the property for following tests.
2097N/A conf.remove_property("first_section", "list_noneallowed")
2097N/A
2097N/A # Verify that attempting to remove a property that doesn't exist
2097N/A # will raise the expected exception.
2097N/A self.assertRaises(cfg.UnknownPropertyError,
2097N/A conf.remove_property, "first_section", "list_noneallowed")
2097N/A
2097N/A # Verify that add_property_value will automatically create
2097N/A # properties, just as set_property does, if needed.
2097N/A conf.add_property_value("first_section", "list_noneallowed",
2097N/A "always")
2097N/A self.assertEqual(conf.get_property("first_section",
2097N/A "list_noneallowed"), ["always"])
2097N/A
2097N/A # Verify that add_property_value will reject invalid values
2097N/A # just as set_property does.
2097N/A self.assertRaises(cfg.InvalidPropertyValueError,
2097N/A conf.add_property_value, "first_section",
2097N/A "list_noneallowed", "notallowed")
2097N/A
2097N/A # Verify that attempting to remove a property in a section that
2097N/A # doesn't exist fails as expected.
2097N/A conf.remove_section("first_section")
2097N/A self.assertRaises(cfg.UnknownPropertyError,
2097N/A conf.remove_property, "first_section", "list_noneallowed")
2097N/A
2097N/A # Verify that attempting to remove a property value in for a
2097N/A # property in a section that doesn't exist fails as expected.
2097N/A self.assertRaises(cfg.UnknownPropertyError,
2097N/A conf.remove_property_value, "first_section",
2097N/A "list_noneallowed", "always")
2097N/A
2097N/A # Verify that setting a property for which a property section
2097N/A # template exists, but an instance of the section does not yet
2097N/A # exist, works as expected.
2097N/A conf = cfg.Config(definitions=self._templated_defs, version=0)
2097N/A conf.remove_section("facet")
2097N/A conf.set_property("facet", "facet.devel", True)
2097N/A self.assertEqual(conf.get_property("facet", "facet.devel"),
2097N/A True)
2097N/A
2097N/A conf = cfg.Config(definitions=self._templated_defs, version=1)
3234N/A self.assertEqualDiff([], list(conf.get_index().keys()))
2097N/A
2097N/A conf.set_property("authority_example.com", "prefix",
2097N/A "example.com")
2097N/A self.assertEqual(conf.get_property("authority_example.com",
2097N/A "prefix"), "example.com")
2097N/A
1968N/A
1968N/Aclass TestSMFConfig(_TestConfigBase):
1968N/A """Class to test the functionality of the pkg.config SMF
1968N/A configuration classes.
1968N/A """
1968N/A
1968N/A _initial_files = {
1968N/A 0: u"""\
1968N/A<?xml version="1.0" encoding="UTF-8"?>
1968N/A<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
1968N/A<service_bundle type='manifest' name=':pkg-config'>
1968N/A<service
1968N/A name='application/pkg/configuration'
1968N/A type='service'
1968N/A version='1'>
1968N/A <property_group name='first_section' type='application'>
1968N/A <propval name='bool_basic' type='boolean' value='false' />
1968N/A <propval name='bool_default' type='boolean' value='true' />
1968N/A <propval name='int_basic' type='integer' value='0' />
1968N/A <propval name='publisher_basic' type='astring' value='' />
1968N/A <propval name='publisher_default' type='astring' value='example.com' />
1968N/A <propval name='str_basic' type='astring' value='' />
1968N/A <propval name='str_escape' type='astring' value=";, &amp;, (, ), |, ^, &lt;, &gt;, nl&#10;, sp , tab&#9;, bs\\, &apos;, &quot;, `" />
3158N/A <propval name='str_default' type='astring' value='{uni_txt}' />
1968N/A <property name='list_basic' type='astring'/>
1968N/A <property name='list_default' type='ustring'>
1968N/A <ustring_list>
3158N/A <value_node value="{uni_txt}" />
1968N/A <value_node value="bob cat" />
1968N/A <value_node value="profit" />
1968N/A </ustring_list>
1968N/A </property>
1968N/A <property name='list_allowed' type='ustring'>
1968N/A <ustring_list>
1968N/A <value_node value='builtin' />
1968N/A </ustring_list>
1968N/A </property>
1968N/A <property name='list_noneallowed' type='ustring' />
1968N/A </property_group>
1968N/A <property_group name='second_section' type='application'>
1968N/A <propval name='uri_basic' type='ustring' value='' />
1968N/A <propval name='uri_default' type='ustring' value='http://example.com/' />
1968N/A <propval name='uuid_basic' type='astring' value='' />
1968N/A <propval name='uuid_default' type='astring' value='16fd2706-8baf-433b-82eb-8c7fada847da' />
1968N/A <property name='simple_list_basic' type='ustring' />
1968N/A <property name='simple_list_default' type='ustring'>
1968N/A <ustring_list>
1968N/A <value_node value='bar' />
1968N/A <value_node value='foo' />
3158N/A <value_node value='{uni_txt}' />
1968N/A </ustring_list>
1968N/A </property>
1968N/A <property name='simple_list_allowed' type='ustring'>
1968N/A <ustring_list>
1968N/A <value_node value='builtin' />
1968N/A </ustring_list>
1968N/A </property>
1968N/A <property name='simple_list_noneallowed' type='ustring' />
1968N/A <property name='urilist_basic' type='uri' />
1968N/A <property name='urilist_default' type='uri'>
1968N/A <uri_list>
1968N/A <value_node value='http://example.com/' />
1968N/A <value_node value='file:/example/path' />
1968N/A </uri_list>
1968N/A </property>
1968N/A </property_group>
1968N/A <stability value='Unstable' />
1968N/A</service>
1968N/A</service_bundle>
3158N/A""".format(uni_txt=TH_PACKAGE),
1968N/A 1: """\
1968N/A<?xml version="1.0" encoding="UTF-8"?>
1968N/A<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
1968N/A<service_bundle type='manifest' name=':pkg-config'>
1968N/A<service
1968N/A name='application/pkg/configuration'
1968N/A type='service'
1968N/A version='1'>
1968N/A <property_group name='first_section' type='application'>
1968N/A <propval name='bool_basic' type='boolean' value='false' />
1968N/A <propval name='str_basic' type='astring' value='' />
1968N/A </property_group>
1968N/A <stability value='Unstable' />
1968N/A</service>
1968N/A</service_bundle>
1968N/A""",
1968N/A }
1968N/A
1968N/A # Manifest and state data for testing unknown sections and properties.
1968N/A __undef_mfst = """\
1968N/A<?xml version="1.0" encoding="UTF-8"?>
1968N/A<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
1968N/A<service_bundle type='manifest' name=':pkg-config'>
1968N/A<service
1968N/A name='application/pkg/configuration'
1968N/A type='service'
1968N/A version='1'>
1968N/A <property_group name='unknown_section1' type='application'>
1968N/A <propval name='unknown_prop11' type='astring' value='foo11' />
1968N/A <propval name='unknown_prop12' type='astring' value='foo12' />
1968N/A </property_group>
1968N/A <property_group name='unknown_section2' type='application'>
1968N/A <propval name='unknown_prop21' type='astring' value='foo21' />
1968N/A <propval name='unknown_prop22' type='astring' value='foo22' />
1968N/A </property_group>
1968N/A <stability value='Unstable' />
1968N/A</service>
1968N/A</service_bundle>
1968N/A"""
1968N/A __undef_state = {
1968N/A "unknown_section1": {
1968N/A "unknown_prop11": "foo11",
1968N/A "unknown_prop12": "foo12",
1968N/A },
1968N/A "unknown_section2": {
1968N/A "unknown_prop21": "foo21",
1968N/A "unknown_prop22": "foo22",
1968N/A },
1968N/A }
1968N/A
1968N/A # "Calgon, take me away!"
1968N/A # Torture data for SMFConfig parsing of values that require escaping.
1968N/A __escape_mfst = """\
1968N/A<?xml version="1.0" encoding="UTF-8"?>
1968N/A<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
1968N/A<service_bundle type='manifest' name=':pkg-config'>
1968N/A<service
1968N/A name='application/pkg/configuration'
1968N/A type='service'
1968N/A version='1'>
1968N/A <property_group name='escaped' type='application'>
1968N/A <propval name='one_slash' type='astring' value='\\' />
1968N/A <propval name='two_slash' type='astring' value='\\\\' />
1968N/A <propval name='one_slash_embed' type='astring' value='\\&#10;\\' />
1968N/A <propval name='two_slash_embed' type='astring' value='\\\\&#10;\\\\' />
1968N/A <propval name='end_one_slash' type='astring' value='foo\\' />
1968N/A <propval name='end_two_slash' type='astring' value='foo\\\\' />
1968N/A <propval name='end_embed_one_slash' type='astring' value='foo\\&#10;\\' />
1968N/A <propval name='end_embed_two_slash' type='astring' value='foo\\\\&#10;\\\\' />
1968N/A <propval name='multi_line' type='astring' value='foo\\&#10;&#10;\\&#10;&#10;\\&#10;\\' />
1968N/A <property name='list_multi_line' type='ustring'>
1968N/A <ustring_list>
1968N/A <value_node value="foo\\&#10;&#10;\\&#10;&#10;\\&#10;\\" />
1968N/A <value_node value=";, &amp;, (, ), |, ^, &lt;, &gt;, nl&#10;, sp , tab&#9;, bs\\, &apos;, &quot;, `" />
1968N/A <value_node value="Eat at Joe&apos;s!&#10;&#9;Really; eat at Joe&apos;s please." />
1968N/A </ustring_list>
1968N/A </property>
1968N/A </property_group>
1968N/A <stability value='Unstable' />
1968N/A</service>
1968N/A</service_bundle>
1968N/A"""
1968N/A
1968N/A __escape_defs = {
1968N/A 3: [cfg.PropertySection("escaped", properties=[
1968N/A cfg.Property("one_slash", default="\\"),
1968N/A cfg.Property("two_slash", default="\\\\"),
1968N/A cfg.Property("one_slash_embed", default="\\\n\\"),
1968N/A cfg.Property("two_slash_embed", default="\\\\\n\\\\"),
1968N/A cfg.Property("end_embed_one_slash", default="foo\\\n\\"),
1968N/A cfg.Property("end_one_slash", default="foo\\"),
1968N/A cfg.Property("end_two_slash", default="foo\\\\"),
1968N/A cfg.Property("end_embed_two_slash", default="foo\\\\\n\\\\"),
1968N/A cfg.Property("multi_line", default="foo\\\n\n\\\n\n\\\n\\"),
1968N/A cfg.PropList("list_multi_line", default=[
1968N/A "foo\\\n\n\\\n\n\\\n\\",
1968N/A ";, &, (, ), |, ^, <, >, nl\n, sp , tab\t, bs\\, ', \", `",
1968N/A "Eat at Joe's!\n\tReally; eat at Joe's please."
1968N/A ])
1968N/A ])]
1968N/A }
1968N/A
1968N/A __escape_state = {
1968N/A "escaped": {
1968N/A "one_slash": "\\",
1968N/A "two_slash": "\\\\",
1968N/A "one_slash_embed": "\\\n\\",
1968N/A "two_slash_embed": "\\\\\n\\\\",
1968N/A "end_embed_one_slash": "foo\\\n\\",
1968N/A "end_one_slash": "foo\\",
1968N/A "end_two_slash": "foo\\\\",
1968N/A "end_embed_two_slash": "foo\\\\\n\\\\",
1968N/A "multi_line": "foo\\\n\n\\\n\n\\\n\\",
1968N/A "list_multi_line": [
1968N/A "foo\\\n\n\\\n\n\\\n\\",
1968N/A ";, &, (, ), |, ^, <, >, nl\n, sp , tab\t, bs\\, ', \", `",
1968N/A "Eat at Joe's!\n\tReally; eat at Joe's please."
1968N/A ],
1968N/A }
1968N/A }
1968N/A
1968N/A def setUp(self):
1968N/A """Prepare the tests."""
1968N/A _TestConfigBase.setUp(self)
1968N/A self.__configd = None
1968N/A
1968N/A def __create_smf_repo(self, manifest):
1968N/A """Create a new SMF repository importing only the specified
1968N/A manifest file."""
1968N/A
1968N/A SVCCFG_PATH = "/usr/sbin/svccfg"
1968N/A
1968N/A rdbname = tempfile.mktemp(prefix="repo-", suffix=".db", dir="")
1968N/A sc_repo_filename = self.make_misc_files({ rdbname: '' })[0]
1968N/A portable.remove(sc_repo_filename)
1968N/A
1968N/A pdir = os.path.dirname(sc_repo_filename)
1968N/A hndl = self.cmdline_run(
3158N/A "SVCCFG_REPOSITORY={sc_repo_filename} "
3158N/A "{SVCCFG_PATH} import {manifest}".format(**locals()),
1971N/A coverage=False, handle=True)
1968N/A assert hndl is not None
1968N/A hndl.wait()
1968N/A
1968N/A return sc_repo_filename
1968N/A
1968N/A def __poll_process(self, hndl, pfile):
1968N/A try:
1968N/A begintime = time.time()
1968N/A
1968N/A sleeptime = 0.0
1968N/A check_interval = 0.20
1968N/A contact = False
1968N/A while (time.time() - begintime) <= 10.0:
1968N/A hndl.poll()
1968N/A time.sleep(check_interval)
1968N/A # The door file will exist but will fail
1968N/A # os.path.isfile() check if the process
1968N/A # has launched.
1968N/A if os.path.exists(pfile) and \
1968N/A not os.path.isfile(pfile):
1968N/A contact = True
1968N/A break
1968N/A
1968N/A if contact == False:
1968N/A raise RuntimeError("Process did not launch "
1968N/A "successfully.")
3171N/A except (KeyboardInterrupt, RuntimeError) as e:
1971N/A try:
1971N/A hndl.kill()
1971N/A finally:
1971N/A self.debug(str(e))
1968N/A raise
1968N/A
1968N/A def __start_configd(self, sc_repo_filename):
1968N/A """Start svc.configd for the specified SMF repository."""
1968N/A
1968N/A assert not self.__configd
1968N/A
1968N/A SC_REPO_SERVER = "/lib/svc/bin/svc.configd"
1968N/A
1968N/A doorname = tempfile.mktemp(prefix="repo-door-", dir="")
1968N/A sc_repo_doorpath = self.make_misc_files({ doorname: "" })[0]
3194N/A os.chmod(sc_repo_doorpath, 0o600)
1968N/A
3158N/A hndl = self.cmdline_run("{SC_REPO_SERVER} "
3158N/A "-d {sc_repo_doorpath} -r {sc_repo_filename}".format(
3158N/A **locals()), coverage=False, handle=True)
1968N/A assert hndl is not None
1968N/A self.__configd = hndl
1968N/A self.__poll_process(hndl, sc_repo_doorpath)
1968N/A self.__starttime = time.time()
1968N/A return sc_repo_doorpath
1968N/A
2097N/A def __verify_ex_stringify(self, ex):
2097N/A encs = str(ex)
2097N/A self.assertNotEqual(len(encs), 0)
3234N/A unis = six.text_type(ex)
2097N/A self.assertNotEqual(len(unis), 0)
3339N/A if six.PY2:
3339N/A self.assertEqualDiff(encs, unis.encode("utf-8"))
3339N/A else:
3339N/A self.assertEqualDiff(encs, unis)
2097N/A
1968N/A def test_exceptions(self):
1968N/A """Verify that exception classes can be initialized as expected,
1968N/A and when stringified return a non-zero-length string.
1968N/A """
1968N/A
1968N/A # Verify the expected behavior of all SMF exception classes.
1968N/A for excls in (cfg.SMFReadError, cfg.SMFWriteError):
1968N/A # Verify that exception can't be created without
1968N/A # specifying svc_fmri and errmsg.
1968N/A self.assertRaises(AssertionError, excls,
1968N/A None, None)
1968N/A
1968N/A # Verify that the properties specified at init can
1968N/A # be accessed.
1968N/A svc_fmri = "svc:/application/pkg/configuration"
1968N/A errmsg = "error message"
1968N/A ex = excls(svc_fmri, errmsg)
1968N/A self.assertEqual(ex.fmri, svc_fmri)
1968N/A self.assertEqual(ex.errmsg, errmsg)
2097N/A self.__verify_ex_stringify(ex)
1968N/A
2097N/A # Verify that exception can't be created without specifying
2097N/A # section.
2097N/A excls = cfg.SMFInvalidSectionNameError
2097N/A self.assertRaises(AssertionError, excls, None)
1968N/A
2097N/A # Verify that exception can be created with just section and
2097N/A # that expected value is set. In addition, verify that the
2097N/A # stringified form or unicode object is equal and not zero-
2097N/A # length.
2097N/A ex1 = excls("section")
2097N/A self.assertEqual(ex1.section, "section")
2097N/A self.__verify_ex_stringify(ex1)
1968N/A
2097N/A # Verify that exception can't be created without specifying
2097N/A # prop.
2097N/A excls = cfg.SMFInvalidPropertyNameError
2097N/A self.assertRaises(AssertionError, excls, None)
1968N/A
2097N/A # Verify that exception can be created with just prop and that
2097N/A # expected value is set. In addition, verify that the
2097N/A # stringified form or unicode object is equal and not zero-
2097N/A # length.
2097N/A ex1 = excls("prop")
2097N/A self.assertEqual(ex1.prop, "prop")
2097N/A self.__verify_ex_stringify(ex1)
1968N/A
1968N/A def test_add_set_property(self):
1968N/A """Verify that add_section and set_property works as expected.
1968N/A (SMFConfig enforces additional restrictions on naming.)
1968N/A """
1968N/A
1968N/A svc_fmri = "svc:/application/pkg/configuration"
1968N/A
1968N/A rfiles = []
1968N/A mname = "smf-manifest-naming.xml"
1968N/A mpath = self.make_misc_files({ mname: self.__undef_mfst })[0]
1968N/A rfiles.append(mpath)
1968N/A
1968N/A rpath = self.__create_smf_repo(mpath)
1968N/A rfiles.append(rpath)
1968N/A
1968N/A dpath = self.__start_configd(rpath)
1968N/A rfiles.append(dpath)
1968N/A
1968N/A # Retrieve configuration data from SMF.
1968N/A try:
1968N/A conf = cfg.SMFConfig(svc_fmri,
1968N/A doorpath=dpath)
1968N/A finally:
1968N/A # Removing the files stops configd.
1968N/A self.__configd = None
1968N/A while rfiles:
1968N/A portable.remove(rfiles[-1])
1968N/A rfiles.pop()
1968N/A
1968N/A # Verify that SMFConfig's add_section passes through the
1968N/A # expected exception when the name of the property section
1968N/A # is not valid for SMF.
1968N/A invalid_names = ("1startnum", "has.stopnocomma",
1968N/A " startspace")
1968N/A for sname in invalid_names:
1968N/A section = cfg.PropertySection(sname)
1968N/A self.assertRaises(cfg.SMFInvalidSectionNameError,
1968N/A conf.add_section, section)
1968N/A
1968N/A # Verify that SMFConfig's set_property passes through the
1968N/A # expected exception when the name of the property is not
1968N/A # valid for SMF.
1968N/A for pname in invalid_names:
1968N/A self.assertRaises(cfg.SMFInvalidPropertyNameError,
1968N/A conf.set_property, "section", pname, "value")
1968N/A
1968N/A def test_read(self):
1968N/A """Verify that read works as expected for SMFConfig."""
1968N/A
1968N/A # Verify read and write of sample configuration.
1968N/A svc_fmri = "svc:/application/pkg/configuration"
1968N/A
1968N/A def cleanup():
1968N/A self.__configd = None
1968N/A while rfiles:
1968N/A portable.remove(rfiles[-1])
1968N/A rfiles.pop()
1968N/A
1968N/A rfiles = []
1968N/A def test_mfst(svc_fmri, ver, mfst_content, defs,
1968N/A exp_state=None):
3158N/A mname = "smf-manifest-{0:d}.xml".format(ver)
1968N/A mpath = self.make_misc_files({ mname: mfst_content })[0]
1968N/A rfiles.append(mpath)
1968N/A
1968N/A rpath = self.__create_smf_repo(mpath)
1968N/A rfiles.append(rpath)
1968N/A
1968N/A dpath = self.__start_configd(rpath)
1968N/A rfiles.append(dpath)
1968N/A
1968N/A # Retrieve configuration data from SMF.
1968N/A try:
1968N/A conf = cfg.SMFConfig(svc_fmri,
1968N/A definitions=defs,
1968N/A doorpath=dpath,
1968N/A version=ver)
1968N/A finally:
1968N/A cleanup()
1968N/A
1968N/A # Verify initial state matches expected.
1968N/A ver_defs = defs.get(ver, {})
1968N/A self._verify_initial_state(conf, ver, ver_defs,
1968N/A exp_state=exp_state)
1968N/A
1968N/A # Verify SMFConfig raises exception if write() is
1968N/A # attempted (not currently supported).
1968N/A self.assertRaises(cfg.SMFWriteError, conf.write)
1968N/A
3234N/A for ver, mfst_content in six.iteritems(self._initial_files):
1968N/A test_mfst(svc_fmri, ver, mfst_content, self._defs)
1968N/A
1968N/A # Verify configuration data with unknown sections or properties
1968N/A # can be loaded.
1968N/A test_mfst(svc_fmri, 2, self.__undef_mfst, {},
1968N/A exp_state=self.__undef_state)
1968N/A
1968N/A # Verify configuration data that requires extensive escaping
1968N/A # during parsing can be loaded.
1968N/A test_mfst(svc_fmri, 3, self.__escape_mfst, self.__escape_defs,
1968N/A exp_state=self.__escape_state)
1968N/A
1968N/A # Verify that an SMFReadError is raised if the configuration
1968N/A # data cannot be read from SMF. (This should fail since
1968N/A self.assertRaises(cfg.SMFReadError, test_mfst,
1968N/A "svc:/nosuchservice", 4, self.__escape_mfst, {})
1968N/A
1968N/A
1968N/Aif __name__ == "__main__":
1968N/A unittest.main()