Exemple #1
0
def test_accessing_non_existant_config_parameter(random_integer):
    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = Default(random_integer)

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    with pytest.raises(ParameterError):
        config["bar"]

    with pytest.raises(ParameterError):
        config.bar

    assert config.get("bar") is None
Exemple #2
0
def test_aws_paramater(aws_parameter_fixtures, random_string):
    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = aws.Parameter(path="/foo/bar/baz")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    assert config.foo == random_string
Exemple #3
0
def test_vault_secret(vault_secret_fixtures, random_string):
    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = vault.Secret(path="/foo/bar/baz", field="my-secret")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    assert config.foo == random_string
Exemple #4
0
def test_default(environ, random_string):
    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = Default(value=random_string)

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    assert config["foo"] == random_string
    assert config.foo == random_string
Exemple #5
0
def test_env(environ, random_string):
    environ["BAR"] = random_string

    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = Env(path="BAR")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    assert config["foo"] == random_string
    assert config.foo == random_string
Exemple #6
0
def test_preloading_config(environ):
    """If all sources are ok preloading is successful."""
    environ["FOO"] = "123"

    class ConfigSpec(Spec):
        foo: str
        bar: str

    class SourceSpec:
        foo = Default(value="FOO")
        bar = Env(path="FOO")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    preload(config)
Exemple #7
0
def test_integer_parameter_type(environ, random_integer):
    environ["FOO"] = str(random_integer)
    environ["BAR"] = str(random_integer)

    class ConfigSpec(Spec):
        foo: int
        bar = Integer()

    class SourceSpec:
        foo = Env(path="FOO")
        bar = Env(path="BAR")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)
    assert config.foo == random_integer
    assert config.bar == random_integer
Exemple #8
0
def test_string_parameter_type(environ, random_string):
    environ["FOO"] = random_string
    environ["BAR"] = random_string

    class ConfigSpec(Spec):
        foo: str
        bar = String()

    class SourceSpec:
        foo = Env(path="FOO")
        bar = Env(path="BAR")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)
    assert config.foo == random_string
    assert config.bar == random_string
Exemple #9
0
def test_get_parameter_info(random_string, random_integer):
    os.environ["VALUE"] = random_string
    expected_parameter_info = ParameterInfo("foo", str,
                                            ["""Env(path="VALUE")"""])

    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = Env(path="VALUE")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    info = parameter_info(config, "foo")
    assert info == expected_parameter_info
Exemple #10
0
    def test_adds_entire_doc_to_cache(self, random_string):
        class MySource(DocumentSource, AbstractSourceDescriptor):
            def __init__(self, path):
                self._path = path

            @property
            def _name(self):
                return self._path

            @property
            def _key(self):
                class_name = type(self).__name__
                return (class_name, )

            def __repr__(self):
                return f"""MySource(path="{self._path}")"""

            @property
            def _doc(self):
                return {
                    "foo": random_string,
                    "bar": random_string,
                    "baz": random_string,
                }

        class ConfigSpec(Spec):
            foo: str
            bar: str

        class SourceSpec:
            foo = MySource("foo")
            bar = MySource("bar")

        config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

        # call to config.foo fetches doc and stores is in cache
        assert config.foo == random_string
        root_cache = getattr(config.__dict__["_Config__source_spec"],
                             "__source_cache__")
        assert root_cache == {
            ("MySource", ): {
                "foo": random_string,
                "bar": random_string,
                "baz": random_string,
            }
        }

        assert config.bar == random_string
Exemple #11
0
def test_failed_runtime(environ):
    """When a source fails at runtime the last fetched value should be kept."""
    environ["FOO"] = "FOO"

    class ConfigSpec(Spec):
        foo: str

    class SourceSpec:
        foo = Env(path="FOO")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    preload(config)
    assert config.foo == "FOO"

    del environ["FOO"]

    assert config.foo == "FOO"
Exemple #12
0
def test_multiple_source_specs(environ, random_string, random_integer):
    environ["VALUE"] = random_string

    class ConfigSpec(Spec):
        foo: str
        bar: int

    class SourceSpec1:
        foo = Env(path="VALUE")

    class SourceSpec2:
        bar = Default(value=str(random_integer))

    config = Config(config_spec=ConfigSpec,
                    source_spec=(SourceSpec1, SourceSpec2))

    assert config.foo == random_string
    assert config.bar == random_integer
