コード例 #1
0
def test_cli_compact_settings_envs(
    cli: typer.Typer,
    fake_settings_class: Type[BaseCustomSettings],
    fake_granular_env_file_content: str,
    export_as_dict: Callable,
    cli_runner: CliRunner,
    monkeypatch: pytest.MonkeyPatch,
):

    with monkeypatch.context() as patch:
        mocked_envs_1: EnvVarsDict = setenvs_as_envfile(
            patch, fake_granular_env_file_content
        )

        settings_1 = fake_settings_class()

        settings_1_dict_wo_secrets = export_as_dict(settings_1)
        assert settings_1_dict_wo_secrets == {
            "APP_HOST": "localhost",
            "APP_PORT": 80,
            "APP_OPTIONAL_ADDON": {"MODULE_VALUE": 10, "MODULE_VALUE_DEFAULT": 42},
            "APP_REQUIRED_PLUGIN": {
                "POSTGRES_HOST": "localhost",
                "POSTGRES_PORT": 5432,
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "foodb",
                "POSTGRES_MINSIZE": 1,
                "POSTGRES_MAXSIZE": 50,
                "POSTGRES_CLIENT_NAME": None,
            },
        }

        setting_env_content_compact = cli_runner.invoke(
            cli,
            ["settings", "--compact", "--show-secrets"],
            catch_exceptions=False,
        ).stdout

    # now we use these as env vars
    print(setting_env_content_compact)

    with monkeypatch.context() as patch:
        mocked_envs_2: EnvVarsDict = setenvs_as_envfile(
            patch,
            setting_env_content_compact,
        )

        assert mocked_envs_2 == {
            "APP_HOST": "localhost",
            "APP_PORT": "80",
            "APP_OPTIONAL_ADDON": '{"MODULE_VALUE": 10, "MODULE_VALUE_DEFAULT": 42}',
            "APP_REQUIRED_PLUGIN": '{"POSTGRES_HOST": "localhost", "POSTGRES_PORT": 5432, "POSTGRES_USER": "******", "POSTGRES_PASSWORD": "******", "POSTGRES_DB": "foodb", "POSTGRES_MINSIZE": 1, "POSTGRES_MAXSIZE": 50, "POSTGRES_CLIENT_NAME": null}',
        }

        settings_2 = fake_settings_class()
        assert settings_1 == settings_2
コード例 #2
0
def test_granular_format(monkeypatch, fake_settings_class):
    setenvs_as_envfile(
        monkeypatch,
        """
    APP_HOST=localhost
    APP_PORT=80

    # --- APP_OPTIONAL_ADDON ---
    MODULE_VALUE=10
    MODULE_VALUE_DEFAULT=42

    # --- APP_REQUIRED_PLUGIN ---
    POSTGRES_HOST=localhost
    POSTGRES_PORT=5432
    POSTGRES_USER=foo
    POSTGRES_PASSWORD=secret
    # Database name
    POSTGRES_DB=foodb
    # Minimum number of connections in the pool
    POSTGRES_MINSIZE=1
    # Maximum number of connections in the pool
    POSTGRES_MAXSIZE=50
    # Name of the application connecting the postgres database, will default to use the host hostname (hostname on linux)
    POSTGRES_CLIENT_NAME=None
    """,
    )

    settings_from_envs = fake_settings_class()

    assert settings_from_envs == fake_settings_class(
        APP_HOST="localhost",
        APP_PORT=80,
        APP_OPTIONAL_ADDON={
            "MODULE_VALUE": 10,
            "MODULE_VALUE_DEFAULT": 42
        },
        APP_REQUIRED_PLUGIN={
            "POSTGRES_HOST": "localhost",
            "POSTGRES_PORT": 5432,
            "POSTGRES_USER": "******",
            "POSTGRES_PASSWORD": "******",
            "POSTGRES_DB": "foodb",
            "POSTGRES_MINSIZE": 1,
            "POSTGRES_MAXSIZE": 50,
            "POSTGRES_CLIENT_NAME": None,
        },
    )
