nixos-rebuild-ng: improve tests (#381842)

This commit is contained in:
Thiago Kenji Okada
2025-02-14 09:44:53 +00:00
committed by GitHub
5 changed files with 761 additions and 640 deletions
@@ -89,6 +89,9 @@ python3Packages.buildPythonApplication rec {
ps: with ps; [
mypy
pytest
# this is to help development (e.g.: better diffs) inside devShell
# only, do not use its helpers like `mocker`
pytest-mock
ruff
]
);
File diff suppressed because it is too large Load Diff
@@ -26,7 +26,7 @@ def test_build(mock_run: Mock) -> None:
m.BuildAttr("<nixpkgs/nixos>", None),
{"nix_flag": "foo"},
) == Path("/path/to/file")
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix-build",
"<nixpkgs/nixos>",
@@ -38,17 +38,13 @@ def test_build(mock_run: Mock) -> None:
stdout=PIPE,
)
mock_run.reset_mock()
assert n.build(
"config.system.build.attr", m.BuildAttr(Path("file"), "preAttr")
) == Path("/path/to/file")
assert mock_run.call_args_list == [
call(
["nix-build", Path("file"), "--attr", "preAttr.config.system.build.attr"],
stdout=PIPE,
)
]
mock_run.assert_called_with(
["nix-build", Path("file"), "--attr", "preAttr.config.system.build.attr"],
stdout=PIPE,
)
@patch(
@@ -65,7 +61,7 @@ def test_build_flake(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) ->
flake,
{"no_link": True, "nix_flag": "foo"},
) == Path("/path/to/file")
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix",
"--extra-experimental-features",
@@ -114,53 +110,58 @@ def test_build_remote(
instantiate_flags={"inst": True},
copy_flags={"copy": True},
) == Path("/path/to/config")
assert mock_run.call_args_list == [
call(
[
"nix-instantiate",
"<nixpkgs/nixos>",
"--attr",
"preAttr.config.system.build.toplevel",
"--add-root",
n.tmpdir.TMPDIR_PATH / "00000000000000000000000000000001",
"--inst",
],
stdout=PIPE,
),
call(
[
"nix-copy-closure",
"--copy",
"--to",
"user@host",
Path("/path/to/file"),
],
extra_env={"NIX_SSHOPTS": " ".join([*p.SSH_DEFAULT_OPTS, "--ssh opts"])},
),
call(
["mktemp", "-d", "-t", "nixos-rebuild.XXXXX"],
remote=build_host,
stdout=PIPE,
),
call(
[
"nix-store",
"--realise",
Path("/path/to/file"),
"--add-root",
Path("/tmp/tmpdir/00000000000000000000000000000002"),
"--realise",
],
remote=build_host,
stdout=PIPE,
),
call(
["readlink", "-f", "/tmp/tmpdir/config"],
remote=build_host,
stdout=PIPE,
),
call(["rm", "-rf", Path("/tmp/tmpdir")], remote=build_host, check=False),
]
mock_run.assert_has_calls(
[
call(
[
"nix-instantiate",
"<nixpkgs/nixos>",
"--attr",
"preAttr.config.system.build.toplevel",
"--add-root",
n.tmpdir.TMPDIR_PATH / "00000000000000000000000000000001",
"--inst",
],
stdout=PIPE,
),
call(
[
"nix-copy-closure",
"--copy",
"--to",
"user@host",
Path("/path/to/file"),
],
extra_env={
"NIX_SSHOPTS": " ".join([*p.SSH_DEFAULT_OPTS, "--ssh opts"])
},
),
call(
["mktemp", "-d", "-t", "nixos-rebuild.XXXXX"],
remote=build_host,
stdout=PIPE,
),
call(
[
"nix-store",
"--realise",
Path("/path/to/file"),
"--add-root",
Path("/tmp/tmpdir/00000000000000000000000000000002"),
"--realise",
],
remote=build_host,
stdout=PIPE,
),
call(
["readlink", "-f", "/tmp/tmpdir/config"],
remote=build_host,
stdout=PIPE,
),
call(["rm", "-rf", Path("/tmp/tmpdir")], remote=build_host, check=False),
]
)
@patch(
@@ -184,43 +185,47 @@ def test_build_remote_flake(
copy_flags={"copy": True},
flake_build_flags={"build": True},
) == Path("/path/to/file")
assert mock_run.call_args_list == [
call(
[
"nix",
"--extra-experimental-features",
"nix-command flakes",
"eval",
"--raw",
".#nixosConfigurations.hostname.config.system.build.toplevel.drvPath",
"--flake",
],
stdout=PIPE,
),
call(
[
"nix-copy-closure",
"--copy",
"--to",
"user@host",
Path("/path/to/file"),
],
extra_env={"NIX_SSHOPTS": " ".join([*p.SSH_DEFAULT_OPTS, "--ssh opts"])},
),
call(
[
"nix",
"--extra-experimental-features",
"nix-command flakes",
"build",
"/path/to/file^*",
"--print-out-paths",
"--build",
],
remote=build_host,
stdout=PIPE,
),
]
mock_run.assert_has_calls(
[
call(
[
"nix",
"--extra-experimental-features",
"nix-command flakes",
"eval",
"--raw",
".#nixosConfigurations.hostname.config.system.build.toplevel.drvPath",
"--flake",
],
stdout=PIPE,
),
call(
[
"nix-copy-closure",
"--copy",
"--to",
"user@host",
Path("/path/to/file"),
],
extra_env={
"NIX_SSHOPTS": " ".join([*p.SSH_DEFAULT_OPTS, "--ssh opts"])
},
),
call(
[
"nix",
"--extra-experimental-features",
"nix-command flakes",
"build",
"/path/to/file^*",
"--print-out-paths",
"--build",
],
remote=build_host,
stdout=PIPE,
),
]
)
def test_copy_closure(monkeypatch: MonkeyPatch) -> None:
@@ -233,7 +238,7 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None:
build_host = m.Remote("user@build.host", [], None)
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
n.copy_closure(closure, target_host)
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-copy-closure", "--to", "user@target.host", closure],
extra_env={"NIX_SSHOPTS": " ".join(p.SSH_DEFAULT_OPTS)},
)
@@ -241,7 +246,7 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None:
monkeypatch.setenv("NIX_SSHOPTS", "--ssh build-opt")
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
n.copy_closure(closure, None, build_host, {"copy_flag": True})
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-copy-closure", "--copy-flag", "--from", "user@build.host", closure],
extra_env={
"NIX_SSHOPTS": " ".join([*p.SSH_DEFAULT_OPTS, "--ssh build-opt"])
@@ -255,7 +260,7 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None:
}
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
n.copy_closure(closure, target_host, build_host, {"copy_flag": True})
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix",
"copy",
@@ -272,16 +277,18 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None:
monkeypatch.setattr(n, "WITH_NIX_2_18", False)
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
n.copy_closure(closure, target_host, build_host)
assert mock_run.call_args_list == [
call(
["nix-copy-closure", "--from", "user@build.host", closure],
extra_env=extra_env,
),
call(
["nix-copy-closure", "--to", "user@target.host", closure],
extra_env=extra_env,
),
]
mock_run.assert_has_calls(
[
call(
["nix-copy-closure", "--from", "user@build.host", closure],
extra_env=extra_env,
),
call(
["nix-copy-closure", "--to", "user@target.host", closure],
extra_env=extra_env,
),
]
)
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
@@ -289,7 +296,7 @@ def test_edit(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> None:
# Flake
flake = m.Flake.parse(f"{tmpdir}#attr")
n.edit(flake, {"commit_lock_file": True})
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix",
"--extra-experimental-features",
@@ -311,7 +318,7 @@ def test_edit(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> None:
mp.setenv("EDITOR", "editor")
n.edit(None)
assert mock_run.call_args == call(["editor", default_nix], check=False)
mock_run.assert_called_with(["editor", default_nix], check=False)
@patch(
@@ -334,7 +341,7 @@ def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None:
"azure": "nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd",
"vmware": "nixos-image-vmware-25.05.20250102.6df2492-x86_64-linux.vmdk",
}
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix-instantiate",
"--eval",
@@ -352,14 +359,12 @@ def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None:
stdout=PIPE,
)
mock_run.reset_mock()
build_attr = m.BuildAttr(Path(tmp_path), "preAttr")
assert n.get_build_image_variants(build_attr, {"inst_flag": True}) == {
"azure": "nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd",
"vmware": "nixos-image-vmware-25.05.20250102.6df2492-x86_64-linux.vmdk",
}
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix-instantiate",
"--eval",
@@ -399,7 +404,7 @@ def test_get_build_image_variants_flake(mock_run: Mock) -> None:
"azure": "nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd",
"vmware": "nixos-image-vmware-25.05.20250102.6df2492-x86_64-linux.vmdk",
}
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix",
"eval",
@@ -424,7 +429,7 @@ def test_get_nixpkgs_rev() -> None:
side_effect=[CompletedProcess([], 0, "")],
) as mock_run:
assert n.get_nixpkgs_rev(path) is None
assert mock_run.call_args == call(
mock_run.assert_called_with(
["git", "-C", path, "rev-parse", "--short", "HEAD"],
check=False,
capture_output=True,
@@ -451,7 +456,7 @@ def test_get_nixpkgs_rev() -> None:
],
) as mock_run:
assert n.get_nixpkgs_rev(path) == ".git.0f7c82403fd6"
assert mock_run.call_args_list == expected_calls
mock_run.assert_has_calls(expected_calls)
with patch(
get_qualified_name(n.run_wrapper, n),
@@ -462,7 +467,7 @@ def test_get_nixpkgs_rev() -> None:
],
) as mock_run:
assert n.get_nixpkgs_rev(path) == ".git.0f7c82403fd6M"
assert mock_run.call_args_list == expected_calls
mock_run.assert_has_calls(expected_calls)
def test_get_generations(tmp_path: Path) -> None:
@@ -503,7 +508,7 @@ def test_get_generations_from_nix_env(tmp_path: Path) -> None:
m.Generation(id=2083, current=False, timestamp="2024-11-07 22:59:41"),
m.Generation(id=2084, current=True, timestamp="2024-11-07 23:54:17"),
]
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-env", "-p", path, "--list-generations"],
stdout=PIPE,
remote=None,
@@ -521,7 +526,7 @@ def test_get_generations_from_nix_env(tmp_path: Path) -> None:
m.Generation(id=2083, current=False, timestamp="2024-11-07 22:59:41"),
m.Generation(id=2084, current=True, timestamp="2024-11-07 23:54:17"),
]
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-env", "-p", path, "--list-generations"],
stdout=PIPE,
remote=remote,
@@ -573,14 +578,12 @@ def test_list_generations(mock_get_generations: Mock, tmp_path: Path) -> None:
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
def test_repl(mock_run: Mock) -> None:
n.repl("attr", m.BuildAttr("<nixpkgs/nixos>", None), {"nix_flag": True})
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix", "repl", "--file", "<nixpkgs/nixos>", "--nix-flag"]
)
n.repl("attr", m.BuildAttr(Path("file.nix"), "myAttr"))
assert mock_run.call_args == call(
["nix", "repl", "--file", Path("file.nix"), "myAttr"]
)
mock_run.assert_called_with(["nix", "repl", "--file", Path("file.nix"), "myAttr"])
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
@@ -599,7 +602,7 @@ def test_rollback(mock_run: Mock, tmp_path: Path) -> None:
profile = m.Profile("system", path)
assert n.rollback(profile, None, False) == profile.path
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-env", "--rollback", "-p", path],
remote=None,
sudo=False,
@@ -607,7 +610,7 @@ def test_rollback(mock_run: Mock, tmp_path: Path) -> None:
target_host = m.Remote("user@localhost", [], None)
assert n.rollback(profile, target_host, True) == profile.path
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-env", "--rollback", "-p", path],
remote=target_host,
sudo=True,
@@ -619,10 +622,8 @@ def test_rollback_temporary_profile(tmp_path: Path) -> None:
path.touch()
profile = m.Profile("system", path)
with patch(
get_qualified_name(n.run_wrapper, n),
autospec=True,
return_value=CompletedProcess(
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
mock_run.return_value = CompletedProcess(
[],
0,
stdout=textwrap.dedent("""\
@@ -630,13 +631,12 @@ def test_rollback_temporary_profile(tmp_path: Path) -> None:
2083 2024-11-07 22:59:41
2084 2024-11-07 23:54:17 (current)
"""),
),
) as mock_run:
)
assert (
n.rollback_temporary_profile(m.Profile("system", path), None, False)
== path.parent / "system-2083-link"
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix-env",
"-p",
@@ -653,7 +653,7 @@ def test_rollback_temporary_profile(tmp_path: Path) -> None:
n.rollback_temporary_profile(m.Profile("foo", path), target_host, True)
== path.parent / "foo-2083-link"
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"nix-env",
"-p",
@@ -665,11 +665,8 @@ def test_rollback_temporary_profile(tmp_path: Path) -> None:
sudo=True,
)
with patch(
get_qualified_name(n.run_wrapper, n),
autospec=True,
return_value=CompletedProcess([], 0, stdout=""),
) as mock_run:
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
mock_run.return_value = CompletedProcess([], 0, stdout="")
assert n.rollback_temporary_profile(profile, None, False) is None
@@ -684,7 +681,7 @@ def test_set_profile(mock_run: Mock) -> None:
sudo=False,
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
["nix-env", "-p", profile_path, "--set", config_path],
remote=None,
sudo=False,
@@ -707,7 +704,7 @@ def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> No
specialisation=None,
install_bootloader=False,
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
[profile_path / "bin/switch-to-configuration", "switch"],
extra_env={"NIXOS_INSTALL_BOOTLOADER": "0"},
sudo=False,
@@ -741,7 +738,7 @@ def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> No
install_bootloader=True,
specialisation="special",
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
config_path / "specialisation/special/bin/switch-to-configuration",
"test",
@@ -765,14 +762,14 @@ def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> No
def test_upgrade_channels(mock_is_dir: Mock, mock_glob: Mock) -> None:
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
n.upgrade_channels(False)
assert mock_run.call_args == call(["nix-channel", "--update", "nixos"], check=False)
mock_run.reset_mock()
mock_run.assert_called_once_with(["nix-channel", "--update", "nixos"], check=False)
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
n.upgrade_channels(True)
assert mock_run.call_args_list == [
call(["nix-channel", "--update", "nixos"], check=False),
call(["nix-channel", "--update", "nixos-hardware"], check=False),
call(["nix-channel", "--update", "home-manager"], check=False),
]
mock_run.assert_has_calls(
[
call(["nix-channel", "--update", "nixos"], check=False),
call(["nix-channel", "--update", "nixos-hardware"], check=False),
call(["nix-channel", "--update", "home-manager"], check=False),
]
)
@@ -1,4 +1,5 @@
from unittest.mock import Mock, call, patch
from typing import Any
from unittest.mock import patch
from pytest import MonkeyPatch
@@ -9,9 +10,9 @@ from .helpers import get_qualified_name
@patch(get_qualified_name(p.subprocess.run), autospec=True)
def test_run(mock_run: Mock) -> None:
def test_run(mock_run: Any) -> None:
p.run_wrapper(["test", "--with", "flags"], check=True)
assert mock_run.call_args == call(
mock_run.assert_called_with(
["test", "--with", "flags"],
check=True,
text=True,
@@ -27,7 +28,7 @@ def test_run(mock_run: Mock) -> None:
sudo=True,
extra_env={"FOO": "bar"},
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
["sudo", "test", "--with", "flags"],
check=False,
text=True,
@@ -44,7 +45,7 @@ def test_run(mock_run: Mock) -> None:
check=True,
remote=m.Remote("user@localhost", ["--ssh", "opt"], "password"),
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"ssh",
"--ssh",
@@ -70,7 +71,7 @@ def test_run(mock_run: Mock) -> None:
extra_env={"FOO": "bar"},
remote=m.Remote("user@localhost", ["--ssh", "opt"], "password"),
)
assert mock_run.call_args == call(
mock_run.assert_called_with(
[
"ssh",
"--ssh",
@@ -13,7 +13,7 @@ let
escapeExpect = lib.strings.escapeNixString;
expectSetup = ''
set timeout 180
set timeout 300
proc expect_simple { pattern } {
puts "Expecting: $pattern"
expect {
@@ -76,7 +76,7 @@ runCommand "test-nixos-rebuild-repl"
expect ${writeText "test-nixos-rebuild-repl-expect" ''
${expectSetup}
spawn nixos-rebuild repl --fast
spawn nixos-rebuild repl --no-reexec
expect "nix-repl> "
@@ -116,7 +116,7 @@ runCommand "test-nixos-rebuild-repl"
expect ${writeText "test-nixos-rebuild-repl-absolute-path-expect" ''
${expectSetup}
spawn sh -c "nixos-rebuild repl --fast --flake path:\$HOME#testconf"
spawn sh -c "nixos-rebuild repl --no-reexec --flake path:\$HOME#testconf"
expect_simple "nix-repl>"
@@ -146,7 +146,7 @@ runCommand "test-nixos-rebuild-repl"
pushd "$HOME"
expect ${writeText "test-nixos-rebuild-repl-relative-path-expect" ''
${expectSetup}
spawn sh -c "nixos-rebuild repl --fast --flake .#testconf"
spawn sh -c "nixos-rebuild repl --no-reexec --flake .#testconf"
expect_simple "nix-repl>"