Compare commits

...

26 commits
v1.1.0 ... main

Author SHA1 Message Date
9f9fcb8534 Merge branch 'feat/vm-tests' into 'main'
feat: add support for running NixOS VM tests more easily

See merge request TECHNOFAB/nixtest!10
2026-01-26 16:24:15 +01:00
c64e0cce0c
feat: add support for running NixOS VM tests more easily 2026-01-20 20:11:18 +01:00
f8fa0846ce Merge branch 'renovate/lock-file-maintenance' into 'main'
chore(deps): lock file maintenance

See merge request TECHNOFAB/nixtest!9
2026-01-01 17:52:46 +01:00
Renovate Bot
e25fb0c609 chore(deps): lock file maintenance 2026-01-01 14:47:37 +00:00
b87e38847d Merge branch 'renovate/github.com-jedib0t-go-pretty-v6-6.x' into 'main'
fix(deps): update module github.com/jedib0t/go-pretty/v6 to v6.7.8

See merge request TECHNOFAB/nixtest!8
2025-12-23 19:23:24 +01:00
Renovate Bot
98250aa7e7 fix(deps): update module github.com/jedib0t/go-pretty/v6 to v6.7.8 2025-12-23 14:09:03 +00:00
fc2b64839c Merge branch 'renovate/github.com-sergi-go-diff-1.x' into 'main'
fix(deps): update module github.com/sergi/go-diff to v1.4.0

See merge request TECHNOFAB/nixtest!6
2025-12-15 09:46:30 +01:00
Renovate Bot
b0988954c7 fix(deps): update module github.com/sergi/go-diff to v1.4.0 2025-12-15 08:09:53 +00:00
a71f897a65 Merge branch 'renovate/github.com-jedib0t-go-pretty-v6-6.x' into 'main'
fix(deps): update module github.com/jedib0t/go-pretty/v6 to v6.7.7

See merge request TECHNOFAB/nixtest!5
2025-12-15 08:35:52 +01:00
Renovate Bot
056851d6c6 fix(deps): update module github.com/jedib0t/go-pretty/v6 to v6.7.7 2025-12-15 07:08:30 +00:00
54d3b534d6 Merge branch 'renovate/github.com-spf13-pflag-1.x' into 'main'
fix(deps): update module github.com/spf13/pflag to v1.0.10

See merge request TECHNOFAB/nixtest!4
2025-12-15 07:17:57 +01:00
Renovate Bot
be32005bc7 fix(deps): update module github.com/spf13/pflag to v1.0.10 2025-12-15 00:07:32 +00:00
c202e41681 Merge branch 'renovate/github.com-stretchr-testify-1.x' into 'main'
fix(deps): update module github.com/stretchr/testify to v1.11.1

See merge request TECHNOFAB/nixtest!7
2025-12-15 00:47:37 +01:00
Renovate Bot
dab1e2ef6f fix(deps): update module github.com/stretchr/testify to v1.11.1 2025-12-14 23:15:53 +00:00
2477ad31ae Merge branch 'feat/rensa-rewrite' into 'main'
refactor: replace flake-parts, devenv etc. with rensa

See merge request TECHNOFAB/nixtest!3
2025-12-14 17:00:58 +01:00
318b903d12
chore: rename module to uppercase 2025-12-14 15:23:19 +01:00
0414493963
refactor: replace flake-parts, devenv etc. with rensa 2025-12-14 14:56:40 +01:00
5a7053afcb
docs: set _file so "declared in" works correctly 2025-10-01 19:42:30 +02:00
56d22f4aa1
test: set SSL_CERT_FILE and NIX_SSL_CERT_FILE so test works in pure mode 2025-10-01 17:08:49 +02:00
c9618a4d9b
docs: update nixmkdocs, use svg for logo and favicon, add module docs 2025-10-01 16:43:30 +02:00
5741109cc9
feat: run script tests in temp dirs for slightly better sandboxing 2025-09-02 13:22:28 +02:00
c9298b91f4
chore!: default to pure mode, rename --pure flag to --impure for switching 2025-09-02 13:06:52 +02:00
22b43c9fe8
chore(flake): enable go hardening workaround 2025-07-31 12:27:03 +02:00
b2fb77ecc9
chore: clean up module a bit 2025-07-31 12:27:03 +02:00
0272a8b0dc
fix: support passing string as dir for autodiscovery 2025-07-31 12:27:03 +02:00
d7e4902fed
fix(README): fix badge 2025-07-31 12:27:03 +02:00
46 changed files with 805 additions and 755 deletions

3
.envrc
View file

