This is an automated email from the ASF dual-hosted git repository.

seanmccarthy pushed a commit to branch sm-otava-82
in repository https://gitbox.apache.org/repos/asf/otava.git

commit 46ae395020a6eb7967932f1e0ddb88bde1116bc9
Author: Sean McCarthy <sean.mccarthy....@gmail.com>
AuthorDate: Tue Aug 19 13:01:42 2025 -0400

    cover all properties in unit tests, replace snake case yaml keys with dash 
cli flag style, fixup bigquery project_id to match config from example
---
 otava/bigquery.py    |  4 +--
 otava/config.py      |  4 +++
 tests/config_test.py | 72 +++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/otava/bigquery.py b/otava/bigquery.py
index c3d6f4e..c9b77a6 100644
--- a/otava/bigquery.py
+++ b/otava/bigquery.py
@@ -34,14 +34,14 @@ class BigQueryConfig:
 
     @staticmethod
     def add_parser_args(arg_group):
-        arg_group.add_argument("--bigquery-project", help="BigQuery project 
ID", env_var="BIGQUERY_PROJECT_ID")
+        arg_group.add_argument("--bigquery-project-id", help="BigQuery project 
ID", env_var="BIGQUERY_PROJECT_ID")
         arg_group.add_argument("--bigquery-dataset", help="BigQuery dataset", 
env_var="BIGQUERY_DATASET")
         arg_group.add_argument("--bigquery-credentials", help="BigQuery 
credentials file", env_var="BIGQUERY_VAULT_SECRET")
 
     @staticmethod
     def from_parser_args(args):
         return BigQueryConfig(
-            project_id=getattr(args, 'bigquery_project', None),
+            project_id=getattr(args, 'bigquery_project_id', None),
             dataset=getattr(args, 'bigquery_dataset', None),
             credentials=getattr(args, 'bigquery_credentials', None)
         )
diff --git a/otava/config.py b/otava/config.py
index 7a76b46..c0e8d54 100644
--- a/otava/config.py
+++ b/otava/config.py
@@ -144,6 +144,10 @@ class 
NestedYAMLConfigFileParser(configargparse.ConfigFileParser):
         for key, value in nested_dict.items():
             new_key = f"{prefix}{key}" if prefix else key
 
+            # yaml keys typically use snake case
+            # replace underscore with dash to convert snake case to CLI 
dash-separated style
+            new_key = new_key.replace("_", "-")
+
             if isinstance(value, dict):
                 # Recursively process nested dictionaries
                 self._flatten_dict(value, flattened_dict, f"{new_key}-")
diff --git a/tests/config_test.py b/tests/config_test.py
index d8566f2..f1e4a1b 100644
--- a/tests/config_test.py
+++ b/tests/config_test.py
@@ -16,6 +16,8 @@
 # under the License.
 import os
 
+import pytest
+
 from otava.config import load_config_from_file
 from otava.test_config import CsvTestConfig, GraphiteTestConfig, 
HistoStatTestConfig
 
@@ -75,29 +77,59 @@ def test_load_histostat_config():
     assert len(test.fully_qualified_metric_names()) == 168
 
 
-def test_load_config_without_substitutions():
-    config = 
load_config_from_file("tests/resources/substitution_test_config.yaml")
-    assert config.slack.bot_token == "config_slack_token"
-
-
-def test_load_config_with_env_var_substitutions():
-    os.environ["SLACK_BOT_TOKEN"] = "env_slack_token"
+@pytest.mark.parametrize(
+    "config_property",
+    [
+        # property, accessor, env_var, cli_flag, [config value, env value, cli 
value]
+        ("slack_token", lambda c: c.slack.bot_token, "SLACK_BOT_TOKEN", 
"--slack-token"),
+        ("bigquery_project_id", lambda c: c.bigquery.project_id, 
"BIGQUERY_PROJECT_ID", "--bigquery-project-id"),
+        ("bigquery_dataset", lambda c: c.bigquery.dataset, "BIGQUERY_DATASET", 
"--bigquery-dataset"),
+        ("bigquery_credentials", lambda c: c.bigquery.credentials, 
"BIGQUERY_VAULT_SECRET", "--bigquery-credentials"),
+        ("grafana_url", lambda c: c.grafana.url, "GRAFANA_ADDRESS", 
"--grafana-url"),
+        ("grafana_user", lambda c: c.grafana.user, "GRAFANA_USER", 
"--grafana-user"),
+        ("grafana_password", lambda c: c.grafana.password, "GRAFANA_PASSWORD", 
"--grafana-password"),
+        ("graphite_url", lambda c: c.graphite.url, "GRAPHITE_ADDRESS", 
"--graphite-url"),
+        ("postgres_hostname", lambda c: c.postgres.hostname, 
"POSTGRES_HOSTNAME", "--postgres-hostname"),
+        ("postgres_port", lambda c: c.postgres.port, "POSTGRES_PORT", 
"--postgres-port", 1111, 2222, 3333),
+        ("postgres_username", lambda c: c.postgres.username, 
"POSTGRES_USERNAME", "--postgres-username"),
+        ("postgres_password", lambda c: c.postgres.password, 
"POSTGRES_PASSWORD", "--postgres-password"),
+        ("postgres_database", lambda c: c.postgres.database, 
"POSTGRES_DATABASE", "--postgres-database"),
+    ],
+    ids=lambda v: v[0],  # use the property name for the parameterized test 
name
+)
+def test_configuration_substitutions(config_property):
+    config_file = "tests/resources/substitution_test_config.yaml"
+    accessor = config_property[1]
+
+    if len(config_property) == 4:
+        config_value = f"config_{config_property[0]}"
+        env_config_value = f"env_{config_property[0]}"
+        cli_config_value = f"cli_{config_property[0]}"
+    else:
+        config_value = config_property[4]
+        env_config_value = config_property[5]
+        cli_config_value = config_property[6]
+
+    # test value from config file
+    config = load_config_from_file(config_file)
+    assert accessor(config) == config_value
+
+    # test env var overrides values from config file
+    os.environ[config_property[2]] = str(env_config_value)
     try:
-        config = 
load_config_from_file("tests/resources/substitution_test_config.yaml")
-        assert config.slack.bot_token == "env_slack_token"
+        config = load_config_from_file(config_file)
+        assert accessor(config) == env_config_value
     finally:
-        os.environ.pop("SLACK_BOT_TOKEN")
-
-
-def test_load_config_with_cli_substitutions():
-    config = 
load_config_from_file("tests/resources/substitution_test_config.yaml", 
arg_overrides=["--slack-token", "cli_slack_token"])
-    assert config.slack.bot_token == "cli_slack_token"
+        os.environ.pop(config_property[2])
 
+    # test cli values override values from config file
+    config = load_config_from_file(config_file, 
arg_overrides=[config_property[3], str(cli_config_value)])
+    assert accessor(config) == cli_config_value
 
-def test_load_config_cli_precedence_over_env_var():
-    os.environ["SLACK_BOT_TOKEN"] = "env_slack_token"
+    # test cli values override values from config file and env var
+    os.environ[config_property[2]] = str(env_config_value)
     try:
-        config = 
load_config_from_file("tests/resources/substitution_test_config.yaml", 
arg_overrides=["--slack-token", "cli_slack_token"])
-        assert config.slack.bot_token == "cli_slack_token"
+        config = load_config_from_file(config_file, 
arg_overrides=[config_property[3], str(cli_config_value)])
+        assert accessor(config) == cli_config_value
     finally:
-        os.environ.pop("SLACK_BOT_TOKEN")
+        os.environ.pop(config_property[2])

Reply via email to