コード例 #3
0
def test_cli_default_settings_envs(
    cli: typer.Typer,
    fake_settings_class: Type[BaseCustomSettings],
    fake_granular_env_file_content: str,
    cli_runner: CliRunner,
    monkeypatch,
):
    with monkeypatch.context() as patch:
        mocked_envs_1: EnvVarsDict = setenvs_as_envfile(
            patch, fake_granular_env_file_content)

        cli_settings_output = cli_runner.invoke(
            cli,
            ["settings", "--show-secrets"],
        ).stdout

    # now let's use these as env vars
    print(cli_settings_output)

    with monkeypatch.context() as patch:
        mocked_envs_2: EnvVarsDict = setenvs_as_envfile(
            patch,
            cli_settings_output,
        )
        settings_object = fake_settings_class()
        assert settings_object

        # NOTE: SEE BaseCustomSettings.Config.json_encoder for SecretStr
        settings_dict_wo_secrets = json.loads(settings_object.json(indent=2))
        assert settings_dict_wo_secrets == {
            "APP_HOST": "localhost",
            "APP_PORT": 80,
            "APP_OPTIONAL_ADDON": {
                "MODULE_VALUE": 10,
                "MODULE_VALUE_DEFAULT": 42
            },
            "APP_REQUIRED_PLUGIN": {
                "POSTGRES_HOST": "localhost",
                "POSTGRES_PORT": 5432,
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "foodb",
                "POSTGRES_MINSIZE": 1,
                "POSTGRES_MAXSIZE": 50,
                "POSTGRES_CLIENT_NAME": None,
            },
        }
コード例 #4
0
def test_toggle_plugin_4(monkeypatch, model_classes_factory):

    *_, S4, S5 = model_classes_factory()
    JSON_VALUE = '{"POSTGRES_HOST":"pg2", "POSTGRES_USER":"******", "POSTGRES_PASSWORD":"******", "POSTGRES_DB":"db2"}'

    with monkeypatch.context() as patch:
        # Enables both
        setenvs_as_envfile(
            patch,
            f"""
            WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV='{JSON_VALUE}'
            WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL='{JSON_VALUE}'

            POSTGRES_HOST=pg
            POSTGRES_USER=test
            POSTGRES_PASSWORD=ssh
            POSTGRES_DB=db
            POSTGRES_CLIENT_NAME=name-is-now-set
            """,
        )
        s4 = S4()
        s5 = S5()

        assert s4.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV is not None
        assert s5.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL is not None
        assert (s4.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV ==
                s5.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL)

    with monkeypatch.context() as patch:

        # Enables both but remove individuals
        setenvs_as_envfile(
            patch,
            f"""
            WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV='{JSON_VALUE}'
            WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL='{JSON_VALUE}'
            """,
        )
        s4 = S4()
        s5 = S5()

        assert s4.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV is not None
        assert s5.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL is not None
        assert (s4.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV ==
                s5.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL)
コード例 #5
0
def test_toggle_plugin_2(monkeypatch, model_classes_factory):
    *_, S4, S5 = model_classes_factory()

    # minimal
    setenvs_as_envfile(
        monkeypatch,
        """
        POSTGRES_HOST=pg
        POSTGRES_USER=test
        POSTGRES_PASSWORD=ssh
        POSTGRES_DB=db
    """,
    )

    s4 = S4()
    s5 = S5()  # disabled by default

    assert s4.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV is not None
    assert s5.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL is None
コード例 #6
0
def test_toggle_plugin_3(monkeypatch, model_classes_factory):
    *_, S4, S5 = model_classes_factory()

    # explicitly disables
    setenvs_as_envfile(
        monkeypatch,
        """
        WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV=null

        POSTGRES_HOST=pg
        POSTGRES_USER=test
        POSTGRES_PASSWORD=ssh
        POSTGRES_DB=db
        """,
    )

    s4 = S4()
    s5 = S5()

    assert s4.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV is None
    assert s5.WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL is None
コード例 #7
0
def test_compact_format(monkeypatch, fake_settings_class):
    compact_envs: EnvVarsDict = setenvs_as_envfile(
        monkeypatch,
        """
        APP_HOST=localhost
        APP_PORT=80
        APP_OPTIONAL_ADDON='{"MODULE_VALUE": 10, "MODULE_VALUE_DEFAULT": 42}'
        APP_REQUIRED_PLUGIN='{"POSTGRES_HOST": "localhost", "POSTGRES_PORT": 5432, "POSTGRES_USER": "******", "POSTGRES_PASSWORD": "******", "POSTGRES_DB": "foodb", "POSTGRES_MINSIZE": 1, "POSTGRES_MAXSIZE": 50, "POSTGRES_CLIENT_NAME": "None"}'
        """,
    )

    settings_from_envs1 = fake_settings_class()
    settings_from_init = fake_settings_class(**envs_to_kwargs(compact_envs))

    assert settings_from_envs1 == settings_from_init
