From 761e1f5aa13201e5677e115ecd2c1f4aef31a3b6 Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Thu, 13 Feb 2025 19:28:53 +0000 Subject: [PATCH 1/7] nixos-rebuild-ng: add test_reexec and test_reexec_flake --- .../nixos-rebuild-ng/src/tests/test_main.py | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py index 823bc9bff536..347dbc228650 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py @@ -7,6 +7,7 @@ from typing import Any from unittest.mock import ANY, Mock, call, patch import pytest +from pytest import MonkeyPatch import nixos_rebuild as nr @@ -125,6 +126,96 @@ def test_parse_args() -> None: ] +@patch.dict(nr.os.environ, {}, clear=True) +@patch(get_qualified_name(nr.os.execve, nr.os), autospec=True) +@patch(get_qualified_name(nr.nix.build), autospec=True) +def test_reexec(mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr(nr, "EXECUTABLE", "nixos-rebuild-ng") + argv = ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"] + args, _ = nr.parse_args(argv) + mock_build.return_value = Path("/path") + + nr.reexec(argv, args, {"build": True}, {"flake": True}) + assert mock_build.call_args_list == [ + call( + "config.system.build.nixos-rebuild", + nr.models.BuildAttr(ANY, ANY), + {"build": True, "no_out_link": True}, + ) + ] + # do not exec if there is no new version + assert mock_execve.call_args_list == [] + + mock_build.return_value = Path("/path/new") + + nr.reexec(argv, args, {}, {}) + # exec in the new version successfully + assert mock_execve.call_args_list == [ + call( + Path("/path/new/bin/nixos-rebuild-ng"), + ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"], + {"_NIXOS_REBUILD_REEXEC": "1"}, + ) + ] + + mock_execve.reset_mock() + mock_execve.side_effect = [OSError("BOOM"), None] + + nr.reexec(argv, args, {}, {}) + # exec in the previous version if the new version fails + assert mock_execve.call_args == call( + Path("/path/bin/nixos-rebuild-ng"), + ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"], + {"_NIXOS_REBUILD_REEXEC": "1"}, + ) + + +@patch.dict(nr.os.environ, {}, clear=True) +@patch(get_qualified_name(nr.os.execve, nr.os), autospec=True) +@patch(get_qualified_name(nr.nix.build_flake), autospec=True) +def test_reexec_flake( + mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch +) -> None: + monkeypatch.setattr(nr, "EXECUTABLE", "nixos-rebuild-ng") + argv = ["/path/bin/nixos-rebuild-ng", "switch", "--flake"] + args, _ = nr.parse_args(argv) + mock_build.return_value = Path("/path") + + nr.reexec(argv, args, {"build": True}, {"flake": True}) + assert mock_build.call_args_list == [ + call( + "config.system.build.nixos-rebuild", + nr.models.Flake(ANY, ANY), + {"flake": True, "no_link": True}, + ) + ] + # do not exec if there is no new version + assert mock_execve.call_args_list == [] + + mock_build.return_value = Path("/path/new") + + nr.reexec(argv, args, {}, {}) + # exec in the new version successfully + assert mock_execve.call_args_list == [ + call( + Path("/path/new/bin/nixos-rebuild-ng"), + ["/path/bin/nixos-rebuild-ng", "switch", "--flake"], + {"_NIXOS_REBUILD_REEXEC": "1"}, + ) + ] + + mock_execve.reset_mock() + mock_execve.side_effect = [OSError("BOOM"), None] + + nr.reexec(argv, args, {}, {}) + # exec in the previous version if the new version fails + assert mock_execve.call_args == call( + Path("/path/bin/nixos-rebuild-ng"), + ["/path/bin/nixos-rebuild-ng", "switch", "--flake"], + {"_NIXOS_REBUILD_REEXEC": "1"}, + ) + + @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: From 52c671bafbc176f4583c5474b7f10e63b6980900 Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Thu, 13 Feb 2025 21:23:37 +0000 Subject: [PATCH 2/7] Revert "nixos-rebuild-ng: {assert_called_with,assert_has_calls} -> {call_args,call_args_list}" This reverts commit d6e849ee03d1849bd5151c651e66a8731a0c4891. It was a bad idea, the diffs are even worse than before for anything that has more 2 calls. --- .../nixos-rebuild-ng/src/tests/test_main.py | 1031 +++++++++-------- .../nixos-rebuild-ng/src/tests/test_models.py | 10 +- .../ni/nixos-rebuild-ng/src/tests/test_nix.py | 327 +++--- .../src/tests/test_process.py | 13 +- 4 files changed, 704 insertions(+), 677 deletions(-) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py index 347dbc228650..e6d40bc8bd19 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py @@ -4,7 +4,7 @@ import uuid from pathlib import Path from subprocess import PIPE, CompletedProcess from typing import Any -from unittest.mock import ANY, Mock, call, patch +from unittest.mock import ANY, call, patch import pytest from pytest import MonkeyPatch @@ -218,7 +218,7 @@ def test_reexec_flake( @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_nix_boot(mock_run: Any, tmp_path: Path) -> None: nixpkgs_path = tmp_path / "nixpkgs" nixpkgs_path.mkdir() config_path = tmp_path / "test" @@ -238,59 +238,62 @@ def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: nr.execute(["nixos-rebuild", "boot", "--no-flake", "-vvv", "--no-reexec"]) - assert mock_run.call_args_list == [ - call( - ["nix-instantiate", "--find-file", "nixpkgs", "-vvv"], - stdout=PIPE, - check=False, - **DEFAULT_RUN_KWARGS, - ), - call( - ["git", "-C", nixpkgs_path, "rev-parse", "--short", "HEAD"], - check=False, - capture_output=True, - **DEFAULT_RUN_KWARGS, - ), - call( - ["git", "-C", nixpkgs_path, "diff", "--quiet"], - check=False, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix-build", - "", - "--attr", - "config.system.build.toplevel", - "-vvv", - "--no-out-link", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix-env", - "-p", - Path("/nix/var/nix/profiles/system"), - "--set", - config_path, - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [config_path / "bin/switch-to-configuration", "boot"], - check=True, - **(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "0"}}), - ), - ] + assert mock_run.call_count == 6 + mock_run.assert_has_calls( + [ + call( + ["nix-instantiate", "--find-file", "nixpkgs", "-vvv"], + stdout=PIPE, + check=False, + **DEFAULT_RUN_KWARGS, + ), + call( + ["git", "-C", nixpkgs_path, "rev-parse", "--short", "HEAD"], + check=False, + capture_output=True, + **DEFAULT_RUN_KWARGS, + ), + call( + ["git", "-C", nixpkgs_path, "diff", "--quiet"], + check=False, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix-build", + "", + "--attr", + "config.system.build.toplevel", + "-vvv", + "--no-out-link", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix-env", + "-p", + Path("/nix/var/nix/profiles/system"), + "--set", + config_path, + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [config_path / "bin/switch-to-configuration", "boot"], + check=True, + **(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "0"}}), + ), + ] + ) @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_build_vm(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_nix_build_vm(mock_run: Any, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -315,28 +318,31 @@ def test_execute_nix_build_vm(mock_run: Mock, tmp_path: Path) -> None: ] ) - assert mock_run.call_args_list == [ - call( - [ - "nix-build", - "", - "--attr", - "config.system.build.vm", - "--include", - "nixos-config=./configuration.nix", - "--include", - "nixpkgs=$HOME/.nix-defexpr/channels/pinned_nixpkgs", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ) - ] + assert mock_run.call_count == 1 + mock_run.assert_has_calls( + [ + call( + [ + "nix-build", + "", + "--attr", + "config.system.build.vm", + "--include", + "nixos-config=./configuration.nix", + "--include", + "nixpkgs=$HOME/.nix-defexpr/channels/pinned_nixpkgs", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ) + ] + ) @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_nix_build_image_flake(mock_run: Any, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -370,39 +376,42 @@ def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None: ] ) - assert mock_run.call_args_list == [ - call( - [ - "nix", - "eval", - "--json", - "/path/to/config#nixosConfigurations.hostname.config.system.build.images", - "--apply", - "builtins.mapAttrs (n: v: v.passthru.filePath)", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "build", - "--print-out-paths", - "/path/to/config#nixosConfigurations.hostname.config.system.build.images.azure", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 2 + mock_run.assert_has_calls( + [ + call( + [ + "nix", + "eval", + "--json", + "/path/to/config#nixosConfigurations.hostname.config.system.build.images", + "--apply", + "builtins.mapAttrs (n: v: v.passthru.filePath)", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "build", + "--print-out-paths", + "/path/to/config#nixosConfigurations.hostname.config.system.build.images.azure", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + ] + ) @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_nix_switch_flake(mock_run: Any, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -431,43 +440,46 @@ def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: ] ) - assert mock_run.call_args_list == [ - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "build", - "--print-out-paths", - "/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel", - "-v", - "--option", - "narinfo-cache-negative-ttl", - "1200", - "--no-link", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "sudo", - "nix-env", - "-p", - Path("/nix/var/nix/profiles/system"), - "--set", - config_path, - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - ["sudo", config_path / "bin/switch-to-configuration", "switch"], - check=True, - **(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "1"}}), - ), - ] + assert mock_run.call_count == 3 + mock_run.assert_has_calls( + [ + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "build", + "--print-out-paths", + "/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel", + "-v", + "--option", + "narinfo-cache-negative-ttl", + "1200", + "--no-link", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "sudo", + "nix-env", + "-p", + Path("/nix/var/nix/profiles/system"), + "--set", + config_path, + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + ["sudo", config_path / "bin/switch-to-configuration", "switch"], + check=True, + **(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "1"}}), + ), + ] + ) @patch.dict(nr.process.os.environ, {}, clear=True) @@ -475,9 +487,9 @@ def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: @patch(get_qualified_name(nr.cleanup_ssh, nr), autospec=True) @patch(get_qualified_name(nr.nix.uuid4, nr.nix), autospec=True) def test_execute_nix_switch_build_target_host( - mock_uuid4: Mock, - mock_cleanup_ssh: Mock, - mock_run: Mock, + mock_uuid4: Any, + mock_cleanup_ssh: Any, + mock_run: Any, tmp_path: Path, ) -> None: config_path = tmp_path / "test" @@ -521,154 +533,157 @@ def test_execute_nix_switch_build_target_host( ] ) - assert mock_run.call_args_list == [ - call( - [ - "nix-instantiate", - "--find-file", - "nixpkgs", - "--include", - "nixos-config=./configuration.nix", - "--include", - "nixpkgs=$HOME/.nix-defexpr/channels/pinned_nixpkgs", - ], - check=False, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix-instantiate", - "", - "--attr", - "config.system.build.toplevel", - "--add-root", - nr.tmpdir.TMPDIR_PATH / "00000000000000000000000000000000", - "--include", - "nixos-config=./configuration.nix", - "--include", - "nixpkgs=$HOME/.nix-defexpr/channels/pinned_nixpkgs", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - ["nix-copy-closure", "--to", "user@build-host", config_path], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@build-host", - "--", - "mktemp", - "-d", - "-t", - "nixos-rebuild.XXXXX", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@build-host", - "--", - "nix-store", - "--realise", - str(config_path), - "--add-root", - "/tmp/tmpdir/00000000000000000000000000000000", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@build-host", - "--", - "readlink", - "-f", - "/tmp/tmpdir/config", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@build-host", - "--", - "rm", - "-rf", - "/tmp/tmpdir", - ], - check=False, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix", - "copy", - "--from", - "ssh://user@build-host", - "--to", - "ssh://user@target-host", - config_path, - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@target-host", - "--", - "sudo", - "nix-env", - "-p", - "/nix/var/nix/profiles/system", - "--set", - str(config_path), - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@target-host", - "--", - "sudo", - "env", - "NIXOS_INSTALL_BOOTLOADER=0", - str(config_path / "bin/switch-to-configuration"), - "switch", - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 10 + mock_run.assert_has_calls( + [ + call( + [ + "nix-instantiate", + "--find-file", + "nixpkgs", + "--include", + "nixos-config=./configuration.nix", + "--include", + "nixpkgs=$HOME/.nix-defexpr/channels/pinned_nixpkgs", + ], + check=False, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix-instantiate", + "", + "--attr", + "config.system.build.toplevel", + "--add-root", + nr.tmpdir.TMPDIR_PATH / "00000000000000000000000000000000", + "--include", + "nixos-config=./configuration.nix", + "--include", + "nixpkgs=$HOME/.nix-defexpr/channels/pinned_nixpkgs", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + ["nix-copy-closure", "--to", "user@build-host", config_path], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@build-host", + "--", + "mktemp", + "-d", + "-t", + "nixos-rebuild.XXXXX", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@build-host", + "--", + "nix-store", + "--realise", + str(config_path), + "--add-root", + "/tmp/tmpdir/00000000000000000000000000000000", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@build-host", + "--", + "readlink", + "-f", + "/tmp/tmpdir/config", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@build-host", + "--", + "rm", + "-rf", + "/tmp/tmpdir", + ], + check=False, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix", + "copy", + "--from", + "ssh://user@build-host", + "--to", + "ssh://user@target-host", + config_path, + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@target-host", + "--", + "sudo", + "nix-env", + "-p", + "/nix/var/nix/profiles/system", + "--set", + str(config_path), + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@target-host", + "--", + "sudo", + "env", + "NIXOS_INSTALL_BOOTLOADER=0", + str(config_path / "bin/switch-to-configuration"), + "switch", + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + ] + ) @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) @patch(get_qualified_name(nr.cleanup_ssh, nr), autospec=True) def test_execute_nix_switch_flake_target_host( - mock_cleanup_ssh: Mock, - mock_run: Mock, + mock_cleanup_ssh: Any, + mock_run: Any, tmp_path: Path, ) -> None: config_path = tmp_path / "test" @@ -695,66 +710,69 @@ def test_execute_nix_switch_flake_target_host( ] ) - assert mock_run.call_args_list == [ - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "build", - "--print-out-paths", - "/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel", - "--no-link", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - ["nix-copy-closure", "--to", "user@localhost", config_path], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@localhost", - "--", - "sudo", - "nix-env", - "-p", - "/nix/var/nix/profiles/system", - "--set", - str(config_path), - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@localhost", - "--", - "sudo", - "env", - "NIXOS_INSTALL_BOOTLOADER=0", - str(config_path / "bin/switch-to-configuration"), - "switch", - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 4 + mock_run.assert_has_calls( + [ + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "build", + "--print-out-paths", + "/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel", + "--no-link", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + ["nix-copy-closure", "--to", "user@localhost", config_path], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@localhost", + "--", + "sudo", + "nix-env", + "-p", + "/nix/var/nix/profiles/system", + "--set", + str(config_path), + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@localhost", + "--", + "sudo", + "env", + "NIXOS_INSTALL_BOOTLOADER=0", + str(config_path / "bin/switch-to-configuration"), + "switch", + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + ] + ) @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) @patch(get_qualified_name(nr.cleanup_ssh, nr), autospec=True) def test_execute_nix_switch_flake_build_host( - mock_cleanup_ssh: Mock, - mock_run: Mock, + mock_cleanup_ssh: Any, + mock_run: Any, tmp_path: Path, ) -> None: config_path = tmp_path / "test" @@ -782,74 +800,77 @@ def test_execute_nix_switch_flake_build_host( ] ) - assert mock_run.call_args_list == [ - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "eval", - "--raw", - "/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel.drvPath", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - ["nix-copy-closure", "--to", "user@localhost", config_path], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "ssh", - *nr.process.SSH_DEFAULT_OPTS, - "user@localhost", - "--", - "nix", - "--extra-experimental-features", - "'nix-command flakes'", - "build", - f"'{config_path}^*'", - "--print-out-paths", - "--no-link", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix-copy-closure", - "--from", - "user@localhost", - config_path, - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix-env", - "-p", - Path("/nix/var/nix/profiles/system"), - "--set", - config_path, - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [config_path / "bin/switch-to-configuration", "switch"], - check=True, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 6 + mock_run.assert_has_calls( + [ + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "eval", + "--raw", + "/path/to/config#nixosConfigurations.hostname.config.system.build.toplevel.drvPath", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + ["nix-copy-closure", "--to", "user@localhost", config_path], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "ssh", + *nr.process.SSH_DEFAULT_OPTS, + "user@localhost", + "--", + "nix", + "--extra-experimental-features", + "'nix-command flakes'", + "build", + f"'{config_path}^*'", + "--print-out-paths", + "--no-link", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix-copy-closure", + "--from", + "user@localhost", + config_path, + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix-env", + "-p", + Path("/nix/var/nix/profiles/system"), + "--set", + config_path, + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [config_path / "bin/switch-to-configuration", "switch"], + check=True, + **DEFAULT_RUN_KWARGS, + ), + ] + ) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_switch_rollback(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_switch_rollback(mock_run: Any, tmp_path: Path) -> None: nixpkgs_path = tmp_path / "nixpkgs" nixpkgs_path.touch() @@ -874,49 +895,52 @@ def test_execute_switch_rollback(mock_run: Mock, tmp_path: Path) -> None: ] ) - assert mock_run.call_args_list == [ - call( - ["nix-instantiate", "--find-file", "nixpkgs"], - check=False, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "git", - "-C", - nixpkgs_path, - "rev-parse", - "--short", - "HEAD", - ], - check=False, - capture_output=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - "nix-env", - "--rollback", - "-p", - Path("/nix/var/nix/profiles/system"), - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - Path("/nix/var/nix/profiles/system/bin/switch-to-configuration"), - "switch", - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 4 + mock_run.assert_has_calls( + [ + call( + ["nix-instantiate", "--find-file", "nixpkgs"], + check=False, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "git", + "-C", + nixpkgs_path, + "rev-parse", + "--short", + "HEAD", + ], + check=False, + capture_output=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + "nix-env", + "--rollback", + "-p", + Path("/nix/var/nix/profiles/system"), + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + Path("/nix/var/nix/profiles/system/bin/switch-to-configuration"), + "switch", + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + ] + ) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_build(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_build(mock_run: Any, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() mock_run.side_effect = [ @@ -926,23 +950,26 @@ def test_execute_build(mock_run: Mock, tmp_path: Path) -> None: nr.execute(["nixos-rebuild", "build", "--no-flake", "--no-reexec"]) - assert mock_run.call_args_list == [ - call( - [ - "nix-build", - "", - "--attr", - "config.system.build.toplevel", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ) - ] + assert mock_run.call_count == 1 + mock_run.assert_has_calls( + [ + call( + [ + "nix-build", + "", + "--attr", + "config.system.build.toplevel", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ) + ] + ) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_test_flake(mock_run: Mock, tmp_path: Path) -> None: +def test_execute_test_flake(mock_run: Any, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -958,35 +985,38 @@ def test_execute_test_flake(mock_run: Mock, tmp_path: Path) -> None: ["nixos-rebuild", "test", "--flake", "github:user/repo#hostname", "--no-reexec"] ) - assert mock_run.call_args_list == [ - call( - [ - "nix", - "--extra-experimental-features", - "nix-command flakes", - "build", - "--print-out-paths", - "github:user/repo#nixosConfigurations.hostname.config.system.build.toplevel", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [config_path / "bin/switch-to-configuration", "test"], - check=True, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 2 + mock_run.assert_has_calls( + [ + call( + [ + "nix", + "--extra-experimental-features", + "nix-command flakes", + "build", + "--print-out-paths", + "github:user/repo#nixosConfigurations.hostname.config.system.build.toplevel", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [config_path / "bin/switch-to-configuration", "test"], + check=True, + **DEFAULT_RUN_KWARGS, + ), + ] + ) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) @patch(get_qualified_name(nr.nix.Path.exists, nr.nix), autospec=True, return_value=True) @patch(get_qualified_name(nr.nix.Path.mkdir, nr.nix), autospec=True) def test_execute_test_rollback( - mock_path_mkdir: Mock, - mock_path_exists: Mock, - mock_run: Mock, + mock_path_mkdir: Any, + mock_path_exists: Any, + mock_run: Any, ) -> None: def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]: if args[0] == "nix-env": @@ -1008,26 +1038,29 @@ def test_execute_test_rollback( ["nixos-rebuild", "test", "--rollback", "--profile-name", "foo", "--no-reexec"] ) - assert mock_run.call_args_list == [ - call( - [ - "nix-env", - "-p", - Path("/nix/var/nix/profiles/system-profiles/foo"), - "--list-generations", - ], - check=True, - stdout=PIPE, - **DEFAULT_RUN_KWARGS, - ), - call( - [ - Path( - "/nix/var/nix/profiles/system-profiles/foo-2083-link/bin/switch-to-configuration" - ), - "test", - ], - check=True, - **DEFAULT_RUN_KWARGS, - ), - ] + assert mock_run.call_count == 2 + mock_run.assert_has_calls( + [ + call( + [ + "nix-env", + "-p", + Path("/nix/var/nix/profiles/system-profiles/foo"), + "--list-generations", + ], + check=True, + stdout=PIPE, + **DEFAULT_RUN_KWARGS, + ), + call( + [ + Path( + "/nix/var/nix/profiles/system-profiles/foo-2083-link/bin/switch-to-configuration" + ), + "test", + ], + check=True, + **DEFAULT_RUN_KWARGS, + ), + ] + ) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py index cb318192fc2e..e02fc69848fb 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py @@ -1,7 +1,8 @@ import platform import subprocess from pathlib import Path -from unittest.mock import Mock, patch +from typing import Any +from unittest.mock import patch from pytest import MonkeyPatch @@ -78,9 +79,7 @@ def test_flake_to_attr() -> None: @patch(get_qualified_name(platform.node), autospec=True) -def test_flake_from_arg( - mock_node: Mock, monkeypatch: MonkeyPatch, tmpdir: Path -) -> None: +def test_flake_from_arg(mock_node: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: mock_node.return_value = "hostname" # Flake string @@ -162,12 +161,11 @@ def test_flake_from_arg( @patch(get_qualified_name(m.Path.mkdir, m), autospec=True) -def test_profile_from_arg(mock_mkdir: Mock) -> None: +def test_profile_from_arg(mock_mkdir: Any) -> None: assert m.Profile.from_arg("system") == m.Profile( "system", Path("/nix/var/nix/profiles/system"), ) - mock_mkdir.assert_not_called() assert m.Profile.from_arg("something") == m.Profile( "something", diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py index 861ba7ae0617..35fea00cbeef 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py @@ -3,7 +3,7 @@ import uuid from pathlib import Path from subprocess import PIPE, CompletedProcess from typing import Any -from unittest.mock import ANY, Mock, call, patch +from unittest.mock import ANY, call, patch import pytest from pytest import MonkeyPatch @@ -20,13 +20,13 @@ from .helpers import get_qualified_name autospec=True, return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), ) -def test_build(mock_run: Mock) -> None: +def test_build(mock_run: Any) -> None: assert n.build( "config.system.build.attr", m.BuildAttr("", None), {"nix_flag": "foo"}, ) == Path("/path/to/file") - assert mock_run.call_args == call( + mock_run.assert_called_with( [ "nix-build", "", @@ -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( @@ -56,7 +52,7 @@ def test_build(mock_run: Mock) -> None: autospec=True, return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), ) -def test_build_flake(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: +def test_build_flake(mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: monkeypatch.chdir(tmpdir) flake = m.Flake.parse(".#hostname") @@ -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", @@ -83,9 +79,7 @@ def test_build_flake(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> @patch(get_qualified_name(n.run_wrapper, n), autospec=True) @patch(get_qualified_name(n.uuid4, n), autospec=True) -def test_build_remote( - mock_uuid4: Mock, mock_run: Mock, monkeypatch: MonkeyPatch -) -> None: +def test_build_remote(mock_uuid4: Any, mock_run: Any, monkeypatch: MonkeyPatch) -> None: build_host = m.Remote("user@host", [], None) monkeypatch.setenv("NIX_SSHOPTS", "--ssh opts") @@ -114,53 +108,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", - "", - "--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", + "", + "--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( @@ -169,7 +168,7 @@ def test_build_remote( return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), ) def test_build_remote_flake( - mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path + mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path ) -> None: monkeypatch.chdir(tmpdir) flake = m.Flake.parse(".#hostname") @@ -184,43 +183,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 +236,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 +244,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 +258,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,24 +275,26 @@ 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) -def test_edit(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: +def test_edit(mock_run: Any, 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 +316,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( @@ -328,13 +333,13 @@ def test_edit(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: """, ), ) -def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None: +def test_get_build_image_variants(mock_run: Any, tmp_path: Path) -> None: build_attr = m.BuildAttr("", None) assert n.get_build_image_variants(build_attr) == { "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 +357,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", @@ -393,13 +396,13 @@ def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None: """, ), ) -def test_get_build_image_variants_flake(mock_run: Mock) -> None: +def test_get_build_image_variants_flake(mock_run: Any) -> None: flake = m.Flake(Path("flake.nix"), "myAttr") assert n.get_build_image_variants_flake(flake, {"eval_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", "eval", @@ -424,7 +427,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 +454,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 +465,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 +506,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 +524,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, @@ -545,7 +548,7 @@ def test_get_generations_from_nix_env(tmp_path: Path) -> None: ), ], ) -def test_list_generations(mock_get_generations: Mock, tmp_path: Path) -> None: +def test_list_generations(mock_get_generations: Any, tmp_path: Path) -> None: # Probably better to test this function in a real system, this test is # mostly to make sure it doesn't break horribly assert n.list_generations(m.Profile("system", tmp_path)) == [ @@ -571,20 +574,18 @@ 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: +def test_repl(mock_run: Any) -> None: n.repl("attr", m.BuildAttr("", None), {"nix_flag": True}) - assert mock_run.call_args == call( + mock_run.assert_called_with( ["nix", "repl", "--file", "", "--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) -def test_repl_flake(mock_run: Mock) -> None: +def test_repl_flake(mock_run: Any) -> None: n.repl_flake("attr", m.Flake(Path("flake.nix"), "myAttr"), {"nix_flag": True}) # See nixos-rebuild-ng.tests.repl for a better test, # this is mostly for sanity check @@ -592,14 +593,14 @@ def test_repl_flake(mock_run: Mock) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_rollback(mock_run: Mock, tmp_path: Path) -> None: +def test_rollback(mock_run: Any, tmp_path: Path) -> None: path = tmp_path / "test" path.touch() 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 +608,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 +620,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 +629,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 +651,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,16 +663,13 @@ 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 @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_set_profile(mock_run: Mock) -> None: +def test_set_profile(mock_run: Any) -> None: profile_path = Path("/path/to/profile") config_path = Path("/path/to/config") n.set_profile( @@ -684,7 +679,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, @@ -692,7 +687,7 @@ def test_set_profile(mock_run: Mock) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> None: +def test_switch_to_configuration(mock_run: Any, monkeypatch: MonkeyPatch) -> None: profile_path = Path("/path/to/profile") config_path = Path("/path/to/config") @@ -707,7 +702,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 +736,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", @@ -762,17 +757,17 @@ def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> No ], ) @patch(get_qualified_name(n.Path.is_dir, n), autospec=True, return_value=True) -def test_upgrade_channels(mock_is_dir: Mock, mock_glob: Mock) -> None: +def test_upgrade_channels(mock_is_dir: Any, mock_glob: Any) -> 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_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), + ] + ) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py index a62ee2355153..6458f54c06ef 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py @@ -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", From 8efe14c0245a86777a48bf64d27dba3606015237 Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Thu, 13 Feb 2025 21:27:19 +0000 Subject: [PATCH 3/7] nixos-rebuild-ng: add pytest-mock --- pkgs/by-name/ni/nixos-rebuild-ng/package.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/package.nix b/pkgs/by-name/ni/nixos-rebuild-ng/package.nix index df33313193fe..02e140fcc0a6 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/package.nix +++ b/pkgs/by-name/ni/nixos-rebuild-ng/package.nix @@ -89,6 +89,7 @@ python3Packages.buildPythonApplication rec { ps: with ps; [ mypy pytest + pytest-mock ruff ] ); From b0ba32b3e73fec51f00d4bb17fe690d235e8e36b Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Thu, 13 Feb 2025 21:30:17 +0000 Subject: [PATCH 4/7] nixos-rebuild-ng: add pytest-mock in devShell It is included to help debugging only, so its helpers shouldn't be used in tests. --- pkgs/by-name/ni/nixos-rebuild-ng/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/package.nix b/pkgs/by-name/ni/nixos-rebuild-ng/package.nix index 02e140fcc0a6..5f75a21e2402 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/package.nix +++ b/pkgs/by-name/ni/nixos-rebuild-ng/package.nix @@ -89,6 +89,8 @@ 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 ] From 83fc1380c37474fe987aadce26dd998bf71347a1 Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Thu, 13 Feb 2025 21:30:52 +0000 Subject: [PATCH 5/7] nixos-rebuild-ng: use Mock as type in test mocks --- .../nixos-rebuild-ng/src/tests/test_main.py | 36 +++++++++---------- .../nixos-rebuild-ng/src/tests/test_models.py | 9 ++--- .../ni/nixos-rebuild-ng/src/tests/test_nix.py | 32 +++++++++-------- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py index e6d40bc8bd19..249d7b059774 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py @@ -4,7 +4,7 @@ import uuid from pathlib import Path from subprocess import PIPE, CompletedProcess from typing import Any -from unittest.mock import ANY, call, patch +from unittest.mock import ANY, Mock, call, patch import pytest from pytest import MonkeyPatch @@ -218,7 +218,7 @@ def test_reexec_flake( @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_boot(mock_run: Any, tmp_path: Path) -> None: +def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: nixpkgs_path = tmp_path / "nixpkgs" nixpkgs_path.mkdir() config_path = tmp_path / "test" @@ -293,7 +293,7 @@ def test_execute_nix_boot(mock_run: Any, tmp_path: Path) -> None: @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_build_vm(mock_run: Any, tmp_path: Path) -> None: +def test_execute_nix_build_vm(mock_run: Mock, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -342,7 +342,7 @@ def test_execute_nix_build_vm(mock_run: Any, tmp_path: Path) -> None: @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_build_image_flake(mock_run: Any, tmp_path: Path) -> None: +def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -411,7 +411,7 @@ def test_execute_nix_build_image_flake(mock_run: Any, tmp_path: Path) -> None: @patch.dict(nr.process.os.environ, {}, clear=True) @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_nix_switch_flake(mock_run: Any, tmp_path: Path) -> None: +def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -487,9 +487,9 @@ def test_execute_nix_switch_flake(mock_run: Any, tmp_path: Path) -> None: @patch(get_qualified_name(nr.cleanup_ssh, nr), autospec=True) @patch(get_qualified_name(nr.nix.uuid4, nr.nix), autospec=True) def test_execute_nix_switch_build_target_host( - mock_uuid4: Any, - mock_cleanup_ssh: Any, - mock_run: Any, + mock_uuid4: Mock, + mock_cleanup_ssh: Mock, + mock_run: Mock, tmp_path: Path, ) -> None: config_path = tmp_path / "test" @@ -682,8 +682,8 @@ def test_execute_nix_switch_build_target_host( @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) @patch(get_qualified_name(nr.cleanup_ssh, nr), autospec=True) def test_execute_nix_switch_flake_target_host( - mock_cleanup_ssh: Any, - mock_run: Any, + mock_cleanup_ssh: Mock, + mock_run: Mock, tmp_path: Path, ) -> None: config_path = tmp_path / "test" @@ -771,8 +771,8 @@ def test_execute_nix_switch_flake_target_host( @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) @patch(get_qualified_name(nr.cleanup_ssh, nr), autospec=True) def test_execute_nix_switch_flake_build_host( - mock_cleanup_ssh: Any, - mock_run: Any, + mock_cleanup_ssh: Mock, + mock_run: Mock, tmp_path: Path, ) -> None: config_path = tmp_path / "test" @@ -870,7 +870,7 @@ def test_execute_nix_switch_flake_build_host( @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_switch_rollback(mock_run: Any, tmp_path: Path) -> None: +def test_execute_switch_rollback(mock_run: Mock, tmp_path: Path) -> None: nixpkgs_path = tmp_path / "nixpkgs" nixpkgs_path.touch() @@ -940,7 +940,7 @@ def test_execute_switch_rollback(mock_run: Any, tmp_path: Path) -> None: @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_build(mock_run: Any, tmp_path: Path) -> None: +def test_execute_build(mock_run: Mock, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() mock_run.side_effect = [ @@ -969,7 +969,7 @@ def test_execute_build(mock_run: Any, tmp_path: Path) -> None: @patch(get_qualified_name(nr.process.subprocess.run), autospec=True) -def test_execute_test_flake(mock_run: Any, tmp_path: Path) -> None: +def test_execute_test_flake(mock_run: Mock, tmp_path: Path) -> None: config_path = tmp_path / "test" config_path.touch() @@ -1014,9 +1014,9 @@ def test_execute_test_flake(mock_run: Any, tmp_path: Path) -> None: @patch(get_qualified_name(nr.nix.Path.exists, nr.nix), autospec=True, return_value=True) @patch(get_qualified_name(nr.nix.Path.mkdir, nr.nix), autospec=True) def test_execute_test_rollback( - mock_path_mkdir: Any, - mock_path_exists: Any, - mock_run: Any, + mock_path_mkdir: Mock, + mock_path_exists: Mock, + mock_run: Mock, ) -> None: def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]: if args[0] == "nix-env": diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py index e02fc69848fb..3c6859015489 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py @@ -1,8 +1,7 @@ import platform import subprocess from pathlib import Path -from typing import Any -from unittest.mock import patch +from unittest.mock import Mock, patch from pytest import MonkeyPatch @@ -79,7 +78,9 @@ def test_flake_to_attr() -> None: @patch(get_qualified_name(platform.node), autospec=True) -def test_flake_from_arg(mock_node: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: +def test_flake_from_arg( + mock_node: Mock, monkeypatch: MonkeyPatch, tmpdir: Path +) -> None: mock_node.return_value = "hostname" # Flake string @@ -161,7 +162,7 @@ def test_flake_from_arg(mock_node: Any, monkeypatch: MonkeyPatch, tmpdir: Path) @patch(get_qualified_name(m.Path.mkdir, m), autospec=True) -def test_profile_from_arg(mock_mkdir: Any) -> None: +def test_profile_from_arg(mock_mkdir: Mock) -> None: assert m.Profile.from_arg("system") == m.Profile( "system", Path("/nix/var/nix/profiles/system"), diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py index 35fea00cbeef..ea937c06fcd3 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py @@ -3,7 +3,7 @@ import uuid from pathlib import Path from subprocess import PIPE, CompletedProcess from typing import Any -from unittest.mock import ANY, call, patch +from unittest.mock import ANY, Mock, call, patch import pytest from pytest import MonkeyPatch @@ -20,7 +20,7 @@ from .helpers import get_qualified_name autospec=True, return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), ) -def test_build(mock_run: Any) -> None: +def test_build(mock_run: Mock) -> None: assert n.build( "config.system.build.attr", m.BuildAttr("", None), @@ -52,7 +52,7 @@ def test_build(mock_run: Any) -> None: autospec=True, return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), ) -def test_build_flake(mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: +def test_build_flake(mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: monkeypatch.chdir(tmpdir) flake = m.Flake.parse(".#hostname") @@ -79,7 +79,9 @@ def test_build_flake(mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> N @patch(get_qualified_name(n.run_wrapper, n), autospec=True) @patch(get_qualified_name(n.uuid4, n), autospec=True) -def test_build_remote(mock_uuid4: Any, mock_run: Any, monkeypatch: MonkeyPatch) -> None: +def test_build_remote( + mock_uuid4: Mock, mock_run: Mock, monkeypatch: MonkeyPatch +) -> None: build_host = m.Remote("user@host", [], None) monkeypatch.setenv("NIX_SSHOPTS", "--ssh opts") @@ -168,7 +170,7 @@ def test_build_remote(mock_uuid4: Any, mock_run: Any, monkeypatch: MonkeyPatch) return_value=CompletedProcess([], 0, stdout=" \n/path/to/file\n "), ) def test_build_remote_flake( - mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path + mock_run: Mock, monkeypatch: MonkeyPatch, tmpdir: Path ) -> None: monkeypatch.chdir(tmpdir) flake = m.Flake.parse(".#hostname") @@ -290,7 +292,7 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_edit(mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: +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}) @@ -333,7 +335,7 @@ def test_edit(mock_run: Any, monkeypatch: MonkeyPatch, tmpdir: Path) -> None: """, ), ) -def test_get_build_image_variants(mock_run: Any, tmp_path: Path) -> None: +def test_get_build_image_variants(mock_run: Mock, tmp_path: Path) -> None: build_attr = m.BuildAttr("", None) assert n.get_build_image_variants(build_attr) == { "azure": "nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd", @@ -396,7 +398,7 @@ def test_get_build_image_variants(mock_run: Any, tmp_path: Path) -> None: """, ), ) -def test_get_build_image_variants_flake(mock_run: Any) -> None: +def test_get_build_image_variants_flake(mock_run: Mock) -> None: flake = m.Flake(Path("flake.nix"), "myAttr") assert n.get_build_image_variants_flake(flake, {"eval_flag": True}) == { "azure": "nixos-image-azure-25.05.20250102.6df2492-x86_64-linux.vhd", @@ -548,7 +550,7 @@ def test_get_generations_from_nix_env(tmp_path: Path) -> None: ), ], ) -def test_list_generations(mock_get_generations: Any, tmp_path: Path) -> None: +def test_list_generations(mock_get_generations: Mock, tmp_path: Path) -> None: # Probably better to test this function in a real system, this test is # mostly to make sure it doesn't break horribly assert n.list_generations(m.Profile("system", tmp_path)) == [ @@ -574,7 +576,7 @@ def test_list_generations(mock_get_generations: Any, tmp_path: Path) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_repl(mock_run: Any) -> None: +def test_repl(mock_run: Mock) -> None: n.repl("attr", m.BuildAttr("", None), {"nix_flag": True}) mock_run.assert_called_with( ["nix", "repl", "--file", "", "--nix-flag"] @@ -585,7 +587,7 @@ def test_repl(mock_run: Any) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_repl_flake(mock_run: Any) -> None: +def test_repl_flake(mock_run: Mock) -> None: n.repl_flake("attr", m.Flake(Path("flake.nix"), "myAttr"), {"nix_flag": True}) # See nixos-rebuild-ng.tests.repl for a better test, # this is mostly for sanity check @@ -593,7 +595,7 @@ def test_repl_flake(mock_run: Any) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_rollback(mock_run: Any, tmp_path: Path) -> None: +def test_rollback(mock_run: Mock, tmp_path: Path) -> None: path = tmp_path / "test" path.touch() @@ -669,7 +671,7 @@ def test_rollback_temporary_profile(tmp_path: Path) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_set_profile(mock_run: Any) -> None: +def test_set_profile(mock_run: Mock) -> None: profile_path = Path("/path/to/profile") config_path = Path("/path/to/config") n.set_profile( @@ -687,7 +689,7 @@ def test_set_profile(mock_run: Any) -> None: @patch(get_qualified_name(n.run_wrapper, n), autospec=True) -def test_switch_to_configuration(mock_run: Any, monkeypatch: MonkeyPatch) -> None: +def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> None: profile_path = Path("/path/to/profile") config_path = Path("/path/to/config") @@ -757,7 +759,7 @@ def test_switch_to_configuration(mock_run: Any, monkeypatch: MonkeyPatch) -> Non ], ) @patch(get_qualified_name(n.Path.is_dir, n), autospec=True, return_value=True) -def test_upgrade_channels(mock_is_dir: Any, mock_glob: Any) -> None: +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) mock_run.assert_called_with(["nix-channel", "--update", "nixos"], check=False) From f2df828138846ba168ce0ba2e7eecc9fcc0d6cba Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Thu, 13 Feb 2025 21:39:04 +0000 Subject: [PATCH 6/7] nixos-rebuild-ng: improve some tests --- .../nixos-rebuild-ng/src/tests/test_main.py | 60 +++++++++---------- .../nixos-rebuild-ng/src/tests/test_models.py | 1 + .../ni/nixos-rebuild-ng/src/tests/test_nix.py | 2 +- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py index 249d7b059774..2e9363e2869a 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py @@ -136,34 +136,34 @@ def test_reexec(mock_build: Mock, mock_execve: Mock, monkeypatch: MonkeyPatch) - mock_build.return_value = Path("/path") nr.reexec(argv, args, {"build": True}, {"flake": True}) - assert mock_build.call_args_list == [ - call( - "config.system.build.nixos-rebuild", - nr.models.BuildAttr(ANY, ANY), - {"build": True, "no_out_link": True}, - ) - ] + mock_build.assert_has_calls( + [ + call( + "config.system.build.nixos-rebuild", + nr.models.BuildAttr(ANY, ANY), + {"build": True, "no_out_link": True}, + ) + ] + ) # do not exec if there is no new version - assert mock_execve.call_args_list == [] + mock_execve.assert_not_called() mock_build.return_value = Path("/path/new") nr.reexec(argv, args, {}, {}) # exec in the new version successfully - assert mock_execve.call_args_list == [ - call( - Path("/path/new/bin/nixos-rebuild-ng"), - ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"], - {"_NIXOS_REBUILD_REEXEC": "1"}, - ) - ] + mock_execve.assert_called_once_with( + Path("/path/new/bin/nixos-rebuild-ng"), + ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"], + {"_NIXOS_REBUILD_REEXEC": "1"}, + ) mock_execve.reset_mock() mock_execve.side_effect = [OSError("BOOM"), None] nr.reexec(argv, args, {}, {}) # exec in the previous version if the new version fails - assert mock_execve.call_args == call( + mock_execve.assert_any_call( Path("/path/bin/nixos-rebuild-ng"), ["/path/bin/nixos-rebuild-ng", "switch", "--no-flake"], {"_NIXOS_REBUILD_REEXEC": "1"}, @@ -182,34 +182,30 @@ def test_reexec_flake( mock_build.return_value = Path("/path") nr.reexec(argv, args, {"build": True}, {"flake": True}) - assert mock_build.call_args_list == [ - call( - "config.system.build.nixos-rebuild", - nr.models.Flake(ANY, ANY), - {"flake": True, "no_link": True}, - ) - ] + mock_build.assert_called_once_with( + "config.system.build.nixos-rebuild", + nr.models.Flake(ANY, ANY), + {"flake": True, "no_link": True}, + ) # do not exec if there is no new version - assert mock_execve.call_args_list == [] + mock_execve.assert_not_called() mock_build.return_value = Path("/path/new") nr.reexec(argv, args, {}, {}) # exec in the new version successfully - assert mock_execve.call_args_list == [ - call( - Path("/path/new/bin/nixos-rebuild-ng"), - ["/path/bin/nixos-rebuild-ng", "switch", "--flake"], - {"_NIXOS_REBUILD_REEXEC": "1"}, - ) - ] + mock_execve.assert_called_once_with( + Path("/path/new/bin/nixos-rebuild-ng"), + ["/path/bin/nixos-rebuild-ng", "switch", "--flake"], + {"_NIXOS_REBUILD_REEXEC": "1"}, + ) mock_execve.reset_mock() mock_execve.side_effect = [OSError("BOOM"), None] nr.reexec(argv, args, {}, {}) # exec in the previous version if the new version fails - assert mock_execve.call_args == call( + mock_execve.assert_any_call( Path("/path/bin/nixos-rebuild-ng"), ["/path/bin/nixos-rebuild-ng", "switch", "--flake"], {"_NIXOS_REBUILD_REEXEC": "1"}, diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py index 3c6859015489..cb318192fc2e 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_models.py @@ -167,6 +167,7 @@ def test_profile_from_arg(mock_mkdir: Mock) -> None: "system", Path("/nix/var/nix/profiles/system"), ) + mock_mkdir.assert_not_called() assert m.Profile.from_arg("something") == m.Profile( "something", diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py index ea937c06fcd3..af8c0bdfd6a7 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py @@ -762,7 +762,7 @@ 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) - mock_run.assert_called_with(["nix-channel", "--update", "nixos"], check=False) + 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) From 91fd664d85d47c66821798f6ed2f01150a0fcf3c Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Fri, 14 Feb 2025 00:48:48 +0000 Subject: [PATCH 7/7] nixos-rebuild-ng: increase timeout for REPL tests --- pkgs/by-name/ni/nixos-rebuild-ng/tests/repl.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/tests/repl.nix b/pkgs/by-name/ni/nixos-rebuild-ng/tests/repl.nix index 1853a65bab86..1a614e8d8655 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/tests/repl.nix +++ b/pkgs/by-name/ni/nixos-rebuild-ng/tests/repl.nix @@ -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>"