예제 #1
0
    def test_load_err(self, tmp_path):
        """Gracefully handle missing file, corrupt content etc."""
        # Must gracefully handle a corrupt configuration file.
        fname = tmp_path / "does-not-exist.yaml"
        _, err = cfgfile.load(fname)
        assert err

        # YAML error.
        fname = tmp_path / "corrupt-yaml.yaml"
        fname.write_text("[foo")
        _, err = cfgfile.load(fname)
        assert err

        # Does not match the definition of `dtypes.Config`.
        fname = tmp_path / "invalid-pydantic-schema.yaml"
        fname.write_text("foo: bar")
        _, err = cfgfile.load(fname)
        assert err

        # YAML file is valid but not a map. This special case is important
        # because the test function will expand the content as **kwargs.
        fname = tmp_path / "invalid-pydantic-schema.yaml"
        fname.write_text("")
        _, err = cfgfile.load(fname)
        assert err

        # Load the sample configuration and corrupt the label selector. Instead
        # of a list of 2-tuples we make it a list of 3-tuples.
        cfg = yaml.safe_load(Filepath("tests/support/config.yaml").read_text())
        cfg["selectors"]["labels"] = [["foo", "bar", "foobar"]]
        fout = tmp_path / "corrupt.yaml"
        fout.write_text(yaml.dump(cfg))
        _, err = cfgfile.load(fout)
        assert err
예제 #2
0
    def test_common_filters(self, tmp_path):
        """Deal with empty or non-existing `_common_` filter."""
        fname_ref = Filepath("tests/support/config.yaml")

        # ----------------------------------------------------------------------
        # Empty _common_ filters.
        # ----------------------------------------------------------------------
        # Clear the "_common_" filter and save the configuration again.
        ref = yaml.safe_load(fname_ref.read_text())
        ref["filters"]["_common_"].clear()
        fout = tmp_path / "corrupt.yaml"
        fout.write_text(yaml.dump(ref))

        # Load the new configuration. This must succeed and the filters must
        # match the ones defined in the file because there the "_common_"
        # filter was empty.
        cfg, err = cfgfile.load(fout)
        assert not err and ref["filters"] == cfg.filters

        # ----------------------------------------------------------------------
        # Missing _common_ filters.
        # ----------------------------------------------------------------------
        # Remove the "_common_" filter and save the configuration again.
        ref = yaml.safe_load(fname_ref.read_text())
        del ref["filters"]["_common_"]
        fout = tmp_path / "valid.yaml"
        fout.write_text(yaml.dump(ref))

        # Load the new configuration. This must succeed and the filters must
        # match the ones defined in the file because there was no "_common_"
        # filter to merge.
        cfg, err = cfgfile.load(fout)
        assert cfg.filters["_common_"] == []
        del cfg.filters["_common_"]
        assert not err and ref["filters"] == cfg.filters
예제 #3
0
    def test_load_folder_paths(self, tmp_path):
        """The folder paths must always be relative to the config file."""
        fname = tmp_path / ".square.yaml"
        fname_ref = Filepath("tests/support/config.yaml")

        # The parsed folder must point to "tmp_path".
        ref = yaml.safe_load(fname_ref.read_text())
        fname.write_text(yaml.dump(ref))
        cfg, err = cfgfile.load(fname)
        assert not err and cfg.folder == tmp_path / "some/path"

        # The parsed folder must point to "tmp_path/folder".
        ref = yaml.safe_load(fname_ref.read_text())
        ref["folder"] = "my-folder"
        fname.write_text(yaml.dump(ref))
        cfg, err = cfgfile.load(fname)
        assert not err and cfg.folder == tmp_path / "my-folder"

        # An absolute path must ignore the position of ".square.yaml".
        # No idea how to handle this on Windows.
        if not sys.platform.startswith("win"):
            ref = yaml.safe_load(fname_ref.read_text())
            ref["folder"] = "/absolute/path"
            fname.write_text(yaml.dump(ref))
            cfg, err = cfgfile.load(fname)
            assert not err and cfg.folder == Filepath("/absolute/path")