Exemple #13
0
def test_source_spec_from_ini_file(environ, random_string):
    environ["VALUE"] = str(random_string)

    tempfile = NamedTemporaryFile(suffix=".ini")
    with open(tempfile.name, "w") as fh:
        fh.write(
            dedent("""
        [parameter_foo]
        source=Env
        path=VALUE
        """))
    environ["SOURCE_SPEC_PATH"] = tempfile.name

    class ConfigSpec(Spec):
        foo: str

    config = Config(config_spec=ConfigSpec, env_var="SOURCE_SPEC_PATH")

    assert config.foo == random_string
Exemple #14
0
def test_failed_preloading(environ):
    """When a source fails at initialisation an error should be thrown."""
    try:
        del environ["FOO"]
    except KeyError:
        pass

    class ConfigSpec(Spec):
        foo: str
        bar: str

    class SourceSpec:
        foo = Default(value="FOO")
        bar = Env(path="FOO")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    with pytest.raises(Exception):
        preload(config)
Exemple #15
0
def test_multiple_source_specs_most_significant_spec(environ, random_string,
                                                     random_integer):
    environ["VALUE"] = random_string

    class ConfigSpec(Spec):
        foo: str
        bar: str

    class SourceSpec1:
        foo = Env(path="VALUE")
        bar = Default(random_integer)

    class SourceSpec2:
        bar = Default(value=str(random_integer))

    config = Config(config_spec=ConfigSpec,
                    source_spec=(SourceSpec1, SourceSpec2))

    # SourceSpec1 shadows SourceSpec2
    assert config.foo == random_string
    assert config.bar == str(random_integer)
Exemple #16
0
def test_get_all_parameters_info(random_string, random_integer):
    os.environ["VALUE"] = random_string
    os.environ["VALUE"] = random_string
    expected_parameter_info = [
        ParameterInfo("foo", str, ["""Env(path="VALUE")"""]),
        ParameterInfo("bar", str, ["""Env(path="VALUE")"""]),
    ]

    class ConfigSpec(Spec):
        foo: str
        bar: str

    class SourceSpec:
        foo = Env(path="VALUE")
        bar = Env(path="VALUE")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    info = all_parameter_info(config)

    assert info == expected_parameter_info
Exemple #17
0
def test_dotfile(random_string, random_integer):
    tempfile = NamedTemporaryFile(prefix=".env")
    with open(tempfile.name, "w") as fh:
        fh.write(
            dedent(f"""
        # a comment and that will be ignored.
        FOO={random_string}
        BAR={random_integer}
        """))

    class ConfigSpec(Spec):
        foo: str
        bar: int

    class SourceSpec:
        foo = files.DotEnvFile(path="FOO", dotenv_path=tempfile.name)
        bar = files.DotEnvFile(path="BAR", dotenv_path=tempfile.name)

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

    assert config.foo == random_string
    assert config.bar == random_integer
Exemple #18
0
def test_source_spec_from_multiple_ini_file(environ, random_string,
                                            random_integer):
    environ["VALUE"] = str(random_string)

    deploy_spec = NamedTemporaryFile(suffix=".ini")
    default_spec = NamedTemporaryFile(suffix=".ini")
    with open(deploy_spec.name, "w") as fh:
        fh.write(
            dedent(f"""
        [parameter_foo]
        source=Env
        path=VALUE
        """))
    with open(default_spec.name, "w") as fh:
        fh.write(
            dedent(f"""
        [parameter_foo]
        source=Default
        value=Should not be read!

        [parameter_bar]
        source=Default
        value={random_integer}
        """))

    # deploy_spec shadows default_spec
    environ["SOURCE_SPEC_PATH"] = ",".join(
        (deploy_spec.name, default_spec.name))

    class ConfigSpec(Spec):
        foo: str
        bar: str

    config = Config(config_spec=ConfigSpec, env_var="SOURCE_SPEC_PATH")

    # deploy_spec shadows default_spec
    assert config.foo == random_string
    assert config.bar == str(random_integer)