コード例 #8
0
def test_cli_settings_exclude_unset_as_json(
    cli: typer.Typer,
    cli_runner: CliRunner,
    monkeypatch: pytest.MonkeyPatch,
):
    # minimal envfile
    mocked_envs: EnvVarsDict = setenvs_as_envfile(
        monkeypatch,
        """
        # these are required
        APP_HOST=localhost
        APP_PORT=80

        # --- APP_REQUIRED_PLUGIN ---
        # these are required
        POSTGRES_HOST=localhost
        POSTGRES_PORT=5432
        POSTGRES_USER=foo
        POSTGRES_PASSWORD=secret
        POSTGRES_DB=foodb

        # this is optional but set
        POSTGRES_MAXSIZE=20
        """,
    )
    stdout_as_json = cli_runner.invoke(
        cli,
        ["settings", "--show-secrets", "--exclude-unset", "--as-json"],
        catch_exceptions=False,
    ).stdout
    print(stdout_as_json)

    # parsing output as json file
    envs_exclude_unset_from_json = json.loads(stdout_as_json)
    assert envs_exclude_unset_from_json == {
        "APP_HOST": "localhost",
        "APP_PORT": 80,
        "APP_REQUIRED_PLUGIN": {
            "POSTGRES_HOST": "localhost",
            "POSTGRES_PORT": 5432,
            "POSTGRES_USER": "******",
            "POSTGRES_PASSWORD": "******",
            "POSTGRES_DB": "foodb",
            "POSTGRES_MAXSIZE": 20,
        },
    }
コード例 #9
0
def test_cli_settings_exclude_unset(
    cli: typer.Typer,
    cli_runner: CliRunner,
    monkeypatch: pytest.MonkeyPatch,
):
    # minimal envfile
    mocked_envs: EnvVarsDict = setenvs_as_envfile(
        monkeypatch,
        """
        # these are required
        APP_HOST=localhost
        APP_PORT=80

        # --- APP_REQUIRED_PLUGIN ---
        # these are required
        POSTGRES_HOST=localhost
        POSTGRES_PORT=5432
        POSTGRES_USER=foo
        POSTGRES_PASSWORD=secret
        POSTGRES_DB=foodb

        # this is optional but set
        POSTGRES_MAXSIZE=20
        """,
    )

    # using exclude-unset
    stdout_as_envfile = cli_runner.invoke(
        cli,
        ["settings", "--show-secrets", "--exclude-unset"],
        catch_exceptions=False,
    ).stdout
    print(stdout_as_envfile)

    # parsing output as an envfile
    envs_exclude_unset_from_env: EnvVarsDict = dotenv_values(
        stream=StringIO(stdout_as_envfile)
    )
    assert envs_exclude_unset_from_env == mocked_envs
コード例 #10
0
def test_parse_from_mixed_envs(monkeypatch, model_classes_factory):

    S1, S2, S3, S4, S5 = model_classes_factory()

    # environment
    # - Mixed with json (compact) AND postgres envs
    ENV_FILE = """
            {0}='{{"POSTGRES_HOST":"pg2", "POSTGRES_USER":"******", "POSTGRES_PASSWORD":"******", "POSTGRES_DB":"db2"}}'

            POSTGRES_HOST=pg
            POSTGRES_USER=test
            POSTGRES_PASSWORD=ssh
            POSTGRES_DB=db
            POSTGRES_CLIENT_NAME=client-name
        """

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            monkeypatch,
            ENV_FILE.format("WEBSERVER_POSTGRES"),
        )

        s1 = S1()

        assert s1.dict() == {
            "WEBSERVER_POSTGRES": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PORT": 5432,
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
                "POSTGRES_MAXSIZE": 50,
                "POSTGRES_MINSIZE": 1,
                "POSTGRES_CLIENT_NAME": "client-name",
            }
        }
        # NOTE how unset marks also applies to embedded fields
        # NOTE: (1) priority of json-compact over granulated
        # NOTE: (2) json-compact did not define this but granulated did
        assert s1.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES": {
                "POSTGRES_HOST": "pg2",  # <- (1)
                "POSTGRES_USER": "******",  # <- (1)
                "POSTGRES_PASSWORD": "******",  # <- (1)
                "POSTGRES_DB": "db2",  # <- (1)
                "POSTGRES_CLIENT_NAME": "client-name",  # <- (2)
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            monkeypatch,
            ENV_FILE.format("WEBSERVER_POSTGRES_NULLABLE_OPTIONAL"),
        )

        s2 = S2()
        assert s2.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_NULLABLE_OPTIONAL": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
                "POSTGRES_CLIENT_NAME": "client-name",
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            monkeypatch,
            ENV_FILE.format("WEBSERVER_POSTGRES_DEFAULT_ENV"),
        )

        s3 = S3()
        assert s3.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_DEFAULT_ENV": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
                "POSTGRES_CLIENT_NAME": "client-name",
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            monkeypatch,
            ENV_FILE.format("WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV"),
        )

        s4 = S4()
        assert s4.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
                "POSTGRES_CLIENT_NAME": "client-name",
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            monkeypatch,
            ENV_FILE.format("WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL"),
        )

        s5 = S5()
        assert s5.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
                "POSTGRES_CLIENT_NAME": "client-name",
            }
        }