예제 #4
0
    def test_boostrap(self):
        """Verify the constants created during package import."""
        assert hasattr(square, "get")
        assert hasattr(square, "plan")
        assert hasattr(square, "apply_plan")
        assert hasattr(square, "show_plan")

        # Must have loaded the configuration file.
        cfg, err = cfgfile.load(DEFAULT_CONFIG_FILE)
        assert not err
        assert square.DEFAULT_CONFIG == cfg
예제 #5
0
    def test_boostrap(self):
        """Verify the constants created during package import."""
        assert hasattr(square, "get")
        assert hasattr(square, "plan")
        assert hasattr(square, "apply_plan")
        assert hasattr(square, "show_plan")

        # Must have loaded the default configuration file but wiped the
        # namespace selector.
        cfg, err = cfgfile.load(DEFAULT_CONFIG_FILE)
        assert not err
        cfg.selectors.namespaces.clear()
        assert square.DEFAULT_CONFIG == cfg
예제 #6
0
    def test_load(self):
        """Load and parse configuration file."""
        # Load the sample that ships with Square.
        fname = Filepath("tests/support/config.yaml")
        cfg, err = cfgfile.load(fname)
        assert not err and isinstance(cfg, Config)

        assert cfg.folder == fname.parent.absolute() / "some/path"
        assert cfg.kubeconfig == Filepath("/path/to/kubeconfig")
        assert cfg.kubecontext is None
        assert cfg.priorities == list(DEFAULT_PRIORITIES)
        assert cfg.selectors.kinds == set(DEFAULT_PRIORITIES)
        assert cfg.selectors.namespaces == ["default", "kube-system"]
        assert cfg.selectors.labels == ["app=square"]
        assert set(cfg.filters.keys()) == {
            "_common_", "ConfigMap", "Deployment", "HorizontalPodAutoscaler",
            "Service"
        }
예제 #7
0
def fname_param_config(tmp_path) -> Generator[
        Tuple[Filepath, types.SimpleNamespace, Config], None, None]:
    """Parsed command line args to produce the default configuration.

    The return values are what `parse_commandline_args` would return, as well
    as what `compile_config` should convert them into.

    This removes a lot of boiler plate in the tests.

    """
    # Location of our configuration file and dummy Kubeconfig.
    fname_square = tmp_path / ".square.yaml"
    fname_kubeconfig = tmp_path / "kubeconfig-dot-square"

    # Duplicate the default configuration with the new kubeconfig.
    ref = yaml.safe_load(DEFAULT_CONFIG_FILE.read_text())
    assert "kubeconfig" in ref and "kubecontext" in ref
    ref["kubeconfig"] = str(fname_kubeconfig.absolute())

    # We will "abuse" the `kubecontext` field to indicate that this is our mock
    # ".square.yaml". We will also replace the default path with a custom one
    # to avoid an ambiguity with the default value of "." for the folder.
    ref["kubecontext"] = "dot-square"
    assert ref["folder"] == "."
    ref["folder"] = "foo/bar"
    fname_square.write_text(yaml.dump(ref))
    del ref

    # Load the sample configuration.
    config, err = cfgfile.load(fname_square)
    assert not err

    # Point the folder and kubeconfig to temporary versions.
    config.folder = tmp_path

    # Ensure the dummy kubeconfig file exists.
    config.kubeconfig.write_text("")

    # Override the version because this one is difficult (and pointless) to
    # compare in tests.
    config.version = ""

    params = types.SimpleNamespace(
        # Not in config file - command line arguments only.
        parser="get",
        configfile="",
        verbosity=9,
        info=False,
        no_config=False,

        # Dummy kubeconfig created by the `config` fixture.
        kubeconfig=str(config.kubeconfig),

        # These were not specified on the command line.
        folder=".",
        kinds=DEFAULT_PRIORITIES,
        labels=[],
        namespaces=["default"],
        kubecontext=None,
        groupby=["ns", "label=app", "kind"],
        priorities=DEFAULT_PRIORITIES,
    )

    cwd = pathlib.Path.cwd()
    os.chdir(tmp_path)
    yield fname_square, params, config
    os.chdir(cwd)