mirror of
https://github.com/nix-community/nix-direnv.git
synced 2025-12-18 23:11:18 +01:00
Improve version testing logic and add relevant tests
This commit is contained in:
parent
add4b907c0
commit
445dc9ffc6
14 changed files with 62 additions and 10 deletions
0
tests/python/tests/__init__.py
Normal file
0
tests/python/tests/__init__.py
Normal file
18
tests/python/tests/conftest.py
Normal file
18
tests/python/tests/conftest.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
pytest_plugins = [
|
||||
"tests.direnv_project",
|
||||
"tests.root",
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _cleanenv(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
# so direnv doesn't touch $HOME
|
||||
monkeypatch.setenv("HOME", str(tmp_path / "home"))
|
||||
# so direnv allow state writes under tmp HOME
|
||||
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
|
||||
# so direnv does not pick up user customization
|
||||
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
|
||||
48
tests/python/tests/direnv_project.py
Normal file
48
tests/python/tests/direnv_project.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import shutil
|
||||
import textwrap
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import pytest
|
||||
|
||||
from .procs import run
|
||||
|
||||
|
||||
@dataclass
|
||||
class DirenvProject:
|
||||
directory: Path
|
||||
nix_direnv: Path
|
||||
|
||||
@property
|
||||
def envrc(self) -> Path:
|
||||
return self.directory / ".envrc"
|
||||
|
||||
def setup_envrc(self, content: str, strict_env: bool) -> None:
|
||||
text = textwrap.dedent(
|
||||
f"""
|
||||
{"strict_env" if strict_env else ""}
|
||||
source {self.nix_direnv}
|
||||
{content}
|
||||
"""
|
||||
)
|
||||
self.envrc.write_text(text)
|
||||
run(["direnv", "allow"], cwd=self.directory)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def direnv_project(test_root: Path, project_root: Path) -> Iterator[DirenvProject]:
|
||||
"""
|
||||
Setups a direnv test project
|
||||
"""
|
||||
with TemporaryDirectory() as _dir:
|
||||
directory = Path(_dir) / "proj"
|
||||
shutil.copytree(test_root / "testenv", directory)
|
||||
nix_direnv = project_root / "direnvrc"
|
||||
|
||||
c = DirenvProject(Path(directory), nix_direnv)
|
||||
try:
|
||||
yield c
|
||||
finally:
|
||||
pass
|
||||
27
tests/python/tests/procs.py
Normal file
27
tests/python/tests/procs.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import logging
|
||||
import shlex
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import IO, Any
|
||||
|
||||
_FILE = None | int | IO[Any]
|
||||
_DIR = None | Path | str
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run(
|
||||
cmd: list[str],
|
||||
text: bool = True,
|
||||
check: bool = True,
|
||||
cwd: _DIR = None,
|
||||
stderr: _FILE = None,
|
||||
stdout: _FILE = None,
|
||||
env: dict[str, str] | None = None,
|
||||
) -> subprocess.CompletedProcess:
|
||||
if cwd is not None:
|
||||
log.debug(f"cd {cwd}")
|
||||
log.debug(f"$ {shlex.join(cmd)}")
|
||||
return subprocess.run(
|
||||
cmd, text=text, check=check, cwd=cwd, stderr=stderr, stdout=stdout, env=env
|
||||
)
|
||||
22
tests/python/tests/root.py
Normal file
22
tests/python/tests/root.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
TEST_ROOT = Path(__file__).parent.resolve()
|
||||
PROJECT_ROOT = TEST_ROOT.parents[2]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_root() -> Path:
|
||||
"""
|
||||
Root directory of the tests
|
||||
"""
|
||||
return TEST_ROOT
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def project_root() -> Path:
|
||||
"""
|
||||
Root directory of the project
|
||||
"""
|
||||
return PROJECT_ROOT
|
||||
98
tests/python/tests/test_gc.py
Normal file
98
tests/python/tests/test_gc.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from .direnv_project import DirenvProject
|
||||
from .procs import run
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def common_test(direnv_project: DirenvProject) -> None:
|
||||
run(["nix-collect-garbage"])
|
||||
|
||||
testenv = str(direnv_project.directory)
|
||||
|
||||
out1 = run(
|
||||
["direnv", "exec", testenv, "hello"],
|
||||
stderr=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.directory,
|
||||
)
|
||||
sys.stderr.write(out1.stderr)
|
||||
assert out1.returncode == 0
|
||||
assert "Renewed cache" in out1.stderr
|
||||
assert "Executing shellHook." in out1.stderr
|
||||
|
||||
run(["nix-collect-garbage"])
|
||||
|
||||
out2 = run(
|
||||
["direnv", "exec", testenv, "hello"],
|
||||
stderr=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.directory,
|
||||
)
|
||||
sys.stderr.write(out2.stderr)
|
||||
assert out2.returncode == 0
|
||||
assert "Using cached dev shell" in out2.stderr
|
||||
assert "Executing shellHook." in out2.stderr
|
||||
|
||||
|
||||
def common_test_clean(direnv_project: DirenvProject) -> None:
|
||||
testenv = str(direnv_project.directory)
|
||||
|
||||
out3 = run(
|
||||
["direnv", "exec", testenv, "hello"],
|
||||
stderr=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.directory,
|
||||
)
|
||||
sys.stderr.write(out3.stderr)
|
||||
|
||||
files = [
|
||||
path
|
||||
for path in (direnv_project.directory / ".direnv").iterdir()
|
||||
if path.is_file()
|
||||
]
|
||||
rcs = [f for f in files if f.match("*.rc")]
|
||||
profiles = [f for f in files if not f.match("*.rc")]
|
||||
if len(rcs) != 1 or len(profiles) != 1:
|
||||
log.debug(files)
|
||||
assert len(rcs) == 1
|
||||
assert len(profiles) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("strict_env", [False, True])
|
||||
def test_use_nix(direnv_project: DirenvProject, strict_env: bool) -> None:
|
||||
direnv_project.setup_envrc("use nix", strict_env=strict_env)
|
||||
common_test(direnv_project)
|
||||
|
||||
direnv_project.setup_envrc(
|
||||
"use nix --argstr shellHook 'echo Executing hijacked shellHook.'",
|
||||
strict_env=strict_env,
|
||||
)
|
||||
common_test_clean(direnv_project)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("strict_env", [False, True])
|
||||
def test_use_flake(direnv_project: DirenvProject, strict_env: bool) -> None:
|
||||
direnv_project.setup_envrc("use flake", strict_env=strict_env)
|
||||
common_test(direnv_project)
|
||||
inputs = list((direnv_project.directory / ".direnv/flake-inputs").iterdir())
|
||||
# should only contain our flake-utils flake
|
||||
if len(inputs) != 4:
|
||||
run(["nix", "flake", "archive", "--json"], cwd=direnv_project.directory)
|
||||
log.debug(inputs)
|
||||
assert len(inputs) == 4
|
||||
for symlink in inputs:
|
||||
assert symlink.is_dir()
|
||||
|
||||
direnv_project.setup_envrc("use flake --impure", strict_env=strict_env)
|
||||
common_test_clean(direnv_project)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
71
tests/python/tests/test_use_nix.py
Normal file
71
tests/python/tests/test_use_nix.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from .direnv_project import DirenvProject
|
||||
from .procs import run
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def direnv_exec(
|
||||
direnv_project: DirenvProject, cmd: str, env: dict[str, str] | None = None
|
||||
) -> None:
|
||||
args = ["direnv", "exec", str(direnv_project.directory), "sh", "-c", cmd]
|
||||
log.debug(f"$ {shlex.join(args)}")
|
||||
out = run(
|
||||
args,
|
||||
stderr=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.directory,
|
||||
env=env,
|
||||
)
|
||||
sys.stdout.write(out.stdout)
|
||||
sys.stderr.write(out.stderr)
|
||||
assert out.returncode == 0
|
||||
assert out.stdout == "OK\n"
|
||||
assert "Renewed cache" in out.stderr
|
||||
|
||||
|
||||
@pytest.mark.parametrize("strict_env", [False, True])
|
||||
def test_attrs(direnv_project: DirenvProject, strict_env: bool) -> None:
|
||||
direnv_project.setup_envrc("use nix -A subshell", strict_env=strict_env)
|
||||
direnv_exec(direnv_project, "echo $THIS_IS_A_SUBSHELL")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("strict_env", [False, True])
|
||||
def test_no_nix_path(direnv_project: DirenvProject, strict_env: bool) -> None:
|
||||
direnv_project.setup_envrc("use nix --argstr someArg OK", strict_env=strict_env)
|
||||
env = os.environ.copy()
|
||||
del env["NIX_PATH"]
|
||||
direnv_exec(direnv_project, "echo $SHOULD_BE_SET", env=env)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("strict_env", [False, True])
|
||||
def test_args(direnv_project: DirenvProject, strict_env: bool) -> None:
|
||||
direnv_project.setup_envrc("use nix --argstr someArg OK", strict_env=strict_env)
|
||||
direnv_exec(direnv_project, "echo $SHOULD_BE_SET")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("strict_env", [False, True])
|
||||
def test_no_files(direnv_project: DirenvProject, strict_env: bool) -> None:
|
||||
direnv_project.setup_envrc("use nix -p hello", strict_env=strict_env)
|
||||
out = run(
|
||||
["direnv", "status"],
|
||||
stderr=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.directory,
|
||||
)
|
||||
assert out.returncode == 0
|
||||
assert 'Loaded watch: "."' not in out.stdout
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
61
tests/python/tests/testenv/flake.lock
generated
Normal file
61
tests/python/tests/testenv/flake.lock
generated
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1701401302,
|
||||
"narHash": "sha256-kfCOHzgtmHcgJwH7uagk8B+K1Qz58rN79eTLe55eGqA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "69a165d0fd2b08a78dbd2c98f6f860ceb2bbcd40",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
12
tests/python/tests/testenv/flake.nix
Normal file
12
tests/python/tests/testenv/flake.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
description = "A very basic flake";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
# deadnix: skip
|
||||
outputs =
|
||||
{ nixpkgs, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system: {
|
||||
devShell = import ./shell.nix { pkgs = nixpkgs.legacyPackages.${system}; };
|
||||
});
|
||||
}
|
||||
17
tests/python/tests/testenv/shell.nix
Normal file
17
tests/python/tests/testenv/shell.nix
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
pkgs ? import (builtins.getFlake (toString ./.)).inputs.nixpkgs { },
|
||||
someArg ? null,
|
||||
shellHook ? ''
|
||||
echo "Executing shellHook."
|
||||
'',
|
||||
}:
|
||||
pkgs.mkShellNoCC {
|
||||
inherit shellHook;
|
||||
|
||||
nativeBuildInputs = [ pkgs.hello ];
|
||||
SHOULD_BE_SET = someArg;
|
||||
|
||||
passthru = {
|
||||
subshell = pkgs.mkShellNoCC { THIS_IS_A_SUBSHELL = "OK"; };
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue