Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
14ea71e
buildRustPackage: default doCheck to false, add passthru.tests.build
jonringer Sep 19, 2026
c22aba5
buildGoModule: default doCheck to false, add passthru.tests.build
jonringer Sep 19, 2026
75fee20
buildRPackage: default doCheck to false
jonringer Sep 19, 2026
30e473e
docs: expand testing policy in AGENTS.md and packaging SKILL.md
jonringer Sep 19, 2026
245814a
nixfmt-rs: add git to nativeCheckInputs
jonringer Sep 19, 2026
edac722
ast-grep: fix cargoBuildFlags quoting
jonringer Sep 19, 2026
3219dd5
gleam: add git to nativeCheckInputs, skip sandbox-incompatible tests
jonringer Sep 19, 2026
7e32bc7
maturin: skip tests requiring pyo3 crate and network access
jonringer Sep 19, 2026
124a7c6
pijul: skip identity test that fails to compile
jonringer Sep 19, 2026
8ed594d
rust-analyzer-unwrapped: disable cargo tests
jonringer Sep 19, 2026
42f6c51
rust-cbindgen: disable cargo tests
jonringer Sep 19, 2026
bd6e744
tree-sitter: disable cargo tests
jonringer Sep 19, 2026
2cd9b2e
uv: disable cargo tests
jonringer Sep 19, 2026
c73b649
skopeo: remove redundant doCheck comment
jonringer Sep 19, 2026
9b562a4
python3Packages.pyflakes: skip tests with sandbox path issues
jonringer Sep 19, 2026
63fac7c
python3Packages.requests: skip test_zipped_paths_extracted
jonringer Sep 19, 2026
dbb76be
python3Packages.pkginfo: skip tests needing fixture archives
jonringer Sep 19, 2026
c70b993
python3Packages.pytest-mock: skip introspection tests
jonringer Sep 19, 2026
4e09627
python3Packages.pytest-rerunfailures: skip flaky rerun fixture tests
jonringer Sep 19, 2026
9734e06
python3Packages.mako: skip HTML exception rendering tests
jonringer Sep 19, 2026
ca5dfec
python3Packages.scikit-build-core: skip test_setup.py
jonringer Sep 19, 2026
7db8c60
python3Packages.hatch-fancy-pypi-readme: skip CLI end-to-end tests
jonringer Sep 19, 2026
136b354
python3Packages.tomli-w: skip test_for_profiler
jonringer Sep 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions .agents/skills/packaging/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,62 @@ platforms = lib.platforms.all; # All platforms

## Testing

**Default:** `doCheck = false;` - Don't set explicitly.
**Goal:** Keep builds as fast as possible by disabling in-build tests. Use `passthru.tests` to preserve test coverage without slowing every build.

### Defaults

`doCheck = false;` and `doInstallCheck = false;` are the defaults across all build systems (`stdenv.mkDerivation`, `buildPythonPackage`, `buildRustPackage`, `buildGoModule`, `buildPerlPackage`). Don't set them explicitly.

### Auto-Generated `passthru.tests.build`

`buildRustPackage` and `buildGoModule` automatically provide `passthru.tests.build` — a variant that re-runs the build with `doCheck = true`. User-supplied `passthru.tests` entries are merged alongside, not replaced.

For `stdenv.mkDerivation` packages, add `passthru.tests` manually:

**Preferred pattern:**
```nix
passthru.tests = {
unittests = runUnitTests finalAttrs.finalPackage;
withChecks = finalAttrs.finalPackage.overrideAttrs { doCheck = true; };
};
```

**Enable tests only when essential:**
### Python: `testPaths` (Preferred)

Set `testPaths` to auto-generate `passthru.tests.python` and a `test_src` output:

```nix
nativeCheckInputs = [ pytestCheckHook ];
testPaths = [ "tests" ];
```

The `test_src` output bundles the listed paths plus config files (`conftest.py`, `pyproject.toml`, etc.). A standalone test derivation runs the suite against the installed package.

For suites that need extra files (helper modules, fixture data):
```nix
doCheck = true;
checkInputs = [ pytest ];
testPaths = [ "tests" "src/helpers" "README.rst" ];
```