コード例 #11
0
def test_parse_compact_env(monkeypatch, model_classes_factory):

    S1, S2, S3, S4, S5 = model_classes_factory()

    # environment
    # - with json (compact)
    JSON_VALUE = '{"POSTGRES_HOST":"pg2", "POSTGRES_USER":"******", "POSTGRES_PASSWORD":"******", "POSTGRES_DB":"db2"}'

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            patch,
            f"""
                WEBSERVER_POSTGRES='{JSON_VALUE}'
            """,
        )

        # test
        s1 = S1()

        assert s1.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
            }
        }
        assert s1.dict() == {
            "WEBSERVER_POSTGRES": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PORT": 5432,
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
                "POSTGRES_MAXSIZE": 50,
                "POSTGRES_MINSIZE": 1,
                "POSTGRES_CLIENT_NAME": None,
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            patch,
            f"""
                WEBSERVER_POSTGRES_NULLABLE_OPTIONAL='{JSON_VALUE}'
            """,
        )
        s2 = S2()
        assert s2.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_NULLABLE_OPTIONAL": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            patch,
            f"""
                WEBSERVER_POSTGRES_DEFAULT_ENV='{JSON_VALUE}'
            """,
        )
        # NOTE: pydantic 1.9 does it right: it delays evaluating
        # default until it is really needed. Here before it would
        # fail because default cannot be computed even if the final value can!
        s3 = S3()
        assert s3.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_DEFAULT_ENV": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            patch,
            f"""
                WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV='{JSON_VALUE}'
            """,
        )
        s4 = S4()
        assert s4.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
            }
        }

    with monkeypatch.context() as patch:
        setenvs_as_envfile(
            patch,
            f"""
                WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL='{JSON_VALUE}'
            """,
        )
        s5 = S5()
        assert s5.dict(exclude_unset=True) == {
            "WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL": {
                "POSTGRES_HOST": "pg2",
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "POSTGRES_DB": "db2",
            }
        }
コード例 #12
0
def test_parse_from_individual_envs(monkeypatch, model_classes_factory):

    S1, S2, S3, S4, S5 = model_classes_factory()

    # environment
    #  - with individual envs (PostgresSettings required fields)
    setenvs_as_envfile(
        monkeypatch,
        """
            POSTGRES_HOST=pg
            POSTGRES_USER=test
            POSTGRES_PASSWORD=shh
            POSTGRES_DB=db
        """,
    )

    with pytest.raises(ValidationError) as exc_info:
        S1()

    assert exc_info.value.errors()[0] == {
        "loc": ("WEBSERVER_POSTGRES", ),
        "msg": "field required",
        "type": "value_error.missing",
    }

    s2 = S2()
    assert s2.dict(exclude_unset=True) == {}
    assert s2.dict() == {"WEBSERVER_POSTGRES_NULLABLE_OPTIONAL": None}

    s3 = S3()
    assert s3.dict(exclude_unset=True) == {}
    assert s3.dict() == {
        "WEBSERVER_POSTGRES_DEFAULT_ENV": {
            "POSTGRES_HOST": "pg",
            "POSTGRES_USER": "******",
            "POSTGRES_PORT": 5432,
            "POSTGRES_PASSWORD": "******",
            "POSTGRES_DB": "db",
            "POSTGRES_MAXSIZE": 50,
            "POSTGRES_MINSIZE": 1,
            "POSTGRES_CLIENT_NAME": None,
        }
    }

    s4 = S4()
    assert s4.dict(exclude_unset=True) == {}
    assert s4.dict() == {
        "WEBSERVER_POSTGRES_NULLABLE_DEFAULT_ENV": {
            "POSTGRES_HOST": "pg",
            "POSTGRES_USER": "******",
            "POSTGRES_PORT": 5432,
            "POSTGRES_PASSWORD": "******",
            "POSTGRES_DB": "db",
            "POSTGRES_MAXSIZE": 50,
            "POSTGRES_MINSIZE": 1,
            "POSTGRES_CLIENT_NAME": None,
        }
    }

    s5 = S5()
    assert s5.dict(exclude_unset=True) == {}
    assert s5.dict() == {"WEBSERVER_POSTGRES_NULLABLE_DEFAULT_NULL": None}