def testSave(self): """Save the config and ensure it still works.""" conf = config_lib.GrrConfigManager() config_file = os.path.join(self.temp_dir, "writeback.yaml") conf.SetWriteBack(config_file) conf.DEFINE_string("NewSection1.new_option1", "Default Value", "Help") conf.Set("NewSection1.new_option1", "New Value1") conf.Write() new_conf = config_lib.GrrConfigManager() new_conf.Initialize(config_file) self.assertEqual(new_conf["NewSection1.new_option1"], "New Value1")
def Run(self): config_obj = config_lib.GrrConfigManager() config_obj.DEFINE_bool("SectionFoo.sample_boolean_option", True, "Regression test sample boolean option.") config_obj.DEFINE_integer("SectionFoo.sample_integer_option", 42, "Sample integer option.") config_obj.DEFINE_string("SectionBar.sample_string_option", "", "Sample string option.") config_obj.DEFINE_list("SectionBar.sample_list_option", [], "Sample list option.") # This has to be defined as http_api.HttpRequestHandler.HandleRequest # depends on it and regression data won't get rendered without # this config option defined. config_obj.DEFINE_string("AdminUI.debug_impersonate_user", None, "") config = """ SectionFoo.sample_boolean_option: True SectionBar.sample_string_option: "%(sAmPlE|lower)" """ config_lib.LoadConfig(config_obj, config_fd=StringIO.StringIO(config), parser=config_lib.YamlParser) with utils.Stubber(config_lib, "CONFIG", config_obj): self.Check("GET", "/api/config")
def testParsing(self): conf = config_lib.GrrConfigManager() conf.DEFINE_list("Section1.test_list", ["a", "b"], "A test integer.") conf.DEFINE_integer("Section1.test", 0, "An integer") conf.DEFINE_integer("Section1.test2", 0, "An integer") self.assertRaises( config_lib.MissingConfigDefinitionError, conf.Initialize, parser=config_lib.YamlParser, data=""" Section2.test: 2 """) conf.DEFINE_string("Section2.test", "", "A string") conf.DEFINE_context("Client Context") conf.DEFINE_context("Windows Context") conf.Initialize( parser=config_lib.YamlParser, data=""" # Configuration options can be written as long hand, dot separated parameters. Section1.test: 2 Section1.test_list: x,y Section2.test: 3%(Section1.test) Client Context: Section1.test: 6 Section1.test2: 1 Windows Context: Section1.test: 10 Windows Context: Section1.test: 5 Section1.test2: 2 """) self.assertEqual(conf["Section1.test"], 2) # Test interpolation works. self.assertEqual(conf["Section2.test"], "32") self.assertEqual(conf["Section1.test_list"], ["x", "y"]) self.assertEqual( conf.Get("Section1.test_list", context=["Client Context", "Windows Context"]), ["x", "y"]) # Test that contexts affect option selection. self.assertEqual(conf.Get("Section1.test", context=["Client Context"]), 6) self.assertEqual(conf.Get("Section1.test", context=["Windows Context"]), 5) context = ["Client Context", "Windows Context"] self.assertEqual(conf.Get("Section1.test", context=context), 10) context = ["Windows Context", "Client Context"] # Order of the context parameters should not matter. self.assertEqual(conf.Get("Section1.test", context=context), 10)
def testInit(self): """Testing initialization of a ConfigManager.""" conf = config_lib.GrrConfigManager() conf.DEFINE_string("MemoryDriver.device_path", "Default Value", "Help") conf.DEFINE_context("Platform:Windows") conf.DEFINE_context("Client Context") conf.DEFINE_context("Platform:Linux") data = r""" Platform:Linux: MemoryDriver.device_path: /dev/pmem Platform:Windows: MemoryDriver.device_path: \\\\.\\pmem """ conf.Initialize(parser=config_lib.YamlParser, data=data) # Check that the linux client have a different value from the windows # client. self.assertEqual( conf.Get("MemoryDriver.device_path", context=("Client Context", "Platform:Linux")), "/dev/pmem") self.assertEqual( conf.Get("MemoryDriver.device_path", context=("Client Context", "Platform:Windows")), r"\\.\pmem")
def _GetNewConf(self): conf = config_lib.GrrConfigManager() conf.DEFINE_bool("SecondaryFileIncluded", False, "A string") conf.DEFINE_bool("TertiaryFileIncluded", False, "A string") conf.DEFINE_integer("Section1.int", 0, "An integer") conf.DEFINE_context("Client Context") return conf
def _SetupConfig(self, value): conf = config_lib.GrrConfigManager() config_file = os.path.join(self.temp_dir, "config.yaml") with open(config_file, "wb") as fd: fd.write("Section1.option1: %s" % value) conf.DEFINE_string("Section1.option1", "Default Value", "Help") conf.Initialize(filename=config_file) return conf
def testAddOption(self): """Test that we can add options.""" conf = config_lib.GrrConfigManager() conf.DEFINE_string("Section1.foobar", "test", "A test string.") conf.DEFINE_string("Section1.test", "test", "A test string.") conf.DEFINE_string("Section1.interpolated", "", "An interpolated string.") # This entry is not correct - the default is invalid. conf.DEFINE_integer("Section1.broken_int", "string", "A test integer.") conf.DEFINE_string("Section1.system", None, "The basic operating system.") conf.DEFINE_integer("Section1.test_int", 54, "A test integer.") conf.DEFINE_list("Section1.test_list", ["a", "b"], "A test integer.") conf.DEFINE_list("Section1.test_list2", ["a", "b"], "A test integer.") conf.Initialize(data=""" [Section1] foobar = X test_list = x,y [Section2] test_int = 34 interpolated = %(Section1.foobar)Y [Section3] test_int = 1 interpolated = %(%(Section1.foobar)|lower)Y """) # The default value is invalid. errors = conf.Validate("Section1") self.assertIn("Invalid value string for Integer", str(errors["Section1.broken_int"])) # Section not specified: self.assertRaises(config_lib.UnknownOption, conf.__getitem__, "a") # Test direct access. self.assertEqual(conf["Section1.foobar"], "X") self.assertEqual(conf["Section1.test_list"], ["x", "y"]) self.assertEqual(conf["Section1.test_list2"], ["a", "b"]) # Test default access. self.assertEqual(conf["Section1.test"], "test") # Test interpolation with full section name. self.assertEqual(conf["Section2.interpolated"], "XY") # Check that default values are typed. self.assertEqual(conf["Section1.test_int"], 54) # Test filter functions. self.assertEqual(conf["Section3.interpolated"], "xY")
def testSet(self): """Test setting options.""" # Test access methods. conf = config_lib.GrrConfigManager() conf.DEFINE_string("NewSection1.new_option1", "Default Value", "Help") conf.Set("NewSection1.new_option1", "New Value1") self.assertEquals(conf["NewSection1.new_option1"], "New Value1")
def testBadConfigRaises(self): conf = config_lib.GrrConfigManager() conf.initialized = False data = """ Section1.test: 2 """ # This config option isn't defined, so it should raise with self.assertRaises(config_lib.MissingConfigDefinitionError): conf.Initialize(parser=config_lib.YamlParser, data=data)
def testDataTypes(self): conf = config_lib.GrrConfigManager() conf.DEFINE_float("Section1.float", 0, "A float") conf.Initialize(parser=config_lib.YamlParser, data="Section1.float: abc") errors = conf.Validate("Section1") self.assertTrue( "Invalid value abc for Float" in str(errors["Section1.float"])) self.assertRaises(config_lib.ConfigFormatError, conf.Get, "Section1.float") conf.Initialize(parser=config_lib.YamlParser, data="Section1.float: 2") # Should have no errors now. Validate should normalize the value to a float. self.assertEqual(conf.Validate("Section1"), {}) self.assertEqual(type(conf.Get("Section1.float")), float) conf = config_lib.GrrConfigManager() conf.DEFINE_integer("Section1.int", 0, "An integer") conf.DEFINE_list("Section1.list", default=[], help="A list") conf.DEFINE_list("Section1.list2", default=["a", "2"], help="A list") conf.Initialize(parser=config_lib.YamlParser, data="Section1.int: 2.0") errors = conf.Validate("Section1") # Floats can not be coerced to an int because that will lose data. self.assertTrue( "Invalid value 2.0 for Integer" in str(errors["Section1.int"])) # A string can be coerced to an int if it makes sense: conf.Initialize(parser=config_lib.YamlParser, data="Section1.int: '2'") errors = conf.Validate("Section1") self.assertEqual(type(conf.Get("Section1.int")), long) self.assertEqual(type(conf.Get("Section1.list")), list) self.assertEqual(conf.Get("Section1.list"), []) self.assertEqual(type(conf.Get("Section1.list2")), list) self.assertEqual(conf.Get("Section1.list2"), ["a", "2"])
def testSemanticValueType(self): conf = config_lib.GrrConfigManager() conf.DEFINE_semantic_value(rdfvalue.Duration, "Section1.foobar", None, "Sample help.") conf.Initialize(parser=config_lib.YamlParser, data=""" Section1.foobar: 6d """) value = conf.Get("Section1.foobar") self.assertTrue(isinstance(value, rdfvalue.Duration)) self.assertEqual(value, rdfvalue.Duration("6d"))
def testBadFilterRaises(self): """Checks that bad filter directive raise.""" conf = config_lib.GrrConfigManager() conf.DEFINE_string("Section1.foo6", "%(somefile@somepackage|resource)", "test") conf.DEFINE_string("Section1.foo1", "%(Section1.foo6)/bar", "test") conf.Initialize(data="") with self.assertRaises(config_lib.InterpolationError) as context: _ = conf["Section1.foo1"] # Make sure the stringified exception explains the full interpolation chain. self.assertTrue("%(Section1.foo6)/bar" in str(context.exception))
def testRemoveContext(self): """Test that conflicting contexts are resolved by precedence.""" conf = config_lib.GrrConfigManager() conf.DEFINE_integer("Section1.test", 0, "An integer") conf.DEFINE_integer("Section1.test2", 9, "An integer") conf.DEFINE_context("Client Context") conf.DEFINE_context("Platform:Windows") conf.DEFINE_context("Extra Context") conf.Initialize( parser=config_lib.YamlParser, data=""" Section1.test: 2 Client Context: Section1.test: 6 Section1.test2: 8 Platform:Windows: Section1.test: 10 Extra Context: Section1.test: 15 """) # Should be defaults, no contexts added self.assertEqual(conf.Get("Section1.test"), 2) self.assertEqual(conf.Get("Section1.test2"), 9) # Now with Client Context conf.AddContext("Client Context") self.assertEqual(conf.Get("Section1.test"), 6) self.assertEqual(conf.Get("Section1.test2"), 8) # Should be back to defaults conf.RemoveContext("Client Context") self.assertEqual(conf.Get("Section1.test"), 2) self.assertEqual(conf.Get("Section1.test2"), 9) # Now with Windows Context, test2 is still default conf.AddContext("Platform:Windows") self.assertEqual(conf.Get("Section1.test"), 10) self.assertEqual(conf.Get("Section1.test2"), 9) # Should be back to defaults conf.RemoveContext("Platform:Windows") self.assertEqual(conf.Get("Section1.test"), 2) self.assertEqual(conf.Get("Section1.test2"), 9)
def testErrorDetection(self): """Check that invalid config files are detected immediately.""" test_conf = """ [Section1] test = val2""" conf = config_lib.GrrConfigManager() # Define test as an integer. conf.DEFINE_integer("Section1.test", 54, "A test integer.") conf.Initialize(data=test_conf) # This should raise since the config file is incorrect. errors = conf.Validate("Section1") self.assertTrue( "Invalid value val2 for Integer" in str(errors["Section1.test"]))
def testGet(self): conf = config_lib.GrrConfigManager() conf.DEFINE_string("Section1.foobar", "test", "A test string.") conf.DEFINE_string("Section1.foobaz", None, "An empty default string.") conf.DEFINE_string("Section1.foobin", "", "An empty default string.") conf.initialized = True self.assertEqual(conf.Get("Section1.foobar"), "test") self.assertEqual(conf.Get("Section1.foobar", default=None), None) conf.Initialize(data=""" [Section1] foobar = X """) self.assertEqual(conf.Get("Section1.foobar", default=None), "X") # This not being None is a little surprising, but probably not a big deal self.assertEqual(conf.Get("Section1.foobaz"), "") self.assertEqual(conf.Get("Section1.foobin"), "")
def testSemanticStructType(self): conf = config_lib.GrrConfigManager() conf.DEFINE_semantic_struct(rdf_file_finder.FileFinderArgs, "Section1.foobar", [], "Sample help.") conf.Initialize(parser=config_lib.YamlParser, data=""" Section1.foobar: paths: - "a/b" - "b/c" pathtype: "TSK" """) values = conf.Get("Section1.foobar") self.assertTrue(isinstance(values, rdf_file_finder.FileFinderArgs)) self.assertEqual(values.paths, ["a/b", "b/c"]) self.assertEqual(values.pathtype, "TSK")
def testContextApplied(self): conf = config_lib.GrrConfigManager() conf.DEFINE_integer("Section1.test", 0, "An integer") conf.DEFINE_context("Client Context") conf.DEFINE_context("Unused Context") conf.Initialize(parser=config_lib.YamlParser, data=""" Client Context: Section1.test: 6 """) # Should be defaults, no contexts added self.assertFalse(conf.ContextApplied("Client Context")) self.assertFalse(conf.ContextApplied("Unused Context")) conf.AddContext("Client Context") self.assertTrue(conf.ContextApplied("Client Context")) self.assertFalse(conf.ContextApplied("Unused Context"))
def testConflictingContexts(self): """Test that conflicting contexts are resolved by precedence.""" conf = config_lib.GrrConfigManager() conf.DEFINE_integer("Section1.test", 0, "An integer") conf.DEFINE_context("Client Context") conf.DEFINE_context("Platform:Windows") conf.DEFINE_context("Extra Context") conf.Initialize( parser=config_lib.YamlParser, data=""" Section1.test: 2 Client Context: Section1.test: 6 Platform:Windows: Section1.test: 10 Extra Context: Section1.test: 15 """) # Without contexts. self.assertEqual(conf.Get("Section1.test"), 2) # When running in the client context only. self.assertEqual(conf.Get("Section1.test", context=["Client Context"]), 6) # Later defined contexts (i.e. with later calls to AddContext()) are # stronger than earlier contexts. For example, contexts set the command line # --context option are stronger than contexts set by the running binary, # since they are added last. self.assertEqual( conf.Get("Section1.test", context=["Client Context", "Platform:Windows"]), 10) self.assertEqual( conf.Get("Section1.test", context=["Platform:Windows", "Client Context"]), 6)
def Run(self): config_obj = config_lib.GrrConfigManager() config_obj.DEFINE_string("SectionFoo.sample_string_option", "", "Sample string option.") config_obj.DEFINE_string("Mysql.database_password", "", "Secret password.") config = """ SectionBar.sample_string_option: "%(sAmPlE|lower)" Mysql.database_password: "******" """ config_lib.LoadConfig(config_obj, StringIO.StringIO(config), parser=config_lib.YamlParser) with utils.Stubber(config_lib, "CONFIG", config_obj): self.Check("GET", "/api/config/SectionFoo.sample_string_option") self.Check("GET", "/api/config/Mysql.database_password") self.Check("GET", "/api/config/NonExistingOption")
def Run(self): config_obj = config_lib.GrrConfigManager() config_obj.DEFINE_bool("SectionFoo.sample_boolean_option", True, "Regression test sample boolean option.") config_obj.DEFINE_integer("SectionFoo.sample_integer_option", 42, "Sample integer option.") config_obj.DEFINE_string("SectionBar.sample_string_option", "", "Sample string option.") config_obj.DEFINE_list("SectionBar.sample_list_option", [], "Sample list option.") config = """ SectionFoo.sample_boolean_option: True SectionBar.sample_string_option: "%(sAmPlE|lower)" """ config_lib.LoadConfig(config_obj, StringIO.StringIO(config), parser=config_lib.YamlParser) with utils.Stubber(config_lib, "CONFIG", config_obj): self.Check("GET", "/api/config")
def testBackslashes(self): conf = config_lib.GrrConfigManager() conf.DEFINE_string("Section1.parameter", "", "A test.") conf.DEFINE_string("Section1.parameter2", "", "A test.") conf.DEFINE_string("Section1.parameter3", "", "A test.") conf.Initialize(parser=config_lib.YamlParser, data=r""" Section1.parameter: | a\\b\\c\\d Section1.parameter2: | %(parameter)\\e Section1.parameter3: | \%(a\\b\\c\\d\) """) self.assertEqual(conf.Get("Section1.parameter"), "a\\b\\c\\d") self.assertEqual(conf.Get("Section1.parameter2"), "a\\b\\c\\d\\e") self.assertEqual(conf.Get("Section1.parameter3"), "%(a\\b\\c\\d)")
def testConstants(self): """Test that we can add options.""" conf = config_lib.GrrConfigManager() conf.initialized = False conf.DEFINE_constant_string("Section1.const", "test", "A test string.") # We should be able to read this while the config is not initialized. self.assertEqual(conf["Section1.const"], "test") data = """ [Section1] const = New string """ # Modification of constant values is an error. self.assertRaises(config_lib.ConstModificationError, conf.Set, "Section1.const", "New string") self.assertRaises(config_lib.ConstModificationError, conf.SetRaw, "Section1.const", "New string") self.assertRaises(config_lib.ConstModificationError, conf.Initialize, data=data)
def testConstants(self): """Test that we can not modify constant values during runtime.""" conf = config_lib.GrrConfigManager() conf.DEFINE_constant_string("Section1.const", "test", "A test string.") # We should be able to read this while the config is not initialized. self.assertEqual(conf["Section1.const"], "test") data = """ [Section1] const = New string """ # Modifying a constant value in the config file is OK. conf.Initialize(data=data) # Once the config file is loaded and initialized, modification of constant # values is an error. self.assertRaises(config_lib.ConstModificationError, conf.Set, "Section1.const", "New string") self.assertRaises(config_lib.ConstModificationError, conf.SetRaw, "Section1.const", "New string")
def Run(self): config_obj = config_lib.GrrConfigManager() config_obj.DEFINE_string("SectionFoo.sample_string_option", "", "Sample string option.") config_obj.DEFINE_string("Mysql.database_password", "", "Secret password.") # This has to be defined as http_api.HttpRequestHandler.HandleRequest # depends on it and regression data won't get rendered without # this config option defined. config_obj.DEFINE_string("AdminUI.debug_impersonate_user", None, "") config = """ SectionBar.sample_string_option: "%(sAmPlE|lower)" Mysql.database_password: "******" """ config_lib.LoadConfig(config_obj, config_fd=StringIO.StringIO(config), parser=config_lib.YamlParser) with utils.Stubber(config_lib, "CONFIG", config_obj): self.Check("GET", "/api/config/SectionFoo.sample_string_option") self.Check("GET", "/api/config/Mysql.database_password") self.Check("GET", "/api/config/NonExistingOption")
def testUnbalancedParenthesis(self): conf = config_lib.GrrConfigManager() name_list = [ "Section1.foobar", "Section1.foo", "Section1.foo1", "Section1.foo2", "Section1.foo3", "Section1.foo4", "Section1.foo5", "Section1.foo6", "Section1.interpolation1", "Section1.interpolation2", "Section1.literal" ] for name in name_list: self._DefineStringName(conf, name) conf.Initialize(data=r""" [Section1] foobar = X foo = %(Section1.foobar) foo1 = %(foo # Unbalanced parenthesis foo2 = foo) # Unbalanced parenthesis is ok if escaped. foo3 = foo\) # Or if enclosed in a literal block. foo6 = %{foo)} foo4 = %{%(hello)} foo5 = %{hello # Literal blocks can also appear inside filter interpolations to prevent # automatic expansions. # This pull the environment variable "sectionX" interpolation1 = %(section%(Section1.foobar)|env) # But this means literally section%(Section1.foo): interpolation2 = %(section%{%(Section1.foo)}|env) literal = %{aff4:/C\.(?P<path>.\{1,16\}?)($|/.*)} """) # Test direct access. self.assertEqual(conf["Section1.foo"], "X") self.assertRaises(config_lib.ConfigFormatError, conf.__getitem__, "Section1.foo1") self.assertRaises(config_lib.ConfigFormatError, conf.__getitem__, "Section1.foo2") self.assertEqual(conf["Section1.foo3"], "foo)") # Test literal expansion. self.assertEqual(conf["Section1.foo4"], "%(hello)") self.assertRaises(config_lib.ConfigFormatError, conf.__getitem__, "Section1.foo5") self.assertEqual(conf["Section1.foo6"], "foo)") # The Env filter forces uppercase on args. os.environ["sectionX".upper()] = "1" os.environ["section%(Section1.foo)".upper()] = "2" self.assertEqual(conf["Section1.interpolation1"], "1") self.assertEqual(conf["Section1.interpolation2"], "2") # Test that Set() escapes - i.e. reading the value back will return exactly # the same as we wrote: conf.Set("Section1.foo6", "%(Section1.foo3)") self.assertEqual(conf["Section1.foo6"], "%(Section1.foo3)") self.assertEqual(conf.GetRaw("Section1.foo6"), r"\%(Section1.foo3\)") # OTOH when we write it raw, reading it back will interpolate: conf.SetRaw("Section1.foo6", "%(Section1.foo3)") self.assertEqual(conf["Section1.foo6"], "foo)") # A complex regex which gets literally expanded. self.assertEqual(conf["Section1.literal"], r"aff4:/C\.(?P<path>.{1,16}?)($|/.*)")