@ -1 +1,2 @@
use flake . --impure --accept-flake-config
source $(fetchurl https://gitlab.com/rensa-nix/direnv/-/raw/v0.3.0/direnvrc "sha256-u7+KEz684NnIZ+Vh5x5qLrt8rKdnUNexewBoeTcEVHQ=")
use ren //repo/devShells/default

3
.gitignore vendored
View file

@ -1,6 +1,3 @@
.direnv/
.devenv/
result
.pre-commit-config.yaml
*.xml
cover.*

View file

@ -1,4 +1,5 @@
# Generated by soonix, DO NOT EDIT
include:
- component: gitlab.com/TECHNOFAB/nix-gitlab-ci/nix-gitlab-ci@2.0.0
inputs:
version: 2.0.0
- component: gitlab.com/TECHNOFAB/nix-gitlab-ci/nix-gitlab-ci@3.1.2
inputs:
version: 3.1.2

23
.gitlab/renovate.json5 Normal file
View file

@ -0,0 +1,23 @@
{
"extends": [
"config:recommended"
],
"gitlabci": {
"enabled": false
},
"lockFileMaintenance": {
"enabled": true,
"extends": [
"schedule:monthly"
]
},
"nix": {
"enabled": true
},
"postUpgradeTasks": {
"commands": [
"nix-portable nix run .#update-package",
"nix-portable nix run .#soonix:update"
]
}
}

View file

@ -2,7 +2,7 @@
[![built with nix](https://img.shields.io/static/v1?logo=nixos&logoColor=white&label=&message=Built%20with%20Nix&color=41439a)](https://builtwithnix.org)
[![pipeline status](https://gitlab.com/TECHNOFAB/nixtest/badges/main/pipeline.svg)](https://gitlab.com/TECHNOFAB/nixtest/-/commits/main)
![License: MIT](https://img.shields.io/gitlab/license/technofab/nix-gitlab-ci)
![License: MIT](https://img.shields.io/gitlab/license/technofab/nixtest)
[![Latest Release](https://gitlab.com/TECHNOFAB/nixtest/-/badges/release.svg)](https://gitlab.com/TECHNOFAB/nixtest/-/releases)
[![Support me](https://img.shields.io/badge/Support-me-green)](https://tec.tf/#support)
[![Docs](https://img.shields.io/badge/Read-Docs-green)](https://nixtest.projects.tf)

View file

@ -3,14 +3,14 @@ package main
import (
"os"
"gitlab.com/technofab/nixtest/internal/config"
appnix "gitlab.com/technofab/nixtest/internal/nix"
"gitlab.com/technofab/nixtest/internal/report/console"
"gitlab.com/technofab/nixtest/internal/report/junit"
"gitlab.com/technofab/nixtest/internal/runner"
appsnap "gitlab.com/technofab/nixtest/internal/snapshot"
"gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/technofab/nixtest/internal/util"
"gitlab.com/TECHNOFAB/nixtest/internal/config"
appnix "gitlab.com/TECHNOFAB/nixtest/internal/nix"
"gitlab.com/TECHNOFAB/nixtest/internal/report/console"
"gitlab.com/TECHNOFAB/nixtest/internal/report/junit"
"gitlab.com/TECHNOFAB/nixtest/internal/runner"
appsnap "gitlab.com/TECHNOFAB/nixtest/internal/snapshot"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/util"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
@ -60,7 +60,7 @@ func main() {
SnapshotDir: appCfg.SnapshotDir,
UpdateSnapshots: appCfg.UpdateSnapshots,
SkipPattern: appCfg.SkipPattern,
PureEnv: appCfg.PureEnv,
ImpureEnv: appCfg.ImpureEnv,
}
testRunner, err := runner.New(runnerCfg, nixService, snapshotService)
if err != nil {

View file

@ -4,7 +4,7 @@
Usage of nixtest:
--junit string Path to generate JUNIT report to, leave empty to disable
--no-color Disable coloring
--pure Unset all env vars before running script tests
--impure Don\'t unset all env vars before running script tests
-s, --skip string Regular expression to skip tests (e.g., 'test-.*|.*-b')
--snapshot-dir string Directory where snapshots are stored (default "./snapshots")
-f, --tests string Path to JSON file containing tests (required)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

1
docs/images/logo.svg Executable file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="none"><rect width="100" height="100" fill="#222" rx="12"/><rect width="100" height="100" fill="url(#a)" rx="12"/><path fill="#3FB950" d="M18 54.7a3 3 0 0 1 4.3 0l17 17c.5.4 1 .4 1.5 0L82.5 30a3 3 0 0 1 4.2 0l2 1.9a3 3 0 0 1 0 4.2L46.2 78.7l-4 4a3 3 0 0 1-4.2 0L16 60.9a3 3 0 0 1 0-4.3l2-1.9Z"/><path fill="url(#b)" d="m89 66.6-5.3 9.6H71l6.3 11-2.7 4.8h-5.5l-9-15.8H53l9.6-9.6H89Zm-76-4.8 1 1.2 6 5.9-3.5 6-5.5-9.4 2-3.7Zm3-5 .1-.2-.1.2Zm11.4-1.1-3-3.1a6 6 0 0 0-8.5 0l-1.8 1.8H4.7L2 49.6l2.7-4.8h18l6.5-11.2H40l-12.6 22ZM62.8 18l6.4-11h5.4l2.7 4.8-9 15.7 4.4 7.9-6.9 6.9L45.8 7 56.5 7l6.2 11.1Z"/><path fill="url(#c)" d="m54.9 91.9-10.7.1-3.1-5.5a6 6 0 0 0 3.2-1.7l4-4 .2-.2L55 92Zm-19.1-7.2L31.7 92h-5.3l-2.8-4.8L29 78l6.9 6.8ZM47 78l-.8.8-4 4-.1.1.1-.1 4-4 .8-.8ZM40.2 72Zm.5-.2Zm.3-4.5-1 .9-11.7-11.7 3.3-6L41 67.3Zm54.3-22.6 2.7 4.7-2.7 4.8H77.5l-6.3 11.2h-7.6l20.8-20.7h11Zm-54.8-22 12.7.1 5.4 9.5H12l5.3-9.5h12.5l-6.2-11L26.2 7h5.5l8.8 15.8Zm44.3 3.4a6 6 0 0 0-2.4.4l1.3-2.4 1.1 2Z"/><defs><linearGradient id="b" x1="76.7" x2="59.1" y1="47.2" y2="17.1" gradientUnits="userSpaceOnUse"><stop offset=".2" stop-color="#7EB1DD"/></linearGradient><linearGradient id="c" x1="63.4" x2="81.3" y1="70.3" y2="40.6" gradientUnits="userSpaceOnUse"><stop offset="1" stop-color="#5277C3"/></linearGradient><radialGradient id="a" cx="0" cy="0" r="1" gradientTransform="matrix(0 50 -50 0 50 50)" gradientUnits="userSpaceOnUse"><stop offset=".5" stop-color="#091A3D"/><stop offset="1" stop-color="#000819"/></radialGradient></defs></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

3
docs/options.md Normal file
View file

@ -0,0 +1,3 @@
# Options
{% include 'options.md' %}

15
docs/style.css Normal file
View file

@ -0,0 +1,15 @@
.md-header__button.md-logo {
margin: 0;
padding-top: .2rem;
padding-bottom: .2rem;
}
[dir="ltr"] .md-header__title {
margin-left: 0;
}
.md-header__button.md-logo img,
.md-header__button.md-logo svg {
height: 2rem;
}

View file

@ -64,6 +64,7 @@ There are currently 3 types of tests:
- `snapshot` -> snapshot testing, only needs `actual` and compares that to the snapshot
- `unit` -> equality checking, needs `expected` and `actual` or `actualDrv`
- `script` -> shell script test, needs `script`
- `vm` -> NixOS VM test, needs `vmConfig`
Examples:
@ -96,10 +97,10 @@ Examples:
name = "script-test";
type = "script";
script =
# there are two modes, "default"/"impure" and "pure"
# there are two modes, "default"/"pure" and "impure"
# in impure mode all env variables etc. from your current session are kept
# and are available to the test
# to make it more reproducible and cleaner, use --pure to switch to pure
# and are available to the test (using --impure).
# to make it more reproducible and cleaner, the default is pure
# mode which will unset all env variables before running the test. That
# requires you to set PATH yourself then:
#
@ -126,6 +127,23 @@ Examples:
expected = pkgs.hello;
actual = pkgs.hello;
}
{
name = "vm-test";
type = "vm";
# gets passed to pkgs.testers.nixosTest, so same params apply
# name gets automatically set, so thats not required
vmConfig = {
nodes.machine = {
services.nginx.enable = true;
};
testScript =
# py
''
machine.wait_for_unit("nginx.service")
machine.wait_for_open_port(80)
'';
};
}
]
```

399
flake.lock generated
View file

@ -1,281 +1,12 @@
{
"nodes": {
"cachix": {
"inputs": {
"devenv": [
"devenv"
],
"flake-compat": [
"devenv"
],
"git-hooks": [
"devenv"
],
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1742042642,
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
"owner": "cachix",
"repo": "cachix",
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "latest",
"repo": "cachix",
"type": "github"
}
},
"devenv": {
"inputs": {
"cachix": "cachix",
"flake-compat": "flake-compat",
"git-hooks": "git-hooks",
"nix": "nix",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1746189866,
"narHash": "sha256-3sTvuSVBFcXbqg26Qcw/ENJ1s36jtzEcZ0mHqLqvWRA=",
"owner": "cachix",
"repo": "devenv",
"rev": "5fc592d45dd056035e0fd5000893a21609c35526",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"devenv",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1743550720,
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"devenv"
],
"gitignore": "gitignore",
"nixpkgs": [
"devenv",
"nixpkgs"
]
},
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"devenv",
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"mkdocs-material-umami": {
"locked": {
"lastModified": 1745840856,
"narHash": "sha256-1Ad1JTMQMP6YsoIKAA+SBCE15qWrYkGue9/lXOLnu9I=",
"owner": "technofab",
"repo": "mkdocs-material-umami",
"rev": "3ac9b194450f6b779c37b8d16fec640198e5cd0a",
"type": "gitlab"
},
"original": {
"owner": "technofab",
"repo": "mkdocs-material-umami",
"type": "gitlab"
}
},
"nix": {
"inputs": {
"flake-compat": [
"devenv"
],
"flake-parts": "flake-parts",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_2",
"nixpkgs-23-11": [
"devenv"
],
"nixpkgs-regression": [
"devenv"
],
"pre-commit-hooks": [
"devenv"
]
},
"locked": {
"lastModified": 1745930071,
"narHash": "sha256-bYyjarS3qSNqxfgc89IoVz8cAFDkF9yPE63EJr+h50s=",
"owner": "domenkozar",
"repo": "nix",
"rev": "b455edf3505f1bf0172b39a735caef94687d0d9c",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.24",
"repo": "nix",
"type": "github"
}
},
"nix-devtools": {
"locked": {
"dir": "lib",
"lastModified": 1739971859,
"narHash": "sha256-DaY11jX7Lraw7mRUIsgPsO+aSkkewQe2D+WMZORTNPE=",
"owner": "technofab",
"repo": "nix-devtools",
"rev": "b4f059657de5ac2569afd69a8f042614d309e6bb",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "technofab",
"repo": "nix-devtools",
"type": "gitlab"
}
},
"nix-gitlab-ci": {
"locked": {
"dir": "lib",
"lastModified": 1746973171,
"narHash": "sha256-q/LhPZlhJB2gXZ5BfgU1Wep/1x1y9Sct3/JU8A2fzjg=",
"owner": "technofab",
"repo": "nix-gitlab-ci",
"rev": "dca2d724c155799e537a898cb9f948f8afae4921",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "technofab",
"ref": "2.0.1",
"repo": "nix-gitlab-ci",
"type": "gitlab"
}
},
"nix-mkdocs": {
"locked": {
"dir": "lib",
"lastModified": 1745841841,
"narHash": "sha256-297zPQbUlc7ZAYDoaD6mCmQxCC3Tr4YOKekRF1ArZ7g=",
"owner": "technofab",
"repo": "nixmkdocs",
"rev": "c7e3c3b13ded25818e9789938387bba6f2cde690",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "technofab",
"repo": "nixmkdocs",
"type": "gitlab"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"lastModified": 1767116409,
"narHash": "sha256-5vKw92l1GyTnjoLzEagJy5V5mDFck72LiQWZSOnSicw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"rev": "cad22e7d996aea55ecab064e84834289143e44a0",
"type": "github"
},
"original": {
@ -287,11 +18,11 @@
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1743296961,
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
"lastModified": 1754184128,
"narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
"rev": "02e72200e6d56494f4a7c0da8118760736e41b60",
"type": "github"
},
"original": {
@ -300,114 +31,30 @@
"type": "github"
}
},
"nixpkgs_2": {
"ren": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1717432640,
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"type": "github"
"dir": "lib",
"lastModified": 1766497301,
"narHash": "sha256-W7WeOXMUZROMtbU1qQNWy/yai+k8gG09YACFQ7ImpsQ=",
"owner": "rensa-nix",
"repo": "core",
"rev": "e08c48b5db1052bfb8b8dad764e05decc1af893e",
"type": "gitlab"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1733477122,
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1746152631,
"narHash": "sha256-zBuvmL6+CUsk2J8GINpyy8Hs1Zp4PP6iBWSmZ4SCQ/s=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "032bc6539bd5f14e9d0c51bd79cfe9a055b094c3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1745377448,
"narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
"dir": "lib",
"owner": "rensa-nix",
"repo": "core",
"type": "gitlab"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"flake-parts": "flake-parts_2",
"mkdocs-material-umami": "mkdocs-material-umami",
"nix-devtools": "nix-devtools",
"nix-gitlab-ci": "nix-gitlab-ci",
"nix-mkdocs": "nix-mkdocs",
"nixpkgs": "nixpkgs_4",
"systems": "systems",
"treefmt-nix": "treefmt-nix"
}
},
"systems": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": "nixpkgs_5"
},
"locked": {
"lastModified": 1746216483,
"narHash": "sha256-4h3s1L/kKqt3gMDcVfN8/4v2jqHrgLIe4qok4ApH5x4=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "29ec5026372e0dec56f890e50dbe4f45930320fd",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
"nixpkgs": "nixpkgs",
"ren": "ren"
}
}
},

276
flake.nix
View file

@ -1,251 +1,39 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
ren.url = "gitlab:rensa-nix/core?dir=lib";
};
outputs = {
flake-parts,
systems,
ren,
self,
...
} @ inputs:
flake-parts.lib.mkFlake {inherit inputs;} {
imports = [
inputs.devenv.flakeModule
inputs.treefmt-nix.flakeModule
inputs.nix-gitlab-ci.flakeModule
inputs.nix-devtools.flakeModule
inputs.nix-mkdocs.flakeModule
ren.buildWith
{
inherit inputs;
cellsFrom = ./nix;
transformInputs = system: i:
i
// {
pkgs = import i.nixpkgs {inherit system;};
};
cellBlocks = with ren.blocks; [
(simple "devShells")
(simple "ci")
(simple "tests")
(simple "packages")
(simple "docs")
(simple "soonix")
];
}
{
packages = ren.select self [
["repo" "ci" "packages"]
["repo" "tests"]
["packages" "packages"]
["repo" "docs"]
["repo" "soonix" "packages"]
];
systems = import systems;
flake = {};
perSystem = {
lib,
pkgs,
config,
...
}: {
treefmt = {
projectRootFile = "flake.nix";
programs = {
alejandra.enable = true;
mdformat.enable = true;
gofmt.enable = true;
};
settings.formatter.mdformat.command = let
pkg = pkgs.python3.withPackages (p: [
p.mdformat
p.mdformat-mkdocs
]);
in "${pkg}/bin/mdformat";
};
devenv.shells.default = {
containers = pkgs.lib.mkForce {};
packages = with pkgs; [gopls gore go-junit-report];
languages.go.enable = true;
pre-commit.hooks = {
treefmt = {
enable = true;
packageOverrides.treefmt = config.treefmt.build.wrapper;
};
convco.enable = true;
};
task = {
enable = true;
alias = ",";
tasks = {
"test" = {
cmds = [
"go test -v -coverprofile cover.out ./..."
"go tool cover -html cover.out -o cover.html"
];
};
};
};
};
doc = {
path = ./docs;
deps = pp: [
pp.mkdocs-material
(pp.callPackage inputs.mkdocs-material-umami {})
];
config = {
site_name = "Nixtest";
repo_name = "TECHNOFAB/nixtest";
repo_url = "https://gitlab.com/TECHNOFAB/nixtest";
edit_uri = "edit/main/docs/";
theme = {
name = "material";
features = ["content.code.copy" "content.action.edit"];
icon.repo = "simple/gitlab";
logo = "images/logo.png";
favicon = "images/favicon.png";
palette = [
{
scheme = "default";
media = "(prefers-color-scheme: light)";
primary = "green";
accent = "light green";
toggle = {
icon = "material/brightness-7";
name = "Switch to dark mode";
};
}
{
scheme = "slate";
media = "(prefers-color-scheme: dark)";
primary = "green";
accent = "light green";
toggle = {
icon = "material/brightness-4";
name = "Switch to light mode";
};
}
];
};
plugins = ["search" "material-umami"];
nav = [
{"Introduction" = "index.md";}
{"Usage" = "usage.md";}
{"Reference" = "reference.md";}
{"CLI" = "cli.md";}
{"Example Configs" = "examples.md";}
];
markdown_extensions = [
"pymdownx.superfences"
"admonition"
];
extra.analytics = {
provider = "umami";
site_id = "716d1869-9342-4b62-a770-e15d2d5c807d";
src = "https://analytics.tf/umami";
domains = "nixtest.projects.tf";
feedback = {
title = "Was this page helpful?";
ratings = [
{
icon = "material/thumb-up-outline";
name = "This page is helpful";
data = "good";
note = "Thanks for your feedback!";
}
{
icon = "material/thumb-down-outline";
name = "This page could be improved";
data = "bad";
note = "Thanks for your feedback! Please leave feedback by creating an issue :)";
}
];
};
};
};
};
ci = {
stages = ["test" "build" "deploy"];
jobs = {
"test:lib" = {
stage = "test";
script = [
"nix run .#tests -- --junit=junit.xml"
];
allow_failure = true;
artifacts = {
when = "always";
reports.junit = "junit.xml";
};
};
"test:go" = {
stage = "test";
nix.deps = with pkgs; [go go-junit-report gocover-cobertura];
variables = {
GOPATH = "$CI_PROJECT_DIR/.go";
GOCACHE = "$CI_PROJECT_DIR/.go/pkg/mod";
};
script = [
"go test -coverprofile=coverage.out -v 2>&1 ./... | go-junit-report -set-exit-code > report.xml"
"go tool cover -func coverage.out"
"gocover-cobertura < coverage.out > coverage.xml"
];
allow_failure = true;
coverage = "/\(statements\)(?:\s+)?(\d+(?:\.\d+)?%)/";
cache.paths = [".go/pkg/mod/"];
artifacts = {
when = "always";
reports = {
junit = "report.xml";
coverage_report = {
coverage_format = "cobertura";
path = "coverage.xml";
};
};
};
};
"docs" = {
stage = "build";
script = [
# sh
''
nix build .#docs:default
mkdir -p public
cp -r result/. public/
''
];
artifacts.paths = ["public"];
};
"pages" = {
nix.enable = false;
image = "alpine:latest";
stage = "deploy";
script = ["true"];
artifacts.paths = ["public"];
rules = [
{
"if" = "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH";
}
];
};
};
};
packages = let
ntlib = import ./lib {inherit pkgs lib;};
in {
default = pkgs.callPackage ./package.nix {};
tests = ntlib.mkNixtest {
modules = ntlib.autodiscover {dir = ./tests;};
args = {
inherit pkgs ntlib;
};
};
};
};
};
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
# flake & devenv related
flake-parts.url = "github:hercules-ci/flake-parts";
systems.url = "github:nix-systems/default-linux";
devenv.url = "github:cachix/devenv";
treefmt-nix.url = "github:numtide/treefmt-nix";
nix-gitlab-ci.url = "gitlab:technofab/nix-gitlab-ci/2.0.1?dir=lib";
nix-devtools.url = "gitlab:technofab/nix-devtools?dir=lib";
nix-mkdocs.url = "gitlab:technofab/nixmkdocs?dir=lib";
mkdocs-material-umami.url = "gitlab:technofab/mkdocs-material-umami";
};
nixConfig = {
extra-substituters = [
"https://cache.nixos.org/"
"https://nix-community.cachix.org"
"https://devenv.cachix.org"
];
extra-trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw="
];
};
}

12
go.mod
View file

@ -1,12 +1,12 @@
module gitlab.com/technofab/nixtest
module gitlab.com/TECHNOFAB/nixtest
go 1.24.2
go 1.23.0
require (
github.com/akedrou/textdiff v0.1.0
github.com/rs/zerolog v1.34.0
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
)
require (
@ -19,9 +19,9 @@ require (
)
require (
github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/jedib0t/go-pretty/v6 v6.7.8
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/sergi/go-diff v1.3.1
github.com/sergi/go-diff v1.4.0
golang.org/x/sys v0.33.0 // indirect
)

10
go.sum
View file

@ -7,6 +7,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=
github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/jedib0t/go-pretty/v6 v6.7.7 h1:Y1Id3lJ3k4UB8uwWWy3l8EVFnUlx5chR5+VbsofPNX0=
github.com/jedib0t/go-pretty/v6 v6.7.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/jedib0t/go-pretty/v6 v6.7.8 h1:BVYrDy5DPBA3Qn9ICT+PokP9cvCv1KaHv2i+Hc8sr5o=
github.com/jedib0t/go-pretty/v6 v6.7.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -32,12 +36,18 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -16,7 +16,7 @@ type AppConfig struct {
JunitPath string
UpdateSnapshots bool
SkipPattern string
PureEnv bool
ImpureEnv bool
NoColor bool
}
@ -29,7 +29,7 @@ func Load() AppConfig {
flag.StringVar(&cfg.JunitPath, "junit", "", "Path to generate JUNIT report to, leave empty to disable")
flag.BoolVarP(&cfg.UpdateSnapshots, "update-snapshots", "u", false, "Update all snapshots")
flag.StringVarP(&cfg.SkipPattern, "skip", "s", "", "Regular expression to skip tests (e.g., 'test-.*|.*-b')")
flag.BoolVar(&cfg.PureEnv, "pure", false, "Unset all env vars before running script tests")
flag.BoolVar(&cfg.ImpureEnv, "impure", false, "Don't unset all env vars before running script tests")
flag.BoolVar(&cfg.NoColor, "no-color", false, "Disable coloring")
helpRequested := flag.BoolP("help", "h", false, "Show this menu")

View file

@ -64,7 +64,7 @@ func TestLoad_CustomValues(t *testing.T) {
"--junit", "report.xml",
"-u",
"--skip", "specific-test",
"--pure",
"--impure",
"--no-color",
}
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) // Reset flags
@ -83,7 +83,7 @@ func TestLoad_CustomValues(t *testing.T) {
if cfg.SkipPattern != "specific-test" {
t.Errorf("SkipPattern: got %s, want specific-test", cfg.SkipPattern)
}
if !cfg.PureEnv {
t.Errorf("PureEnv: got %v, want true", cfg.PureEnv)
if !cfg.ImpureEnv {
t.Errorf("ImpureEnv: got %v, want true", cfg.ImpureEnv)
}
}

View file

@ -3,18 +3,19 @@ package nix
import (
"bytes"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
)
// Service defines operations related to Nix
type Service interface {
BuildDerivation(derivation string) (string, error)
BuildAndParseJSON(derivation string) (any, error)
BuildAndRunScript(derivation string, pureEnv bool) (exitCode int, stdout string, stderr string, err error)
BuildAndRunScript(derivation string, impureEnv bool) (exitCode int, stdout string, stderr string, err error)
}
type DefaultService struct {
@ -72,21 +73,29 @@ func (s *DefaultService) BuildAndParseJSON(derivation string) (any, error) {
}
// BuildAndRunScript builds a derivation and runs it as a script
func (s *DefaultService) BuildAndRunScript(derivation string, pureEnv bool) (exitCode int, stdout string, stderr string, err error) {
func (s *DefaultService) BuildAndRunScript(derivation string, impureEnv bool) (exitCode int, stdout string, stderr string, err error) {
exitCode = -1
path, err := s.BuildDerivation(derivation)
if err != nil {
return exitCode, "", "", err
}
// run scripts in a temporary directory
tempDir, err := os.MkdirTemp("", "nixtest-script-")
if err != nil {
return exitCode, "", "", &apperrors.ScriptExecutionError{Path: path, Err: fmt.Errorf("failed to create temporary directory: %w", err)}
}
defer os.RemoveAll(tempDir)
var cmdArgs []string
if pureEnv {
cmdArgs = append([]string{"env", "-i"}, "bash", path)
} else {
if impureEnv {
cmdArgs = []string{"bash", path}
} else {
cmdArgs = append([]string{"env", "-i"}, "bash", path)
}
cmd := s.commandExecutor(cmdArgs[0], cmdArgs[1:]...)
cmd.Dir = tempDir
var outBuf, errBuf bytes.Buffer
cmd.Stdout = &outBuf
cmd.Stderr = &errBuf

View file

@ -10,7 +10,7 @@ import (
"strings"
"testing"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
)
func TestHelperProcess(t *testing.T) {
@ -232,7 +232,7 @@ func TestDefaultService_BuildAndRunScript(t *testing.T) {
tests := []struct {
name string
derivation string
pureEnv bool
impureEnv bool
mockBuildDrvOutput string
mockBuildDrvError string
mockBuildDrvExitCode string
@ -252,7 +252,7 @@ func TestDefaultService_BuildAndRunScript(t *testing.T) {
0, "Hello", "ErrOut", false, nil, "",
},
{
"Success pure", "script.drv#sh", true, mockScriptPath, "", "0",
"Success impure", "script.drv#sh", true, mockScriptPath, "", "0",
"Hello", "ErrOut", "0",
0, "Hello", "ErrOut", false, nil, "",
},
@ -277,7 +277,7 @@ func TestDefaultService_BuildAndRunScript(t *testing.T) {
os.Setenv("MOCK_SCRIPT_STDERR", tt.mockScriptStderr)
os.Setenv("MOCK_SCRIPT_EXIT_CODE", tt.mockScriptExitCode)
exitCode, stdout, stderr, err := service.BuildAndRunScript(tt.derivation, tt.pureEnv)
exitCode, stdout, stderr, err := service.BuildAndRunScript(tt.derivation, tt.impureEnv)
if (err != nil) != tt.wantErr {
t.Fatalf("BuildAndRunScript() error = %v, wantErr %v", err, tt.wantErr)

View file

@ -11,8 +11,8 @@ import (
"github.com/jedib0t/go-pretty/v6/text"
"github.com/rs/zerolog/log"
"github.com/sergi/go-diff/diffmatchpatch"
"gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/technofab/nixtest/internal/util"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/util"
)
// PrintErrors prints error messages for failed tests

View file

@ -12,7 +12,7 @@ import (
"time"
"github.com/jedib0t/go-pretty/v6/text"
"gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
)
// captureOutput captures stdout and stderr during the execution of a function

View file

@ -7,8 +7,8 @@ import (
"strings"
"time"
"gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/technofab/nixtest/internal/util"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/util"
)
type JUnitReport struct {

View file

@ -9,7 +9,7 @@ import (
"testing"
"time"
"gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
)
func formatDurationSeconds(d time.Duration) string {

View file

@ -9,10 +9,10 @@ import (
"time"
"github.com/rs/zerolog/log"
"gitlab.com/technofab/nixtest/internal/nix"
"gitlab.com/technofab/nixtest/internal/snapshot"
"gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/technofab/nixtest/internal/util"
"gitlab.com/TECHNOFAB/nixtest/internal/nix"
"gitlab.com/TECHNOFAB/nixtest/internal/snapshot"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/util"
)
// Runner executes tests based on provided specifications and configuration
@ -32,7 +32,7 @@ type Config struct {
SnapshotDir string
UpdateSnapshots bool
SkipPattern string
PureEnv bool
ImpureEnv bool
}
func New(cfg Config, nixService nix.Service, snapService snapshot.Service) (*Runner, error) {
@ -181,7 +181,7 @@ func (r *Runner) handleUnitTest(result *types.TestResult, spec types.TestSpec, a
// handleScriptTest processes script type tests
func (r *Runner) handleScriptTest(result *types.TestResult, spec types.TestSpec) {
exitCode, stdout, stderrStr, err := r.nixService.BuildAndRunScript(spec.Script, r.config.PureEnv)
exitCode, stdout, stderrStr, err := r.nixService.BuildAndRunScript(spec.Script, r.config.ImpureEnv)
if err != nil {
result.Status = types.StatusError
result.ErrorMessage = fmt.Sprintf("[system] failed to run script derivation %s: %v", spec.Script, err)

View file

@ -9,8 +9,8 @@ import (
"testing"
"time"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
"gitlab.com/technofab/nixtest/internal/types"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
"gitlab.com/TECHNOFAB/nixtest/internal/types"
)
// --- Mock Service Implementations ---
@ -18,7 +18,7 @@ import (
type mockNixService struct {
BuildDerivationFunc func(derivation string) (string, error)
BuildAndParseJSONFunc func(derivation string) (any, error)
BuildAndRunScriptFunc func(derivation string, pureEnv bool) (exitCode int, stdout string, stderr string, err error)
BuildAndRunScriptFunc func(derivation string, impureEnv bool) (exitCode int, stdout string, stderr string, err error)
}
func (m *mockNixService) BuildDerivation(d string) (string, error) {
@ -253,7 +253,7 @@ func TestRunner_executeTest(t *testing.T) {
spec: types.TestSpec{Name: "ScriptSuccess", Type: types.TestTypeScript, Script: "script.sh"},
runnerConfig: Config{},
setupMockServices: func(t *testing.T, mNix *mockNixService, mSnap *mockSnapshotService, s types.TestSpec, c Config) {
mNix.BuildAndRunScriptFunc = func(derivation string, pureEnv bool) (int, string, string, error) {
mNix.BuildAndRunScriptFunc = func(derivation string, impureEnv bool) (int, string, string, error) {
return 0, "stdout", "stderr", nil
}
},
@ -264,7 +264,7 @@ func TestRunner_executeTest(t *testing.T) {
spec: types.TestSpec{Name: "ScriptFail", Type: types.TestTypeScript, Script: "script.sh"},
runnerConfig: Config{},
setupMockServices: func(t *testing.T, mNix *mockNixService, mSnap *mockSnapshotService, s types.TestSpec, c Config) {
mNix.BuildAndRunScriptFunc = func(derivation string, pureEnv bool) (int, string, string, error) {
mNix.BuildAndRunScriptFunc = func(derivation string, impureEnv bool) (int, string, string, error) {
return 1, "out on fail", "err on fail", nil
}
},
@ -313,7 +313,7 @@ func TestRunner_RunTests(t *testing.T) {
mockSnapSvc := &mockSnapshotService{}
mockNixSvc.BuildAndParseJSONFunc = func(derivation string) (any, error) { return "parsed", nil }
mockNixSvc.BuildAndRunScriptFunc = func(derivation string, pureEnv bool) (int, string, string, error) { return 0, "", "", nil }
mockNixSvc.BuildAndRunScriptFunc = func(derivation string, impureEnv bool) (int, string, string, error) { return 0, "", "", nil }
mockSnapSvc.StatFunc = func(name string) (os.FileInfo, error) { return mockFileInfo{}, nil }
mockSnapSvc.LoadFileFunc = func(filePath string) (any, error) { return "snapshot", nil }
mockSnapSvc.CreateFileFunc = func(filePath string, data any) error { return nil }

View file

@ -7,8 +7,8 @@ import (
"path/filepath"
"strings"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
"gitlab.com/technofab/nixtest/internal/util"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
"gitlab.com/TECHNOFAB/nixtest/internal/util"
)
// Service defines operations related to test snapshots

View file

@ -9,7 +9,7 @@ import (
"strings"
"testing"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
)
func TestDefaultService_GetPath(t *testing.T) {

View file

@ -8,7 +8,7 @@ import (
"github.com/akedrou/textdiff"
"github.com/akedrou/textdiff/myers"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
)
func ComputeDiff(expected, actual string) (string, error) {

View file

@ -8,7 +8,7 @@ import (
"strings"
"testing"
apperrors "gitlab.com/technofab/nixtest/internal/errors"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors"
)
func TestComputeDiff(t *testing.T) {

View file

@ -39,7 +39,11 @@ in rec {
}: let
files = builtins.readDir dir;
matchingFiles = builtins.filter (name: builtins.match pattern name != null) (builtins.attrNames files);
imports = map (file: /${dir}/${file}) matchingFiles;
imports = map (file:
if builtins.isString dir
then (builtins.unsafeDiscardStringContext dir) + "/${file}"
else /${dir}/${file})
matchingFiles;
in {
inherit imports;
# automatically set the base so test filepaths are easier to read

View file

@ -3,7 +3,19 @@
lib,
...
}: let
inherit (lib) mkOptionType mkOption types;
inherit
(lib)
mkOptionType
mkOption
types
filterAttrs
isType
removePrefix
assertMsg
generators
literalExpression
xor
;
nixtest-lib = import ./default.nix {inherit pkgs lib;};
@ -16,14 +28,26 @@
unset = {
_type = "unset";
};
isUnset = lib.isType "unset";
isUnset = isType "unset";
unsetOr = typ:
(types.either unsetType typ)
// {
inherit (typ) description getSubOptions;
};
mkUnsetOption = opts:
mkOption (opts
// {
type = unsetOr opts.type;
default = opts.default or unset;
defaultText = literalExpression "unset";
});
filterUnset = value:
if builtins.isAttrs value && !builtins.hasAttr "_type" value
then let
filteredAttrs = builtins.mapAttrs (n: v: filterUnset v) value;
in
lib.filterAttrs (name: value: (!isUnset value)) filteredAttrs
filterAttrs (name: value: (!isUnset value)) filteredAttrs
else if builtins.isList value
then builtins.filter (elem: !isUnset elem) (map filterUnset value)
else value;
@ -35,74 +59,95 @@
...
}: {
options = {
pos = mkOption {
type = types.either types.attrs unsetType;
pos = mkUnsetOption {
type = types.attrs;
description = ''
Position of test, use `__curPos` for automatic insertion of current position.
'';
default = pos;
apply = val:
if isUnset val
then val
else let
fileRelative = lib.removePrefix testsBase val.file;
fileRelative = removePrefix testsBase val.file;
in "${fileRelative}:${toString val.line}";
};
type = mkOption {
type = types.enum ["unit" "snapshot" "script"];
type = types.enum ["unit" "snapshot" "script" "vm"];
description = ''
Type of test, has to be one of "unit", "snapshot", "script", or "vm".
'';
default = "unit";
apply = value:
assert lib.assertMsg (value != "script" || !isUnset config.script)
assert assertMsg (value == "script" -> !isUnset config.script)
"test '${config.name}' as type 'script' requires 'script' to be set";
assert lib.assertMsg (value != "unit" || !isUnset config.expected)
assert assertMsg (value == "unit" -> !isUnset config.expected)
"test '${config.name}' as type 'unit' requires 'expected' to be set";
assert lib.assertMsg (
let
actualIsUnset = isUnset config.actual;
actualDrvIsUnset = isUnset config.actualDrv;
in
(value != "unit")
|| (!actualIsUnset && actualDrvIsUnset)
|| (actualIsUnset && !actualDrvIsUnset)
)
assert assertMsg (value == "unit" -> (xor (isUnset config.actual) (isUnset config.actualDrv)))
"test '${config.name}' as type 'unit' requires only 'actual' OR 'actualDrv' to be set"; value;
};
name = mkOption {
type = types.str;
description = ''
Name of this test.
'';
};
description = mkOption {
type = types.either types.str unsetType;
default = unset;
description = mkUnsetOption {
type = types.str;
description = ''
Short description of the test.
'';
};
format = mkOption {
type = types.enum ["json" "pretty"];
description = ''
Which format to use for serializing arbitrary values.
Required since this config is serialized to JSON for passing it to Nixtest, so no Nix-values can be used directly.
- `json`: serializes the data to json using `builtins.toJSON`
- `pretty`: serializes the data to a "pretty" format using `lib.generators.toPretty`
'';
default = "json";
};
expected = mkOption {
expected = mkUnsetOption {
type = types.anything;
default = unset;
description = ''
Expected value of the test. Remember, the values are serialized (see [here](#suitesnametestsformat)).
'';
apply = val:
if isUnset val || config.format == "json"
then val
else lib.generators.toPretty {} val;
else generators.toPretty {} val;
};
actual = mkOption {
actual = mkUnsetOption {
type = types.anything;
default = unset;
description = ''
Actual value of the test. Remember, the values are serialized (see [here](#suitesnametestsformat)).
'';
apply = val:
if isUnset val || config.format == "json"
then val
else lib.generators.toPretty {} val;
else generators.toPretty {} val;
};
actualDrv = mkOption {
type = types.either types.package unsetType;
default = unset;
actualDrv = mkUnsetOption {
type = types.package;
description = ''
Actual value of the test, but as a derivation.
Nixtest will build this derivation when running the test, then compare the contents of the
resulting file to the [`expected`](#suitesnametestsexpected) value.
'';
apply = val:
# keep unset value
if isUnset val
then val
else builtins.unsafeDiscardStringContext (val.drvPath or "");
};
script = mkOption {
type = types.either types.str unsetType;
default = unset;
script = mkUnsetOption {
type = types.str;
description = ''
Script to run for the test.
Nixtest will run this, failing the test if it exits with a non-zero exit code.
'';
apply = val:
if isUnset val
then val
@ -110,6 +155,59 @@
builtins.unsafeDiscardStringContext
(pkgs.writeShellScript "nixtest-${config.name}" val).drvPath;
};
vmConfig = mkUnsetOption {
type = types.attrs;
description = ''
Configuration for `pkgs.testers.nixosText`.
'';
example = {
nodes.machine = {
services.nginx.enable = true;
};
testScript =
# py
''
machine.wait_for_unit("nginx.service")
machine.wait_for_open_port(80)
'';
};
};
finalConfig = mkOption {
internal = true;
type = types.attrs;
};
};
config = {
finalConfig = builtins.addErrorContext "[nixtest] while processing test ${config.name}" {
inherit (config) name expected actual actualDrv;
type =
if config.type == "vm"
then "script"
else config.type;
script =
if config.type == "vm"
then
assert assertMsg ((!isUnset config.vmConfig) && (config.vmConfig ? nodes) && (config.vmConfig ? testScript))
"test '${config.name}' as type 'vm' requires 'vmConfig' to be set and contain 'nodes' & 'testScript'"; let
inherit
(pkgs.testers.nixosTest (
{
name = "nixtest-vm-${config.name}";
}
// config.vmConfig
))
driver
;
in
builtins.unsafeDiscardStringContext
(pkgs.writeShellScript "nixtest-vm-${config.name}" ''
# use different TMPDIR to prevent race conditions:
# vde_switch: Could not bind to socket '/tmp/vde1.ctl/ctl': Address already in use
TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d) ${driver}/bin/nixos-test-driver
'').drvPath
else config.script;
};
};
};
@ -122,11 +220,19 @@
options = {
name = mkOption {
type = types.str;
description = ''
Name of the suite, uses attrset name by default.
'';
default = name;
defaultText = literalExpression name;
};
pos = mkOption {
type = types.either types.attrs unsetType;
default = unset;
pos = mkUnsetOption {
type = types.attrs;
description = ''
Position for tests, use `__curPos` for automatic insertion of current position.
This will set `pos` for every test of this suite, useful if the suite's tests are all in a single file.
'';
example = literalExpression "__curPos";
};
tests = mkOption {
type = types.listOf (types.submoduleWith {
@ -136,20 +242,41 @@
inherit testsBase;
};
});
description = ''
Define tests of this suite here.
'';
default = [];
};
finalConfig = mkOption {
internal = true;
type = types.attrs;
};
};
config = {
finalConfig = builtins.addErrorContext "[nixtest] while processing suite ${config.name}" {
inherit (config) name;
tests = map (test: test.finalConfig) config.tests;
};
};
};
nixtestSubmodule = {config, ...}: {
_file = ./module.nix;
options = {
base = mkOption {
description = "Base directory of the tests, will be removed from the test file path";
type = types.str;
description = ''
Base directory of the tests, will be removed from the test file path.
This makes it possible to show the relative path from the git repo, instead of ugly Nix store paths.
'';
default = "";
};
skip = mkOption {
type = types.str;
description = ''
Tests to skip, is passed to Nixtest's `--skip` param.
'';
default = "";
};
suites = mkOption {
@ -159,14 +286,23 @@
testsBase = config.base;
};
});
description = ''
Define your test suites here, every test belongs to a suite.
'';
default = {};
apply = suites:
map (
n: filterUnset (builtins.removeAttrs suites.${n} ["pos"])
)
(builtins.attrNames suites);
example = {
"Suite A".tests = [
{
name = "Some Test";
}
];
};
};
finalConfig = mkOption {
internal = true;
type = types.listOf types.attrs;
};
finalConfigJson = mkOption {
internal = true;
type = types.package;
@ -177,11 +313,18 @@
};
};
config = {
finalConfigJson = nixtest-lib.exportSuites config.suites;
app = nixtest-lib.mkBinary {
nixtests = config.finalConfigJson;
extraParams = ''--skip="${config.skip}"'';
};
finalConfig = map (suite: filterUnset suite.finalConfig) (builtins.attrValues config.suites);
finalConfigJson =
builtins.addErrorContext "[nixtest] while exporting suites"
(nixtest-lib.exportSuites config.finalConfig);
app =
(nixtest-lib.mkBinary {
nixtests = config.finalConfigJson;
extraParams = ''--skip="${config.skip}"'';
})
// {
rawTests = config.finalConfig;
};
};
};
in

View file

@ -35,16 +35,6 @@ function assert_file_not_contains() {
}
}
function tmpdir() {
dir=$(mktemp -d)
trap "rm -rf $dir" EXIT
echo -n "$dir"
}
function tmpfile() {
file=$(mktemp)
trap "rm -f $file" EXIT
echo -n "$file"
}
function run() {
output=$($@ 2>&1)
exit_code=$?

View file

@ -0,0 +1,8 @@
{inputs, ...}: let
inherit (inputs) self pkgs;
in {
nixtest = pkgs.callPackage "${self}/package.nix" {};
update-package = pkgs.writeShellScriptBin "update-package" ''
${pkgs.nix-update}/bin/nix-update nixtest --flake --version skip
'';
}

85
nix/repo/ci.nix Normal file
View file

@ -0,0 +1,85 @@
{inputs, ...}: let
inherit (inputs) pkgs cilib;
in
cilib.mkCI {
pipelines."default" = {
stages = ["test" "build" "deploy"];
jobs = {
"test:lib" = {
stage = "test";
script = [
"nix run .#tests -- --junit=junit.xml"
];
allow_failure = true;
artifacts = {
when = "always";
reports.junit = "junit.xml";
};
};
"test:go" = {
stage = "test";
nix.deps = with pkgs; [gcc go go-junit-report gocover-cobertura];
variables = {
GOPATH = "$CI_PROJECT_DIR/.go";
GOCACHE = "$CI_PROJECT_DIR/.go/pkg/mod";
};
script = [
# sh
''
set +e
go test -coverprofile=coverage.out -v 2>&1 ./... | go-junit-report -set-exit-code > report.xml
TEST_EXIT_CODE=$?
go tool cover -func coverage.out
gocover-cobertura < coverage.out > coverage.xml
exit $TEST_EXIT_CODE
''
];
allow_failure = true;
coverage = "/\(statements\)(?:\s+)?(\d+(?:\.\d+)?%)/";
cache.paths = [".go/pkg/mod/"];
artifacts = {
when = "always";
reports = {
junit = "report.xml";
coverage_report = {
coverage_format = "cobertura";
path = "coverage.xml";
};
};
};
};
"build" = {
stage = "build";
script = [
# sh
"nix build .#nixtest"
];
};
"docs" = {
stage = "build";
script = [
# sh
''
nix build .#docs:default
mkdir -p public
cp -r result/. public/
''
];
artifacts.paths = ["public"];
};
"pages" = {
nix.enable = false;
image = "alpine:latest";
stage = "deploy";
script = ["true"];
artifacts.paths = ["public"];
rules = [
{
"if" = "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH";
}
];
};
};
};
}

33
nix/repo/devShells.nix Normal file
View file

@ -0,0 +1,33 @@
{
inputs,
cell,
...
}: let
inherit (inputs) pkgs devshell treefmt;
inherit (cell) soonix;
in {
default = devshell.mkShell {
imports = [soonix.devshellModule];
packages = with pkgs; [
(treefmt.mkWrapper pkgs {
programs = {
alejandra.enable = true;
mdformat.enable = true;
gofmt.enable = true;
};
settings.formatter.mdformat.command = let
pkg = pkgs.python3.withPackages (p: [
p.mdformat
p.mdformat-mkdocs
]);
in "${pkg}/bin/mdformat";
})
gcc
go
gopls
delve
go-junit-report
gocover-cobertura
];
};
}

64
nix/repo/docs.nix Normal file
View file

@ -0,0 +1,64 @@
{inputs, ...}: let
inherit (inputs) pkgs doclib ntlib;
optionsDoc = doclib.mkOptionDocs {
module = ntlib.module;
roots = [
{
url = "https://gitlab.com/TECHNOFAB/nixtest/-/blob/main/lib";
path = "${inputs.self}/lib";
}
];
};
optionsDocs = pkgs.runCommand "options-docs" {} ''
mkdir -p $out
ln -s ${optionsDoc} $out/options.md
'';
in
(doclib.mkDocs {
docs."default" = {
base = "${inputs.self}";
path = "${inputs.self}/docs";
material = {
enable = true;
colors = {
primary = "green";
accent = "light green";
};
umami = {
enable = true;
src = "https://analytics.tf/umami";
siteId = "716d1869-9342-4b62-a770-e15d2d5c807d";
domains = ["nixtest.projects.tf"];
};
};
macros = {
enable = true;
includeDir = toString optionsDocs;
};
config = {
site_name = "Nixtest";
site_url = "https://nixtest.projects.tf";
repo_name = "TECHNOFAB/nixtest";
repo_url = "https://gitlab.com/TECHNOFAB/nixtest";
extra_css = ["style.css"];
theme = {
logo = "images/logo.svg";
icon.repo = "simple/gitlab";
favicon = "images/logo.svg";
};
nav = [
{"Introduction" = "index.md";}
{"Usage" = "usage.md";}
{"Reference" = "reference.md";}
{"CLI" = "cli.md";}
{"Example Configs" = "examples.md";}
{"Options" = "options.md";}
];
markdown_extensions = [
"pymdownx.superfences"
"admonition"
];
};
};
}).packages

100
nix/repo/flake.lock generated Normal file
View file

@ -0,0 +1,100 @@
{
"nodes": {
"devshell-lib": {
"locked": {
"dir": "lib",
"lastModified": 1767274074,
"narHash": "sha256-h2grM9qoSnYdqN7K8+taeMuWC2umaN/c2FCBu48frlo=",
"owner": "rensa-nix",
"repo": "devshell",
"rev": "5508ced269ee40ff7f5261ee3b5bf5597f7cad5d",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "rensa-nix",
"repo": "devshell",
"type": "gitlab"
}
},
"nix-gitlab-ci-lib": {
"locked": {
"dir": "lib",
"lastModified": 1765444672,
"narHash": "sha256-B0cMjRs9P50ym9Le0VUcRN69Yy6tbV13MXq81tTTEus=",
"owner": "TECHNOFAB",
"repo": "nix-gitlab-ci",
"rev": "8f88a53b5479773cd626420362631bc1da99e677",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "TECHNOFAB",
"ref": "3.1.2",
"repo": "nix-gitlab-ci",
"type": "gitlab"
}
},
"nixmkdocs-lib": {
"locked": {
"dir": "lib",
"lastModified": 1766404754,
"narHash": "sha256-EjBe6x6BT8ckPirMWhSf1GfaFxORYxR/Uu71FvSAm60=",
"owner": "TECHNOFAB",
"repo": "nixmkdocs",
"rev": "cfa9606eeeb9288e2799896d7d42b3d3860f9ccb",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "TECHNOFAB",
"repo": "nixmkdocs",
"type": "gitlab"
}
},
"root": {
"inputs": {
"devshell-lib": "devshell-lib",
"nix-gitlab-ci-lib": "nix-gitlab-ci-lib",
"nixmkdocs-lib": "nixmkdocs-lib",
"soonix-lib": "soonix-lib",
"treefmt-nix": "treefmt-nix"
}
},
"soonix-lib": {
"locked": {
"dir": "lib",
"lastModified": 1767274116,
"narHash": "sha256-8+VeMokZHjOLs6fRUTj/9uxbMlHKDl384Tk6K8Qjm4k=",
"owner": "TECHNOFAB",
"repo": "soonix",
"rev": "56f281eea45bdcf29674adfa7962f14e490a6051",
"type": "gitlab"
},
"original": {
"dir": "lib",
"owner": "TECHNOFAB",
"repo": "soonix",
"type": "gitlab"
}
},
"treefmt-nix": {
"flake": false,
"locked": {
"lastModified": 1767122417,
"narHash": "sha256-yOt/FTB7oSEKQH9EZMFMeuldK1HGpQs2eAzdS9hNS/o=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "dec15f37015ac2e774c84d0952d57fcdf169b54d",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

22
nix/repo/flake.nix Normal file
View file

@ -0,0 +1,22 @@
{
inputs = {
devshell-lib.url = "gitlab:rensa-nix/devshell?dir=lib";
soonix-lib.url = "gitlab:TECHNOFAB/soonix?dir=lib";
nix-gitlab-ci-lib.url = "gitlab:TECHNOFAB/nix-gitlab-ci/3.1.2?dir=lib";
nixmkdocs-lib.url = "gitlab:TECHNOFAB/nixmkdocs?dir=lib";
treefmt-nix = {
url = "github:numtide/treefmt-nix";
flake = false;
};
};
outputs = i:
i
// {
devshell = i.devshell-lib.lib {inherit (i.parent) pkgs;};
soonix = i.soonix-lib.lib {inherit (i.parent) pkgs;};
cilib = i.nix-gitlab-ci-lib.lib {inherit (i.parent) pkgs;};
doclib = i.nixmkdocs-lib.lib {inherit (i.parent) pkgs;};
ntlib = import "${i.parent.self}/lib" {inherit (i.parent) pkgs;};
treefmt = import i.treefmt-nix;
};
}

34
nix/repo/soonix.nix Normal file
View file

@ -0,0 +1,34 @@
{
inputs,
cell,
...
}: let
inherit (inputs) soonix;
inherit (cell) ci;
in
(soonix.make {
hooks = {
ci = ci.soonix;
renovate = {
output = ".gitlab/renovate.json5";
data = {
extends = ["config:recommended"];
postUpgradeTasks.commands = [
"nix-portable nix run .#update-package"
"nix-portable nix run .#soonix:update"
];
lockFileMaintenance = {
enabled = true;
extends = ["schedule:monthly"];
};
nix.enabled = true;
gitlabci.enabled = false;
};
hook = {
mode = "copy";
gitignore = false;
};
opts.format = "json";
};
};
}).config

10
nix/repo/tests.nix Normal file
View file

@ -0,0 +1,10 @@
{inputs, ...}: let
inherit (inputs) pkgs ntlib;
in {
tests = ntlib.mkNixtest {
modules = ntlib.autodiscover {dir = "${inputs.self}/tests";};
args = {
inherit pkgs ntlib;
};
};
}

View file

@ -4,7 +4,8 @@
...
}:
buildGoModule {
name = "nixtest";
pname = "nixtest";
version = "latest";
src =
# filter everything except for cmd/ and go.mod, go.sum
with lib.fileset;
@ -18,6 +19,6 @@ buildGoModule {
];
};
subPackages = ["cmd/nixtest"];
vendorHash = "sha256-6kARJgngmXielUoXukYdAA0QHk1mwLRvgKJhx+v1iSo=";
vendorHash = "sha256-WF/lzu9lt9SR3WiA8LLWVT1OwpE3sIOtSqf4HMIMmE8=";
meta.mainProgram = "nixtest";
}

View file

@ -1 +1 @@
"{\n example = \u003cfunction\u003e;\n example2 = {\n drv = \u003cderivation hello-2.12.1\u003e;\n };\n}"
"{\n example = \u003cfunction\u003e;\n example2 = {\n drv = \u003cderivation hello-2.12.2\u003e;\n };\n}"

View file

@ -49,6 +49,39 @@
grep -q "test" ${builtins.toFile "test" "test"}
'';
}
{
name = "test-vm";
type = "vm";
vmConfig = {
nodes.machine = {pkgs, ...}: {
services.nginx = {
enable = true;
virtualHosts."localhost" = {
root = pkgs.writeTextDir "index.html" "Hello from nixtest VM!";
};
};
};
testScript =
# py
''
machine.wait_for_unit("nginx.service")
machine.wait_for_open_port(80)
machine.succeed("curl -f http://localhost | grep 'Hello from nixtest VM!'")
'';
};
}
{
name = "vm-fail";
type = "vm";
vmConfig = {
nodes.machine = {};
testScript =
# py
''
machine.succeed("curl -f http://localhost | grep 'Hello from nixtest VM!'")
'';
};
}
];
};
"other-suite".tests = [

View file

@ -13,6 +13,10 @@
actual = ntlib.helpers.toPrettyFile (ntlib.autodiscover {
dir = ./fixtures;
});
# tests if strings with store path context work
actualDirString = ntlib.helpers.toPrettyFile (ntlib.autodiscover {
dir = "${./fixtures}";
});
in
# sh
''
@ -20,6 +24,9 @@
${ntlib.helpers.scriptHelpers}
assert_file_contains ${actual} "sample_test.nix" "should find sample_test.nix"
assert_file_contains ${actual} "base = \"/nix/store/.*-source/tests/fixtures/\"" "should set base to fixtures dir"
assert_file_contains ${actualDirString} "sample_test.nix" "should find sample_test.nix"
assert_file_contains ${actualDirString} "base = \"/nix/store/.*-fixtures/\"" "should set base to fixtures dir"
'';
}
{
@ -29,7 +36,7 @@
binary =
(ntlib.mkBinary {
nixtests = "stub";
extraParams = "--pure";
extraParams = "--impure";
})
+ "/bin/nixtests:run";
in
@ -38,7 +45,7 @@
${ntlib.helpers.path [pkgs.gnugrep]}
${ntlib.helpers.scriptHelpers}
assert_file_contains ${binary} "nixtest" "should contain nixtest"
assert_file_contains ${binary} "--pure" "should contain --pure arg"
assert_file_contains ${binary} "--impure" "should contain --impure arg"
assert_file_contains ${binary} "--tests=stub" "should contain --tests arg"
run "${binary} --help"
@ -63,26 +70,29 @@
in
# sh
''
${ntlib.helpers.path [pkgs.gnugrep pkgs.mktemp]}
${ntlib.helpers.path [pkgs.gnugrep pkgs.mktemp pkgs.coreutils]}
${ntlib.helpers.scriptHelpers}
export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
export NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
cp -r ${./../snapshots} snapshots
TMPDIR=$(tmpdir)
# start without nix & env binaries to expect errors
run "${binary} --pure --junit=$TMPDIR/junit.xml"
run "${binary} --junit=junit.xml"
assert "$exit_code -eq 2" "should exit 2"
assert "-f $TMPDIR/junit.xml" "should create junit.xml"
assert "-f junit.xml" "should create junit.xml"
assert_contains "$output" "executable file not found" "nix should not be found in pure mode"
# now add required deps
${ntlib.helpers.pathAdd [pkgs.nix pkgs.coreutils]}
run "${binary} --pure --junit=$TMPDIR/junit2.xml"
run "${binary} --junit=junit2.xml"
assert "$exit_code -eq 2" "should exit 2"
assert "-f $TMPDIR/junit2.xml" "should create junit2.xml"
assert "-f junit2.xml" "should create junit2.xml"
assert_not_contains "$output" "executable file not found" "nix should now exist"
assert_contains "$output" "suite-one" "should contain suite-one"
assert_contains "$output" "8/11 (1 SKIPPED)" "should be 8/11 total"
assert_contains "$output" "9/13 (1 SKIPPED)" "should be 9/13 total"
assert_contains "$output" "ERROR" "should contain an error"
assert_contains "$output" "SKIP" "should contain a skip"
assert_contains "$output" "RequestedAssertionFailed" "vm-fail test should fail"
'';
}
];