Exemple #19
0
def test_casts_source_value_to_type(environ, random_integer):
    environ["VALUE"] = str(random_integer)

    class ConfigSpec(Spec):
        foo: str
        bar: int
        xor = String()
        baz = Integer()

    class SourceSpec:
        foo = Env(path="VALUE")
        bar = Env(path="VALUE")
        xor = Env(path="VALUE")
        baz = Env(path="VALUE")

    config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)
    assert type(config.foo) == str
    assert config.foo == str(random_integer)
    assert type(config.bar) == int
    assert config.bar == random_integer
    assert type(config.xor) == str
    assert config.foo == str(random_integer)
    assert type(config.baz) == int
    assert config.bar == random_integer
Exemple #20
0
# Add repo root to path to make config_composer importable
repo_root = str(Path(__file__).absolute().parent.parent.parent)
sys.path.append(repo_root)
from config_composer.core import Config, Spec  # noqa: E402s

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class ConfigSpec(Spec):
    host: str
    port: int
    db_pass: str


config = Config(config_spec=ConfigSpec, env_var="SOURCE_SPEC_PATH")


def mock_query_db():
    # password = config.db_pass

    return "Bob"


class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        username = mock_query_db().encode()

        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Hello, " + username)
from config_composer.core import Spec, Config
from config_composer.core.utils import preload
from config_composer.sources.env import Env
from config_composer.sources import aws, vault, files
from config_composer.sources.default import Default


class ConfigSpec(Spec):
    foo: str
    bar: int
    baz: str


class SourceSpec:
    foo = Env("FOO")
    bar = aws.Parameter(path="/foo/bar/baz")
    baz = vault.Secret(path="/foo/bar/baz", field="my-secret")
    qux = files.DotEnvFile(path="FOO", dotenv_path="/app/config/.prod-env")
    wat = Default(value="wat")


config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

if __name__ == "__main__":
    preload(config)

    env_foo = config.foo
    bar_foo = config["bar"]
    env_baz = config.get("baz")
Exemple #22
0
    def test_adds_entire_doc_to_cache(self, random_string):

        control = {"expired": True}

        class MySource(DocumentSource, DocumentSourceTTL,
                       AbstractSourceDescriptor):
            def __init__(self, path):
                self._path = path
                self._count = 0

            @property
            def _name(self):
                return self._path

            @property
            def _key(self):
                class_name = type(self).__name__
                return (class_name, )

            def __repr__(self):
                return f"""MySource(path="{self._path}")"""

            @property
            def _doc(self):
                self._count += 1
                return {
                    "foo": f"foo - {random_string} - {self._count}",
                    "bar": f"bar - {random_string} - {self._count}",
                    "baz": f"baz - {random_string} - {self._count}",
                }

            def _expired(self, ttl_data):
                if not isinstance(ttl_data, dict):
                    ttl_data = control

                if ttl_data["expired"] is True:
                    expired = True
                    ttl_data.update({"expired": False})
                else:
                    expired = False

                return expired, ttl_data

        class ConfigSpec(Spec):
            foo: str
            bar: str

        class SourceSpec:
            foo = MySource("foo")
            bar = MySource("bar")

        config = Config(config_spec=ConfigSpec, source_spec=SourceSpec)

        # call to config.foo fetches doc and stores is in cache
        assert config.foo == f"foo - {random_string} - 1"
        assert config.bar == f"bar - {random_string} - 1"
        root_cache = getattr(config.__dict__["_Config__source_spec"],
                             "__source_cache__")
        assert root_cache == {
            ("MySource", ): {
                "foo": f"foo - {random_string} - 1",
                "bar": f"bar - {random_string} - 1",
                "baz": f"baz - {random_string} - 1",
            }
        }

        # call to config.foo fetches doc and stores is in cache
        source_spec = config.__dict__["_Config__source_spec"]
        control["expired"] = True

        assert config.foo == f"foo - {random_string} - 2"
        assert config.bar == f"bar - {random_string} - 2"
        root_cache = getattr(source_spec, "__source_cache__")
        assert root_cache == {
            ("MySource", ): {
                "foo": f"foo - {random_string} - 2",
                "bar": f"bar - {random_string} - 2",
                "baz": f"baz - {random_string} - 2",
            }
        }