-
Notifications
You must be signed in to change notification settings - Fork 24k
allow to set an env var to undefined, aka default #75680
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devel
Are you sure you want to change the base?
Conversation
Hey, maybe a silly question, but were you intending that users would set the envvar to literally 'AnsibleUndefined'? Or that they'd be able to get an actual instance of Anyhow, here's a patch with some tests I made while fiddling with this: From 5dee184cf8987d4e8d7d8dd65ad885c4d0d6b79c Mon Sep 17 00:00:00 2001
From: Daniel Goldman <danielgoldman4@gmail.com>
Date: Sat, 2 Oct 2021 05:36:17 +0000
Subject: [PATCH] add tests for config.manager loading envvars
---
test/units/config/test.yml | 22 ++++++++++++++++++
test/units/config/test_manager.py | 38 +++++++++++++++++++++++++++++++
2 files changed, 60 insertions(+)
diff --git a/test/units/config/test.yml b/test/units/config/test.yml
index 384a055b2d..d1850362ef 100644
--- a/test/units/config/test.yml
+++ b/test/units/config/test.yml
@@ -28,6 +28,28 @@ config_entry_bool:
<<: *entry
type: bool
default: False
+config_entry_bool_default_to_true:
+ name: test config
+ default: True
+ description:
+ - This does nothing, its for testing
+ env:
+ - name: BOOL_ENVVAR
+ ini:
+ - section: defaults
+ key: bool_key
+ type: bool
+config_entry_int:
+ name: test config
+ description:
+ - This does nothing, its for testing
+ type: int
+ default: 42
+ env:
+ - name: INT_ENVVAR
+ ini:
+ - section: defaults
+ key: int_key
config_entry_list:
<<: *entry
type: list
diff --git a/test/units/config/test_manager.py b/test/units/config/test_manager.py
index a957e39749..314203411f 100644
--- a/test/units/config/test_manager.py
+++ b/test/units/config/test_manager.py
@@ -22,6 +22,8 @@ cfg_file2 = os.path.join(curdir, 'test2.cfg')
expected_ini = {'CONFIG_FILE': Setting(name='CONFIG_FILE', value=cfg_file, origin='', type='string'),
'config_entry': Setting(name='config_entry', value=u'fromini', origin=cfg_file, type='string'),
'config_entry_bool': Setting(name='config_entry_bool', value=False, origin=cfg_file, type='bool'),
+ 'config_entry_bool_default_to_true': Setting(name='config_entry_bool_default_to_true', value=True, origin='default', type='bool'),
+ 'config_entry_int': Setting(name='config_entry_int', value=42, origin='default', type='int'),
'config_entry_list': Setting(name='config_entry_list', value=['fromini'], origin=cfg_file, type='list'),
'config_entry_deprecated': Setting(name='config_entry_deprecated', value=u'fromini', origin=cfg_file, type='string'),
'config_entry_multi': Setting(name='config_entry_multi', value=u'morefromini', origin=cfg_file, type='string'),
@@ -108,6 +110,42 @@ class TestConfigManager:
def test_value_and_origin_from_alt_ini(self):
assert self.manager.get_config_value_and_origin('config_entry', cfile=cfg_file2) == ('fromini2', cfg_file2)
+ @pytest.mark.parametrize(
+ ['env_value', 'expected_value', 'expected_origin'],
+ [
+ ('fromenviron', 'fromenviron', "env: %s" % 'ENVVAR'),
+ ('', '', "env: %s" % 'ENVVAR'),
+ ('AnsibleUndefined', 'DEFAULT', 'default'),
+ ])
+ def test_value_and_origin_from_env(self, monkeypatch, env_value, expected_value, expected_origin):
+ # monkeypatching the environment has to happen through the py3compat module
+ # since py3compat._TextEnviron holds a reference to the `os.environ` dictionary
+ # and so calling setattr on `os.environ` doesn't replace the reference held by py3compat
+ # we should be able to monkeypatch `os.environ` once py3compat is deprecated
+ from ansible.utils import py3compat
+ monkeypatch.setattr(py3compat.environ, '_raw_environ', {'ENVVAR': env_value})
+
+ assert ConfigManager(None, os.path.join(curdir, 'test.yml')).get_config_value_and_origin('config_entry') == (expected_value, expected_origin)
+
+ def test_value_and_origin_from_env_empty_and_wrong_type_defaults(self, monkeypatch):
+ from ansible.utils import py3compat
+ monkeypatch.setattr(py3compat.environ, '_raw_environ', {'INT_ENVVAR': ''})
+
+ assert ConfigManager(None, os.path.join(curdir, 'test.yml')).get_config_value_and_origin('config_entry_int') == (42, 'default')
+
+ @pytest.mark.parametrize(
+ ['env_key', 'config_key', 'expected_value'],
+ [
+ ('ENVVAR', 'config_entry_bool', False),
+ ('BOOL_ENVVAR', 'config_entry_bool_default_to_true', True),
+ ])
+ def test_value_and_origin_from_env_empty_and_bool(self, monkeypatch, env_key, config_key, expected_value):
+ """Test that the empty string is not cast into a bool and the default is fallen back on"""
+ from ansible.utils import py3compat
+ monkeypatch.setattr(py3compat.environ, '_raw_environ', {env_key: ''})
+
+ assert ConfigManager(None, os.path.join(curdir, 'test.yml')).get_config_value_and_origin(config_key) == (expected_value, 'default')
+
def test_value_from_alt_ini(self):
assert self.manager.get_config_value('config_entry', cfile=cfg_file2) == 'fromini2'
--
2.25.1
|
it is meant to allow setting but not setting an env var, which should trigger a default value |
I don't think I know what it means to do that. But it sounds like that's not what those test cases test for. Can you describe how I would do that? I can then fixup the test case. Also, should we add to the docs about this feature? |
|
Ahok, gotcha. I think I was confused by the And the second piece of modified code (at the end of the function) is just to catch-and-transform the ValueError which could arise from attempting to get the default if it's an empty envvar (happening inside the first try-catch). I'll see about getting some tests in on the second part. |
I think I found a failing test case: config values requesting Booleans will cast the emptystring to False, which will be accepted as a valid boolean. This will therefore not fall back on the default value. I've updated the git patch above with these tests (and other which pass). |
the reason i'm using a specific token is that 'empty string' is a valid way of saying 'false' in shell |
Oh, gotcha, so we should expect the boolean thing to fail. So the recommended usage to force the default is to set the envvar to AnsibleUndefined. Setting the envvar to Should we include a doc fragment to that effect with this MR? |
The test
|
ISSUE TYPE
COMPONENT NAME
config