forked from clan/clan-core
Fixed failing tests in machines and history cli, removed test_machines_api.py
This commit is contained in:
parent
e139628fbd
commit
1a36ef242f
@ -106,6 +106,10 @@ class ClanURI:
|
||||
|
||||
@classmethod
|
||||
def from_str(cls, url: str, params: ClanParameters | None = None) -> Self: # noqa
|
||||
prefix = "clan://"
|
||||
if url.startswith(prefix):
|
||||
url = url[len(prefix) :]
|
||||
|
||||
if params is None:
|
||||
return cls(f"clan://{url}")
|
||||
|
||||
@ -118,4 +122,4 @@ class ClanURI:
|
||||
return cls(f"clan://{new_url}")
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"ClanURI({self._components.geturl()})"
|
||||
return self.get_full_uri()
|
||||
|
@ -5,6 +5,7 @@ from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from ..errors import ClanError
|
||||
from ..machines.list import list_machines
|
||||
from ..nix import nix_config, nix_eval, nix_metadata
|
||||
|
||||
|
||||
@ -24,6 +25,12 @@ def inspect_flake(flake_url: str | Path, flake_attr: str) -> FlakeConfig:
|
||||
config = nix_config()
|
||||
system = config["system"]
|
||||
|
||||
machines = list_machines(flake_url)
|
||||
if flake_attr not in machines:
|
||||
raise ClanError(
|
||||
f"Machine {flake_attr} not found in {flake_url}. Available machines: {', '.join(machines)}"
|
||||
)
|
||||
|
||||
cmd = nix_eval(
|
||||
[
|
||||
f'{flake_url}#clanInternals.machines."{system}"."{flake_attr}".config.clanCore.clanIcon'
|
||||
|
@ -77,12 +77,12 @@ def add_history(uri: ClanURI) -> list[HistoryEntry]:
|
||||
|
||||
|
||||
def add_history_command(args: argparse.Namespace) -> None:
|
||||
add_history(args.path)
|
||||
add_history(args.uri)
|
||||
|
||||
|
||||
# takes a (sub)parser and configures it
|
||||
def register_add_parser(parser: argparse.ArgumentParser) -> None:
|
||||
parser.add_argument(
|
||||
"uri", type=ClanURI, help="Path to the flake", default=ClanURI(".")
|
||||
"uri", type=ClanURI.from_str, help="Path to the flake", default="."
|
||||
)
|
||||
parser.set_defaults(func=add_history_command)
|
||||
|
@ -11,12 +11,12 @@ from ..nix import nix_config, nix_eval
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def list_machines(flake_dir: Path) -> list[str]:
|
||||
def list_machines(flake_url: Path | str) -> list[str]:
|
||||
config = nix_config()
|
||||
system = config["system"]
|
||||
cmd = nix_eval(
|
||||
[
|
||||
f"{flake_dir}#clanInternals.machines.{system}",
|
||||
f"{flake_url}#clanInternals.machines.{system}",
|
||||
"--apply",
|
||||
"builtins.attrNames",
|
||||
"--json",
|
||||
|
@ -125,6 +125,11 @@ def test_from_str() -> None:
|
||||
assert uri.params.flake_attr == "defaultVM"
|
||||
assert uri.get_internal() == "~/Downloads/democlan"
|
||||
|
||||
uri_str = "clan://~/Downloads/democlan"
|
||||
uri = ClanURI.from_str(url=uri_str)
|
||||
assert uri.params.flake_attr == "defaultVM"
|
||||
assert uri.get_internal() == "~/Downloads/democlan"
|
||||
|
||||
|
||||
def test_remote_with_all_params() -> None:
|
||||
# Create a ClanURI object from a remote URI with parameters
|
||||
|
@ -1,10 +1,12 @@
|
||||
import json
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import pytest
|
||||
from cli import Cli
|
||||
from fixtures_flakes import FlakeForTest
|
||||
from pytest import CaptureFixture
|
||||
|
||||
from clan_cli.clan_uri import ClanParameters, ClanURI
|
||||
from clan_cli.dirs import user_history_file
|
||||
from clan_cli.history.add import HistoryEntry
|
||||
|
||||
@ -12,14 +14,17 @@ if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.impure
|
||||
def test_history_add(
|
||||
test_flake_with_core: FlakeForTest,
|
||||
) -> None:
|
||||
cli = Cli()
|
||||
params = ClanParameters(flake_attr="vm1")
|
||||
uri = ClanURI.from_path(test_flake_with_core.path, params=params)
|
||||
cmd = [
|
||||
"history",
|
||||
"add",
|
||||
str(test_flake_with_core.path),
|
||||
str(uri),
|
||||
]
|
||||
|
||||
cli.run(cmd)
|
||||
@ -30,11 +35,14 @@ def test_history_add(
|
||||
assert history[0].flake.flake_url == str(test_flake_with_core.path)
|
||||
|
||||
|
||||
@pytest.mark.impure
|
||||
def test_history_list(
|
||||
capsys: CaptureFixture,
|
||||
test_flake_with_core: FlakeForTest,
|
||||
) -> None:
|
||||
cli = Cli()
|
||||
params = ClanParameters(flake_attr="vm1")
|
||||
uri = ClanURI.from_path(test_flake_with_core.path, params=params)
|
||||
cmd = [
|
||||
"history",
|
||||
"list",
|
||||
@ -43,6 +51,6 @@ def test_history_list(
|
||||
cli.run(cmd)
|
||||
assert str(test_flake_with_core.path) not in capsys.readouterr().out
|
||||
|
||||
cli.run(["history", "add", str(test_flake_with_core.path)])
|
||||
cli.run(["history", "add", str(uri)])
|
||||
cli.run(cmd)
|
||||
assert str(test_flake_with_core.path) in capsys.readouterr().out
|
||||
|
@ -1,279 +0,0 @@
|
||||
import pytest
|
||||
from api import TestClient
|
||||
from fixtures_flakes import FlakeForTest
|
||||
|
||||
|
||||
def test_machines(api: TestClient, test_flake: FlakeForTest) -> None:
|
||||
response = api.get(f"/api/machines?flake_dir={test_flake.path}")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"machines": []}
|
||||
response = api.put(
|
||||
f"/api/machines/test/config?flake_dir={test_flake.path}", json={}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api.get(f"/api/machines/test?flake_dir={test_flake.path}")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"machine": {"name": "test", "status": "unknown"}}
|
||||
|
||||
response = api.get(f"/api/machines?flake_dir={test_flake.path}")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"machines": [{"name": "test", "status": "unknown"}]}
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_schema_errors(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
|
||||
# make sure that eval errors do not raise an internal server error
|
||||
response = api.put(
|
||||
f"/api/schema?flake_dir={test_flake_with_core.path}",
|
||||
json={"imports": ["some-invalid-import"]},
|
||||
)
|
||||
assert response.status_code == 422
|
||||
assert (
|
||||
"error: string 'some-invalid-import' doesn't represent an absolute path"
|
||||
in response.json()["detail"][0]["msg"]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_schema_invalid_clan_imports(
|
||||
api: TestClient, test_flake_with_core: FlakeForTest
|
||||
) -> None:
|
||||
response = api.put(
|
||||
f"/api/schema?flake_dir={test_flake_with_core.path}",
|
||||
json={"clanImports": ["non-existing-clan-module"]},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert (
|
||||
"Some requested clan modules could not be found"
|
||||
in response.json()["detail"]["msg"]
|
||||
)
|
||||
|
||||
|
||||
def test_create_machine_invalid_hostname(
|
||||
api: TestClient, test_flake: FlakeForTest
|
||||
) -> None:
|
||||
response = api.put(
|
||||
f"/api/machines/-invalid-hostname/config?flake_dir={test_flake.path}",
|
||||
json=dict(),
|
||||
)
|
||||
assert response.status_code == 422
|
||||
assert (
|
||||
"Machine name must be a valid hostname" in response.json()["detail"][0]["msg"]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_verify_config_without_machine(
|
||||
api: TestClient, test_flake_with_core: FlakeForTest
|
||||
) -> None:
|
||||
response = api.put(
|
||||
f"/api/machines/test/verify?flake_dir={test_flake_with_core.path}",
|
||||
json=dict(),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"success": True, "error": None}
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_ensure_empty_config_is_valid(
|
||||
api: TestClient, test_flake_with_core: FlakeForTest
|
||||
) -> None:
|
||||
response = api.put(
|
||||
f"/api/machines/test/config?flake_dir={test_flake_with_core.path}",
|
||||
json=dict(),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api.get(
|
||||
f"/api/machines/test/verify?flake_dir={test_flake_with_core.path}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"success": True, "error": None}
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
|
||||
# ensure error 404 if machine does not exist when accessing the config
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}"
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
# create the machine
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}", json={}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# ensure an empty config is returned by default for a new machine
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"clanImports": [],
|
||||
"clan": {},
|
||||
}
|
||||
|
||||
# get jsonschema for without imports
|
||||
response = api.put(
|
||||
f"/api/schema?flake_dir={test_flake_with_core.path}",
|
||||
json={"clanImports": []},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
json_response = response.json()
|
||||
assert "schema" in json_response and "properties" in json_response["schema"]
|
||||
|
||||
# an invalid config setting some non-existent option
|
||||
invalid_config = dict(
|
||||
clan=dict(),
|
||||
foo=dict(
|
||||
bar=True,
|
||||
),
|
||||
services=dict(
|
||||
nginx=dict(
|
||||
enable=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# verify an invalid config (foo option does not exist)
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/verify?flake_dir={test_flake_with_core.path}",
|
||||
json=invalid_config,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert "error: The option `foo' does not exist" in response.json()["error"]
|
||||
|
||||
# set come invalid config (foo option does not exist)
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
json=invalid_config,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# ensure the config has actually been updated
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == dict(clanImports=[], **invalid_config)
|
||||
|
||||
# set some valid config
|
||||
config2 = dict(
|
||||
clan=dict(),
|
||||
services=dict(
|
||||
nginx=dict(
|
||||
enable=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
json=config2,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# ensure the config has been applied
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == dict(clanImports=[], **config2)
|
||||
|
||||
# get the config again
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"clanImports": [], **config2}
|
||||
|
||||
# ensure PUT on the config is idempotent by passing the config again
|
||||
# For example, this should not result in the boot.loader.grub.devices being
|
||||
# set twice (eg. merged)
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
json=config2,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# ensure the config has been applied
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == dict(clanImports=[], **config2)
|
||||
|
||||
# verify the machine config evaluates
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/verify?flake_dir={test_flake_with_core.path}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
assert response.json() == {"success": True, "error": None}
|
||||
|
||||
# get the schema with an extra module imported
|
||||
response = api.put(
|
||||
f"/api/schema?flake_dir={test_flake_with_core.path}",
|
||||
json={"clanImports": ["diskLayouts"]},
|
||||
)
|
||||
# expect the result schema to contain the deltachat option
|
||||
assert response.status_code == 200
|
||||
assert (
|
||||
response.json()["schema"]["properties"]["diskLayouts"]["properties"][
|
||||
"singleDiskExt4"
|
||||
]["properties"]["device"]["type"]
|
||||
== "string"
|
||||
)
|
||||
|
||||
# new config importing an extra clanModule (clanModules.fake-module)
|
||||
config_with_imports: dict = {
|
||||
"clanImports": ["fake-module"],
|
||||
"clan": {
|
||||
"fake-module": {
|
||||
"fake-flag": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# set the fake-module.fake-flag option to true
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
json=config_with_imports,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# ensure the config has been applied
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"clanImports": ["fake-module"],
|
||||
"clan": {
|
||||
"fake-module": {
|
||||
"fake-flag": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# remove the import from the config
|
||||
response = api.put(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
json=dict(
|
||||
clanImports=[],
|
||||
),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# ensure the config has been applied
|
||||
response = api.get(
|
||||
f"/api/machines/machine1/config?flake_dir={test_flake_with_core.path}",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"clan": {},
|
||||
"clanImports": [],
|
||||
}
|
@ -3,20 +3,25 @@ from cli import Cli
|
||||
from fixtures_flakes import FlakeForTest
|
||||
|
||||
|
||||
@pytest.mark.impure
|
||||
def test_machine_subcommands(
|
||||
test_flake: FlakeForTest, capsys: pytest.CaptureFixture
|
||||
test_flake_with_core: FlakeForTest, capsys: pytest.CaptureFixture
|
||||
) -> None:
|
||||
cli = Cli()
|
||||
cli.run(["--flake", str(test_flake.path), "machines", "create", "machine1"])
|
||||
cli.run(
|
||||
["--flake", str(test_flake_with_core.path), "machines", "create", "machine1"]
|
||||
)
|
||||
|
||||
capsys.readouterr()
|
||||
cli.run(["--flake", str(test_flake.path), "machines", "list"])
|
||||
cli.run(["--flake", str(test_flake_with_core.path), "machines", "list"])
|
||||
out = capsys.readouterr()
|
||||
assert "machine1\n" == out.out
|
||||
assert "machine1\nvm1\nvm2\n" == out.out
|
||||
|
||||
cli.run(["--flake", str(test_flake.path), "machines", "delete", "machine1"])
|
||||
cli.run(
|
||||
["--flake", str(test_flake_with_core.path), "machines", "delete", "machine1"]
|
||||
)
|
||||
|
||||
capsys.readouterr()
|
||||
cli.run(["--flake", str(test_flake.path), "machines", "list"])
|
||||
cli.run(["--flake", str(test_flake_with_core.path), "machines", "list"])
|
||||
out = capsys.readouterr()
|
||||
assert "" == out.out
|
||||
assert "vm1\nvm2\n" == out.out
|
||||
|
@ -4,7 +4,7 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import gi
|
||||
from clan_cli import flakes, vms
|
||||
from clan_cli import flakes, history, vms
|
||||
|
||||
gi.require_version("GdkPixbuf", "2.0")
|
||||
from gi.repository import GdkPixbuf
|
||||
@ -77,7 +77,7 @@ def get_initial_vms(start: int = 0, end: int | None = None) -> list[VM]:
|
||||
|
||||
# TODO: list_history() should return a list of dicts, not a list of paths
|
||||
# Execute `clan flakes add <path>` to democlan for this to work
|
||||
for entry in flakes.history.list_history():
|
||||
for entry in history.list.list_history():
|
||||
flake_config = flakes.inspect.inspect_flake(entry.path, "defaultVM")
|
||||
vm_config = vms.inspect.inspect_vm(entry.path, "defaultVM")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user