def test_is_set(mock_init): # if an option is set from kwargs, is_set() returns True, otherwise False # Note: is_set() here means 'value is set by user', which includes setting # to None or setting to the same value as the schema default. # First, test that none are set config = BaseAppConfiguration() assert not config.is_set('property1') assert not config.is_set('property2') assert not config.is_set('property3') assert not config.is_set('property4') assert not config.is_set('property5') assert not config.is_set('property6') # Now set all values, including setting to None and setting to the schema default config = BaseAppConfiguration( property1='b', # default = 'a' (overwrites default w/'a') property2=None, # default = 1 (overwrites default w/None) property3=1.0, # default = 1.0 (same as default: 1.0) property4=True, # default = True (same as default: True) property5=None, # default = None (same as default: None) property6=1) # default = None (overwrites default w/None) assert config.is_set('property1') assert config.is_set('property2') assert config.is_set('property3') assert config.is_set('property4') assert config.is_set('property4') assert config.is_set('property6')
def test_set_alt_paths(mock_init, monkeypatch): def path_exists(_, path): return True if path == 'foo' else False monkeypatch.setattr(BaseAppConfiguration, '_path_exists', path_exists) def reset_to_initial_default(): config.path1 = 'my-config/my-config-files' config = BaseAppConfiguration() # default does not exist, one alt path exists assert config.path1 == 'my-config/my-config-files' config._set_alt_paths('path1', 'foo') assert config.path1 == 'foo' # default does not exist, 2 alt paths passed, second exists reset_to_initial_default() config._set_alt_paths('path1', 'invalid', 'foo') assert config.path1 == 'foo' # default does not exist, alt paths do not exist reset_to_initial_default() config._set_alt_paths('path1', 'invalid', 'invalid-2') assert config.path1 == 'my-config/my-config-files'
def test_no_kwargs(mock_init): # Expected: use default from schema, then resolve config = BaseAppConfiguration() assert config.path1 == 'my-config/my-config-files' # resolved assert config.path2 == 'my-data/my-data-files' # resolved assert config.path3 == 'my-other-files' # no change assert config.path4 == ['my-config/conf3'] # last value resolved and listified; others dropped as files do not exist
def test_no_kwargs_listify_all_files_exist(mock_init, monkeypatch): # Expected: each value resolved and listified (mock: all files exist) monkeypatch.setattr(BaseAppConfiguration, '_path_exists', lambda a, b: True) config = BaseAppConfiguration() assert config._raw_config['path4'] == 'conf1, conf2, conf3' assert config.path4 == ['my-config/conf1', 'my-config/conf2', 'my-config/conf3']
def test_kwargs_listify(mock_init, monkeypatch): # Expected: use values from kwargs; each value resolved and listified new_path4 = 'new1, new2' config = BaseAppConfiguration(path4=new_path4) assert config._raw_config['path4'] == 'new1,new2' assert config.path4 == ['my-config/new1', 'my-config/new2']
def test_overwrite_reloadable_attribute(mock_init, monkeypatch): # This is similar to test_update_property, but here we overwrite the attribute before reloading. # This can happen if a config property is modified AFTER it has been loaded from schema or kwargs. # For example: load `foo` (from schema or kwargs), but then, in a # subsequent step while initializing # GalaxyAppConfiguration, do something like this: `foo = resove_path(foo, bar)`. Now the value of `foo` # is not what was initially loaded, and if `foo` is reloadable, it will be reset to its default as soon # as the config file is modified. To prevent this, we compare the values read from the modified file # to the `_raw_config` dict. This test ensures this works correctly. # edits to config file: R2 modified monkeypatch.setattr(config, 'read_properties_from_file', lambda _: { R1: 1, R2: 42 }) appconfig = BaseAppConfiguration() assert getattr(appconfig, R1) == 1 assert getattr(appconfig, R2) == 2 # overwrite R1 setattr(appconfig, R1, 99) assert getattr(appconfig, R1) == 99 # then reload reload_config_options(appconfig) assert getattr(appconfig, R1) == 99 # no change; should remain overwritten assert getattr(appconfig, R2) == 42 # change: reloadable option modified
def test_update_raw_config_from_kwargs_falsy_not_none(mock_init): # if kwargs supplies a falsy value, it should not evaluate to null # (ensures code is 'if value is not None' vs. 'if value') config = BaseAppConfiguration(property1=0) assert config._raw_config['property1'] == '0' # updated assert type(config._raw_config['property1']) is str # and converted to str
def test_select_one_path_from_list_all_files_exist(mock_init, monkeypatch): # Expected: all files exist, so use first file in list; value is not a list monkeypatch.setattr(BaseAppConfiguration, 'add_sample_file_to_defaults', {'path1'}) monkeypatch.setattr(BaseAppConfiguration, '_path_exists', lambda a, b: True) config = BaseAppConfiguration() assert config._raw_config['path1'] == 'my-config-files' assert config.path1 == 'my-config/my-config-files'
def test_select_one_path_from_list(mock_init, monkeypatch): # Expected: files do not exist, so use last file in list (would be sample file); value is not a list monkeypatch.setattr(BaseAppConfiguration, 'add_sample_file_to_defaults', {'path1'}) monkeypatch.setattr(BaseAppConfiguration, '_in_sample_dir', lambda a, path: '/sample-dir/%s' % path) config = BaseAppConfiguration() assert config._raw_config['path1'] == 'my-config-files' assert config.path1 == '/sample-dir/my-config-files.sample'
def test_kwargs_relative_path_old_prefix_csv_value(mock_init): # Expect: use value from kwargs, split at commas, then for each path strip # spaces, strip old prefix if needed, and resolve if needed config = BaseAppConfiguration( path4='old-config/foo/file1 , /foo1/bar, foo/file3') assert config.path4 == [ 'my-config/foo/file1', '/foo1/bar', 'my-config/foo/file3' ]
def test_kwargs_relative_path_old_prefix_empty_after_strip(mock_init): # Expect: use value from kwargs, strip old prefix, then resolve new_path1 = 'old-config' config = BaseAppConfiguration(path1=new_path1) assert config.path1 == 'my-config/' # stripped of old prefix, then resolved assert config.path2 == 'my-data/my-data-files' # stripped of old prefix, then resolved assert config.path3 == 'my-other-files' # no change
def test_kwargs_absolute_path(mock_init): # Expected: use value from kwargs, do NOT resolve new_path1 = '/foo1/bar' new_path2 = '/foo2/bar' config = BaseAppConfiguration(path1=new_path1, path2=new_path2) assert config.path1 == new_path1 # NOT resolved assert config.path2 == new_path2 # NOT resolved assert config.path3 == 'my-other-files' # no change
def test_kwargs_relative_path_old_prefix(mock_init): # Expect: use value from kwargs, strip old prefix, then resolve new_path1 = 'old-config/foo1/bar' new_path2 = 'old-database/foo2/bar' config = BaseAppConfiguration(path1=new_path1, path2=new_path2) assert config.path1 == 'my-config/foo1/bar' # stripped of old prefix, resolved assert config.path2 == 'my-data/foo2/bar' # stripped of old prefix, resolved assert config.path3 == 'my-other-files' # no change
def test_check_against_root_list_of_paths(mock_check_against_root): # 1. Set path4='foo, bar' # 2. It is resolved to ['my-config/foo', 'my-config/bar'] # 3. path4 is in paths to check against root # 4. both paths do not exist, so both are re-resolved w.r.t root # 5. 'root/foo' exists, so config.path4 is set to ['root/foo', 'my-config/bar'] config = BaseAppConfiguration(path4='foo, bar') assert config.path4 == ['root/foo', 'my-config/bar']
def test_kwargs_relative_path(mock_init): # Expected: use value from kwargs, then resolve new_path1 = 'foo1/bar' new_path2 = 'foo2/bar' config = BaseAppConfiguration(path1=new_path1, path2=new_path2) assert config.path1 == 'my-config/' + new_path1 # resolved assert config.path2 == 'my-data/' + new_path2 # resolved assert config.path3 == 'my-other-files' # no change
def test_check_against_root_single_path(mock_check_against_root): # 1. Set path1='foo' # 2. It is resolved to 'my-config/foo' # 3. path1 is in paths to check against root # 4. 'my-config/foo' does not exist, so 'foo' is re-resolved w.r.t root # 5. 'root/foo' exists, so config.path1 is set to 'root/foo' config = BaseAppConfiguration(path1='foo') assert config.path1 == 'root/foo'
def test_kwargs_set_to_null(mock_init): # Expected: allow overriding with null, then resolve # This is not a common scenario, but it does happen: one example is # `job_config` set to `None` when testing config = BaseAppConfiguration(path1=None) assert config.path1 == 'my-config' # resolved assert config.path2 == 'my-data/my-data-files' # resolved assert config.path3 == 'my-other-files' # no change
def test_mock_schema_is_loaded(mock_init): # Check that mock is loaded as expected config = BaseAppConfiguration() assert len(config._raw_config) == 6 assert config._raw_config['my_config_dir'] == 'my-config' assert config._raw_config['my_data_dir'] == 'my-data' assert config._raw_config['path1'] == 'my-config-files' assert config._raw_config['path2'] == 'my-data-files' assert config._raw_config['path3'] == 'my-other-files' assert config._raw_config['path4'] == 'conf1, conf2, conf3'
def test_kwargs_relative_path_old_prefix_for_other_option(mock_init): # Expect: use value from kwargs, do NOT strip old prefix, then resolve # Reason: deprecated dirs are option-specific: we don't want to strip 'old-config' # (deprecated for the config_dir option) if it's used for another option new_path1 = 'old-database/foo1/bar' new_path2 = 'old-config/foo2/bar' config = BaseAppConfiguration(path1=new_path1, path2=new_path2) assert config.path1 == 'my-config/' + new_path1 # resolved assert config.path2 == 'my-data/' + new_path2 # resolved assert config.path3 == 'my-other-files' # no change
def test_update_raw_config_from_kwargs_with_none(mock_init): # should be able to set to null regardless of property's datatype config = BaseAppConfiguration( property1=None, property2=None, property3=None, property4=None, property5=None, property6=None, ) assert config._raw_config['property1'] is None assert config._raw_config['property2'] is None assert config._raw_config['property3'] is None assert config._raw_config['property4'] is None assert config._raw_config['property5'] is None assert config._raw_config['property6'] is None
def test_add_sample_file(mock_init, monkeypatch): # Expected: sample file appended to list of defaults: # - resolved w.r.t sample-dir (_in_sample_dir mocked) # - has ".sample" suffix # Last value (sample file) resolved and listified; others dropped as files do not exist monkeypatch.setattr(BaseAppConfiguration, 'add_sample_file_to_defaults', {'path1', 'path4'}) monkeypatch.setattr(BaseAppConfiguration, '_in_sample_dir', lambda a, path: '/sample-dir/%s' % path) config = BaseAppConfiguration() assert config._raw_config['path1'] == 'my-config-files' assert config.path1 == '/sample-dir/my-config-files.sample' assert config._raw_config['path4'] == 'conf1, conf2, conf3' assert config.path4 == ['/sample-dir/conf3.sample']
def test_update_raw_config_from_string_kwargs(mock_init): # kwargs may be passed as strings: property data types should not be affected config = BaseAppConfiguration(property1='b', property2='2', property3='2.0', property4='false') assert len(config._raw_config) == 6 # no change assert config._raw_config['property1'] == 'b' # updated assert config._raw_config['property2'] == 2 # updated assert config._raw_config['property3'] == 2.0 # updated assert config._raw_config['property4'] is False # updated assert type(config._raw_config['property1']) is str assert type(config._raw_config['property2']) is int assert type(config._raw_config['property3']) is float assert type(config._raw_config['property4']) is bool
def test_load_config_from_schema(mock_init): config = BaseAppConfiguration() assert len(config._raw_config) == 6 assert config._raw_config['property1'] == 'a' assert config._raw_config['property2'] == 1 assert config._raw_config['property3'] == 1.0 assert config._raw_config['property4'] is True assert config._raw_config['property5'] is None assert config._raw_config['property6'] is None assert type(config._raw_config['property1']) is str assert type(config._raw_config['property2']) is int assert type(config._raw_config['property3']) is float assert type(config._raw_config['property4']) is bool
def test_update_raw_config_from_kwargs(mock_init): config = BaseAppConfiguration(property2=2, property3=2.0, another_key=66) assert len(config._raw_config) == 6 # no change: another_key NOT added assert config._raw_config['property1'] == 'a' # no change assert config._raw_config['property2'] == 2 # updated assert config._raw_config['property3'] == 2.0 # updated assert config._raw_config['property4'] is True # no change assert config._raw_config['property5'] is None # no change assert config._raw_config['property6'] is None # no change assert type(config._raw_config['property1']) is str assert type(config._raw_config['property2']) is int assert type(config._raw_config['property3']) is float assert type(config._raw_config['property4']) is bool
def test_update_property(mock_init, monkeypatch): # This also covers adding a property. When a config file does not set a property, # that property is set to its default value. Thus, if we add a reloadable property # to the config file, it's the same as modifying that property's value. # edits to config file: R2, N1 modified monkeypatch.setattr(config, 'read_properties_from_file', lambda _: { R1: 1, R2: 42, N1: 99 }) appconfig = BaseAppConfiguration() assert getattr(appconfig, R1) == 1 assert getattr(appconfig, R2) == 2 assert getattr(appconfig, N1) == 3 reload_config_options(appconfig) assert getattr(appconfig, R1) == 1 # no change assert getattr(appconfig, R2) == 42 # change: reloadable option modified assert getattr(appconfig, N1) == 3 # no change: option modified but is non-relodable
def test_basecase(monkeypatch): # Check that a valid graph is loaded correctly (this graph has 2 components) mock_schema = { 'component1_path0': { 'type': 'str', 'default': 'value0', }, 'component1_path1': { 'type': 'str', 'default': 'value1', 'path_resolves_to': 'component1_path0', }, 'component1_path2': { 'type': 'str', 'default': 'value2', 'path_resolves_to': 'component1_path1', }, 'component2_path0': { 'type': 'str', 'default': 'value3', }, 'component2_path1': { 'type': 'str', 'default': 'value4', 'path_resolves_to': 'component2_path0', }, } monkeypatch.setattr(AppSchema, '_read_schema', lambda a, b: get_schema(mock_schema)) monkeypatch.setattr(BaseAppConfiguration, '_load_schema', lambda a: AppSchema(None, '_')) config = BaseAppConfiguration() assert config.component1_path0 == 'value0' assert config.component1_path1 == 'value0/value1' assert config.component1_path2 == 'value0/value1/value2' assert config.component2_path0 == 'value3' assert config.component2_path1 == 'value3/value4'
def test_cant_delete_property(mock_init, monkeypatch): # A property should not be deleted: we don't know whether it was initially # set to a default, loaded from a config file, env var, etc. Therefore, if a property # is removed from the config file, it will not be modified or deleted. # edits to config file: R2, N2 deleted monkeypatch.setattr(config, 'read_properties_from_file', lambda _: { R1: 1, N1: 3 }) appconfig = BaseAppConfiguration() assert getattr(appconfig, R1) == 1 assert getattr(appconfig, R2) == 2 assert getattr(appconfig, N1) == 3 assert getattr(appconfig, N2) == 4 reload_config_options(appconfig) assert getattr(appconfig, R1) == 1 # no change assert getattr(appconfig, R2) == 2 # no change: option cannot be deleted assert getattr(appconfig, N1) == 3 # no change assert getattr(appconfig, N2) == 4 # no change: option cannot be deleted
def test_resolves_with_empty_component(monkeypatch): # A path can be None (root path is never None; may be asigned elsewhere) mock_schema = { 'path0': { 'type': 'str', 'default': 'value0', }, 'path1': { 'type': 'str', 'path_resolves_to': 'path0', }, 'path2': { 'type': 'str', 'default': 'value2', 'path_resolves_to': 'path1', }, } monkeypatch.setattr(AppSchema, '_read_schema', lambda a, b: get_schema(mock_schema)) monkeypatch.setattr(BaseAppConfiguration, '_load_schema', lambda a: AppSchema(None, '_')) config = BaseAppConfiguration() assert config.path0 == 'value0' assert config.path1 == 'value0' assert config.path2 == 'value0/value2'
def test_unset_renamed_option_set_by_old_option(mock_init, monkeypatch): monkeypatch.setattr(BaseAppConfiguration, 'renamed_options', {'old_property1': 'property1'}) config = BaseAppConfiguration(old_property1='b') assert config._raw_config['property1'] == 'b'
def test_no_kwargs_listify(mock_init, monkeypatch): # Expected: last value resolved and listified; others dropped as files do not exist config = BaseAppConfiguration() assert config._raw_config['path4'] == 'conf1, conf2, conf3' assert config.path4 == ['my-config/conf3']