Test configuration attributes are forwarded automatically:
- `disabledTests`, `disabledTestPaths`, `enabledTestPaths`
- `pytestFlags`, `pytestFlagsArray`, `unittestFlagsArray`
- `preCheck`, `postCheck`, `preInstallCheck`, `postInstallCheck`

### Python: Manual `tests.nix` (Fallback)

When `testPaths` is not suitable (e.g., circular dependencies with pytest), create a separate `tests.nix`:

```nix
# default.nix
passthru.tests = {
pytest = callPackage ./tests.nix { };
};
```

### Acceptable In-Build Checks

`doInstallCheck = true;` is acceptable for:
- `versionCheckHook` — verifies the built binary runs and prints expected version
- `pythonImportsCheck` — runs automatically in `buildPythonPackage`, no need to enable explicitly

## Dependencies

```nix
Expand Down
29 changes: 26 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,32 @@ for migration patterns (array iteration, `env` attrset, `substituteAll`, etc.).

### Testing

- `doCheck = false;` is the default - don't set it explicitly
- Prefer `passthru.tests` for unit tests
- Only enable `doCheck = true;` for critical packages
**Goal:** Keep builds as fast as possible. Tests run in `passthru.tests`, not during the main build.

**Rules:**
- `doCheck = false;` and `doInstallCheck = false;` are the defaults across all build systems — don't set them explicitly
- Move test suites to `passthru.tests` so they can be built on demand without slowing every build
- Very minimal test suites may be permitted in-build, but the strong default is tests off
- `doInstallCheck = true;` is acceptable for lightweight checks (e.g., `versionCheckHook`)

**Auto-generated tests:** `buildRustPackage` and `buildGoModule` automatically provide `passthru.tests.build` — a variant that re-runs the build with `doCheck = true`. User-supplied `passthru.tests` entries are merged alongside, not replaced.

**Additional `passthru.tests` (optional):**
```nix
passthru.tests.version = testers.testVersion {
package = finalAttrs.finalPackage;
};
```

**Python — use `testPaths` (preferred):**
```nix
nativeCheckInputs = [ pytestCheckHook ];
testPaths = [ "tests" ];
```

This auto-generates `passthru.tests.python` and a `test_src` output. Test configuration attributes (`disabledTests`, `pytestFlags`, etc.) are forwarded automatically. For suites needing extra files: `testPaths = [ "tests" "src/helpers" "README.rst" ];`.

When `testPaths` is not suitable (e.g., circular dependencies with pytest), create a separate `tests.nix` referenced via `passthru.tests`.

**Detailed guide:** See [`.agents/skills/packaging/SKILL.md`](.agents/skills/packaging/SKILL.md#testing) for testing patterns.

Expand Down
30 changes: 21 additions & 9 deletions pkgs-many/go/module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ lib.extendMkDerivation {
''
);

doCheck = args.doCheck or (!buildTestBinaries);
doCheck = args.doCheck or false;
checkPhase =
args.checkPhase or ''
runHook preCheck
Expand Down Expand Up @@ -395,14 +395,26 @@ lib.extendMkDerivation {
inherit allowGoReference;
disallowedReferences = lib.optional (!finalAttrs.allowGoReference) go;

passthru = {
inherit go;
# Canonicallize `overrideModAttrs` as an attribute overlay.
# `passthru.overrideModAttrs` will be overridden
# when users want to override `goModules`.
overrideModAttrs = lib.toExtension overrideModAttrs;
}
// passthru;
passthru =
let
autoTests = {
# Re-run the build with tests enabled; allow Go references since
# test binaries may embed the Go compiler path
build = finalAttrs.finalPackage.overrideAttrs {
doCheck = true;
allowGoReference = true;
};
};
in
{
inherit go;
# Canonicallize `overrideModAttrs` as an attribute overlay.
# `passthru.overrideModAttrs` will be overridden
# when users want to override `goModules`.
overrideModAttrs = lib.toExtension overrideModAttrs;
tests = autoTests // (passthru.tests or { });
}
// removeAttrs passthru [ "tests" ];

meta = {
# Add default meta information.
Expand Down
12 changes: 10 additions & 2 deletions pkgs/ast-grep/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,17 @@ rustPlatform.buildRustPackage (finalAttrs: {
nativeBuildInputs = [ installShellFiles ];

cargoBuildFlags = [
"--package ast-grep --bin ast-grep"
"--package"
"ast-grep"
"--bin"
"ast-grep"
]
++ lib.optionals enableLegacySg [ "--package ast-grep --bin sg" ];
++ lib.optionals enableLegacySg [
"--package"
"ast-grep"
"--bin"
"sg"
];

postInstall = lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
installShellCompletion --cmd ast-grep \
Expand Down
2 changes: 1 addition & 1 deletion pkgs/buildRPackage/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ stdenv.mkDerivation (
runHook postBuild
'';

installFlags = if attrs.doCheck or true then [ ] else [ "--no-test-load" ];
installFlags = if attrs.doCheck or false then [ ] else [ "--no-test-load" ];

rCommand = "R";

Expand Down
12 changes: 11 additions & 1 deletion pkgs/gleam/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
fetchFromGitHub,
pkg-config,
erlang,
git,
}:

rustPlatform.buildRustPackage (finalAttrs: {
Expand All @@ -25,7 +26,16 @@ rustPlatform.buildRustPackage (finalAttrs: {
erlang
];

doCheck = false;
nativeCheckInputs = [ git ];

checkFlags = [
# scans build directory and chokes on .d files from cargo
"--skip=tests::all_files_have_copyright_notice"
# requires erlang escriptize which needs network/deps
"--skip=tests::escript_success_with_dependency"
# echo tests require bun (JavaScript runtime)
"--skip=tests::echo::"
];

meta = {
description = "Statically typed language for the Erlang VM";
Expand Down
12 changes: 10 additions & 2 deletions pkgs/maturin/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,16 @@ rustPlatform.buildRustPackage rec {
libiconv
];

# Requires network access, fails in sandbox.
doCheck = false;
cargoTestFlags = [ "--lib" ];

checkFlags = [
# these tests require pyo3 crate not included in vendored deps
"--skip=build_options::tests::"
# these tests require files not included in the source
"--skip=metadata::tests::test_implicit_readme"
"--skip=metadata::tests::test_merge_metadata_from_pyproject_toml"
"--skip=metadata::tests::test_pep639"
];

passthru = {
tests = {
Expand Down
3 changes: 2 additions & 1 deletion pkgs/nixfmt-rs/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
lib,
rustPlatform,
fetchFromGitHub,
git,
}:

rustPlatform.buildRustPackage rec {
Expand All @@ -17,7 +18,7 @@ rustPlatform.buildRustPackage rec {

cargoHash = "sha256-LVn9QxJU2r6urD6MA7Z52ajXcgE2Q6dmjirgA/jBKUw=";

doCheck = false;
nativeCheckInputs = [ git ];

meta = with lib; {
description = "A from-scratch Rust reimplementation of nixfmt that produces byte-identical output to the Haskell original.";
Expand Down
3 changes: 2 additions & 1 deletion pkgs/pijul/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ rustPlatform.buildRustPackage (finalAttrs: {

cargoHash = "sha256-Ldb+CpKiVvNOeMhdD/hfQfAAMwdwUy/npY85VBPBq5k=";

doCheck = false;
# identity test fails to compile: SecretKey type removed from pijul_core::key
cargoTestFlags = [ "--bins" ];
nativeBuildInputs = [
installShellFiles
pkg-config
Expand Down
3 changes: 2 additions & 1 deletion pkgs/rust-analyzer-unwrapped/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ rustPlatform.buildRustPackage (finalAttrs: {
libiconv
];

doCheck = false;
# Tests require rustfmt +stable toolchain and real Rust sysroot
dontCargoCheck = true;

env.CFG_RELEASE = finalAttrs.version;

Expand Down
5 changes: 3 additions & 2 deletions pkgs/rust-cbindgen/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
lib,
fetchFromGitHub,
rustPlatform,
cmake,
}:

rustPlatform.buildRustPackage (finalAttrs: {
Expand All @@ -17,8 +18,8 @@ rustPlatform.buildRustPackage (finalAttrs: {

cargoHash = "sha256-f6YoDoiVoh0BVPYHFO1FsdI4OCsF+LY72QaD57StdIQ=";

# Tests require cython and rust nightly features
doCheck = false;
# Tests require nightly rustc (-Zunpretty=expanded) and cython
dontCargoCheck = true;

meta = {
description = "Tool for generating C bindings to Rust code";
Expand Down
15 changes: 14 additions & 1 deletion pkgs/rust/build-rust-package/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,20 @@ lib.extendMkDerivation {
runHook postConfigure
'';

doCheck = args.doCheck or true;
doCheck = args.doCheck or false;

passthru =
let
userPassthru = args.passthru or { };
autoTests = {
# Re-run the build with tests enabled
build = finalAttrs.finalPackage.overrideAttrs { doCheck = true; };
};
in
{
tests = autoTests // (userPassthru.tests or { });
}
// removeAttrs userPassthru [ "tests" ];

meta = meta // {
badPlatforms = meta.badPlatforms or [ ] ++ rustc.badTargetPlatforms;
Expand Down
3 changes: 1 addition & 2 deletions pkgs/skopeo/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ buildGoModule rec {
runHook postBuild
'';

# Embeds paths from go
doCheck = false;
# Test binaries embed Go compiler paths; tests run via passthru.tests.build

installPhase = ''
runHook preInstall
Expand Down
2 changes: 1 addition & 1 deletion pkgs/tree-sitter/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
];

# Tests require grammar fixtures not included in the source
doCheck = false;
dontCargoCheck = true;

patches = [
./remove-web-interface.patch
Expand Down
4 changes: 2 additions & 2 deletions pkgs/uv/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ rustPlatform.buildRustPackage (finalAttrs: {
"uv"
];

# Tests require python3
doCheck = false;
# Tests require python3, network access, and keyring
dontCargoCheck = true;

postInstall = lib.optionalString (stdenv.hostPlatform.emulatorAvailable buildPackages) (
let
Expand Down
6 changes: 4 additions & 2 deletions python/pkgs/hatch-fancy-pypi-readme/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ buildPythonPackage (finalAttrs: {
"README.md"
];

# Requires network connection
disabledTests = [
"test_build" # Requires internet
"test_build" # requires internet
"test_invalid_config"
];

# CLI end-to-end tests need pyproject.toml at source root
disabledTestPaths = [ "tests/test_cli.py" ];

pythonImportsCheck = [ "hatch_fancy_pypi_readme" ];

meta = {
Expand Down
8 changes: 7 additions & 1 deletion python/pkgs/mako/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ buildPythonPackage (finalAttrs: {

testPaths = [ "test" ];

disabledTests = lib.optionals isPyPy [
disabledTests = [
# HTML rendering output differs across pygments/markupsafe versions
"test_custom_tback"
"test_py_utf8_html_error_template"
"test_utf8_format_exceptions_pygments"
]
++ lib.optionals isPyPy [
# https://github.com/sqlalchemy/mako/issues/315
"test_alternating_file_names"
# https://github.com/sqlalchemy/mako/issues/238
Expand Down
13 changes: 13 additions & 0 deletions python/pkgs/pkginfo/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ buildPythonPackage (finalAttrs: {
"test_installed_ctor_w_dist_info"
"test_installed_ctor_w_name"
"test_installed_ctor_w_package"
# tests referencing fixture wheel/sdist archives in docs/examples/
"test_wheel"
"test_get_metadata_w_wheel"
"test_sdist"
];

# Most tests require fixture archives from docs/examples/ not present in PyPI sdist
disabledTestPaths = [
"pkginfo/tests/test_sdist.py"
"pkginfo/tests/test_wheel.py"
"pkginfo/tests/test_utils.py"
"pkginfo/tests/test_bdist.py"
"pkginfo/tests/test_develop.py"
];

pythonImportsCheck = [ "pkginfo" ];
Expand Down
10 changes: 9 additions & 1 deletion python/pkgs/pyflakes/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ buildPythonPackage (finalAttrs: {

testPaths = [ "pyflakes/test" ];

disabledTests = lib.optionals isPyPy [
disabledTests = [
# paths in error messages differ in sandbox
"test_readFromStdin"
"test_errors_io"
"test_errors_syntax"
"test_fileWithFlakes"
"test_goodFile"
]
++ lib.optionals isPyPy [
# https://github.com/PyCQA/pyflakes/issues/779
"test_eofSyntaxError"
"test_misencodedFileUTF16"
Expand Down
Loading
Loading