def test_config_strict_mode_errors(): config.register(Item, strict_mode=True) test_config_path = testing.relative_module_path(__file__, 'test_config.yaml') with pytest.raises(ConfigLoadError, match='missing type declaration'): config.load_config(test_config_path)
def test_config_with_simple_classes(): # Another method for registering items (other than using decorator). config.register(Item) test_config_path = testing.relative_module_path(__file__, 'test_config.yaml') data = config.load_config(test_config_path) foo_with_defaults = data['foo_with_defaults'] assert foo_with_defaults.f == 1 empty_boo = data['empty_boo'] assert empty_boo.foo is None foo = data['foo'] boo = data['boo'] assert foo.s == 'some_string' assert foo.f == 2.5 assert boo.foo is foo assert len(boo.items) == 2 assert isinstance(boo.items[0], Item)
def test_config_unsafe_object_creation(): from ruamel import yaml import calendar test_config_path = testing.relative_module_path(__file__, 'test_config_unsafe.yaml') # Unsafe default loader allows any python object initialization data = yaml.load(open(test_config_path), Loader=yaml.Loader) assert 'time' in data assert isinstance(data['time'], calendar.Calendar) # With use safe version only to allow construct previously registered objects with pytest.raises(config.ConfigLoadError, match='could not determine a constructor'): config.load_config(test_config_path)
def test_dataclass(): test_config_path = testing.relative_module_path(__file__, 'test_dataclasses.yaml') data = config.load_config(test_config_path) dc1 = data['dc1'] assert dc1.x == 5 assert dc1.y == 'bleblo' assert dc1.z == [1, 2, 3] assert dc1.d == 'asd' dc2 = data['dc2'] assert dc2.x == 1 assert dc2.y == 'newble' assert dc2.z == [3, 4, 5] assert dc2.d == 4
def test_dataclass(): test_config_path = testing.relative_module_path(__file__, 'test_dataclasses.yaml') data = config.load_config(test_config_path) dc1 = data['dc1'] assert dc1.x == 5 assert dc1.y is None assert dc1.z == [1, 2, 3] assert dc1.d == 'asd' assert dc1.foo == 'foobaz' dc2 = data['dc2'] assert dc2.x == 1 assert dc2.y == 'newble' assert dc2.z == [3, 4, 5] assert dc2.d == 4 assert dc2.foo == FooEnum.BAR
def test_dataclass_validation_invalid_dict(): test_config_path = testing.relative_module_path(__file__, 'test_dataclasses_validation_invalid_dict.yaml') with pytest.raises(ConfigLoadError, match='wrong_value'): config.load_config(test_config_path)
def test_dataclass_validation(): test_config_path = testing.relative_module_path(__file__, 'test_dataclasses_validation.yaml') data = config.load_config(test_config_path) assert data['dc1'].rr == [[2, 3], []]
def test_dataclass_invalid_field(): test_config_path = testing.relative_module_path( __file__, 'test_dataclasses_invalid_field.yaml') with pytest.raises(config.ConfigLoadError, match="constructor signature"): config.load_config(test_config_path)
def test_invalid_dataclass_union(): test_config_path = testing.relative_module_path( __file__, 'test_dataclasses_invalid_union.yaml') with pytest.raises(config.ConfigLoadError, match="field 'd'.*improper type from union"): config.load_config(test_config_path)
def test_invalid_dataclass(): test_config_path = testing.relative_module_path( __file__, 'test_dataclasses_invalid.yaml') with pytest.raises(config.ConfigLoadError, match="has improper type"): config.load_config(test_config_path)
def main(): parser = argparse.ArgumentParser() parser.add_argument( '-c', '--config', help="Configuration", default=None, required=True) parser.add_argument( '-l', '--log-level', help='Log level for modules (by default for owca) in [module:]level form,' 'where level can be one of: CRITICAL,ERROR,WARNING,INFO,DEBUG,TRACE' 'Example -l debug -l example:debug. Defaults to owca:INFO.' 'Can be overridden at runtime with config.yaml "loggers" section.', default=[], action='append', dest='levels', ) parser.add_argument( '-r', '--register', action='append', dest='components', help="Register additional components in config", default=[]) parser.add_argument( '-v', '--version', action='version', version=platforms.get_owca_version(), help="Show version") parser.add_argument( '-0', '--root', help="Allow OWCA process to be run using root account", dest='is_root_allowed', action='store_true') args = parser.parse_args() # Do not allow to run OWCA with root privileges unless user indicates that it is intended. uid = os.geteuid() if uid == 0 and not args.is_root_allowed: log.fatal("Do not run OWCA with root privileges. Consult documentation " "to understand what capabilities are required. If root account " "has to be used then set --root/-0 argument to override.") exit(2) # Initialize logging subsystem from command line options. log_levels = logger.parse_loggers_from_list(args.levels) log_levels.setdefault(logger.DEFAULT_MODULE, 'info') logger.configure_loggers_from_dict(log_levels) log.warn('This software is pre-production and should not be deployed to production servers.') log.debug('started PID=%r', os.getpid()) log.info('Version owca: %s', platforms.get_owca_version()) # Register internal & external components. components.register_components(extra_components=args.components) # Initialize all necessary objects. try: configuration = config.load_config(args.config) except config.ConfigLoadError as e: log.error('Error: Cannot load config file %r: %s', args.config, e) if log.getEffectiveLevel() <= logging.DEBUG: log.exception('Detailed exception:') exit(1) # Configure loggers using configuration file. if 'loggers' in configuration: log_levels_config = configuration['loggers'] if not isinstance(log_levels, dict): log.error('Loggers configuration error: log levels are mapping from logger name to' 'log level got "%r" instead!' % log_levels_config) exit(1) # Merge config from cmd line and config file. # Overide config file values with values provided from command line. log_levels = dict(log_levels, **log_levels_config) logger.configure_loggers_from_dict(log_levels) # Dump loggers configurations to debug issues with loggers. if os.environ.get('OWCA_DUMP_LOGGERS') == 'True': print('------------------------------------ Logging tree ---------------------') import logging_tree logging_tree.printout() print('------------------------------------ Logging tree END------------------') # Extract main loop component. runner = configuration['runner'] # Prepare and run the "main loop". runner.run()