Compare commits

..

No commits in common. "main" and "v1.1.0" have entirely different histories.
main ... v1.1.0

46 changed files with 755 additions and 805 deletions

3
.envrc
View file

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

3
.gitignore vendored
View file

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

View file

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

View file

@ -1,23 +0,0 @@
{
"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) [![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) [![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/nixtest) ![License: MIT](https://img.shields.io/gitlab/license/technofab/nix-gitlab-ci)
[![Latest Release](https://gitlab.com/TECHNOFAB/nixtest/-/badges/release.svg)](https://gitlab.com/TECHNOFAB/nixtest/-/releases) [![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) [![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) [![Docs](https://img.shields.io/badge/Read-Docs-green)](https://nixtest.projects.tf)

View file

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

View file

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

BIN
docs/images/favicon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
docs/images/logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

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

View file

@ -1,15 +0,0 @@
.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,7 +64,6 @@ There are currently 3 types of tests:
- `snapshot` -> snapshot testing, only needs `actual` and compares that to the snapshot - `snapshot` -> snapshot testing, only needs `actual` and compares that to the snapshot
- `unit` -> equality checking, needs `expected` and `actual` or `actualDrv` - `unit` -> equality checking, needs `expected` and `actual` or `actualDrv`
- `script` -> shell script test, needs `script` - `script` -> shell script test, needs `script`
- `vm` -> NixOS VM test, needs `vmConfig`
Examples: Examples:
@ -97,10 +96,10 @@ Examples:
name = "script-test"; name = "script-test";
type = "script"; type = "script";
script = script =
# there are two modes, "default"/"pure" and "impure" # there are two modes, "default"/"impure" and "pure"
# in impure mode all env variables etc. from your current session are kept # in impure mode all env variables etc. from your current session are kept
# and are available to the test (using --impure). # and are available to the test
# to make it more reproducible and cleaner, the default is pure # to make it more reproducible and cleaner, use --pure to switch to pure
# mode which will unset all env variables before running the test. That # mode which will unset all env variables before running the test. That
# requires you to set PATH yourself then: # requires you to set PATH yourself then:
# #
@ -127,23 +126,6 @@ Examples:
expected = pkgs.hello; expected = pkgs.hello;
actual = 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,12 +1,281 @@
{ {
"nodes": { "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": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1767116409, "lastModified": 1733212471,
"narHash": "sha256-5vKw92l1GyTnjoLzEagJy5V5mDFck72LiQWZSOnSicw=", "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "cad22e7d996aea55ecab064e84834289143e44a0", "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -18,11 +287,11 @@
}, },
"nixpkgs-lib": { "nixpkgs-lib": {
"locked": { "locked": {
"lastModified": 1754184128, "lastModified": 1743296961,
"narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=", "narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixpkgs.lib", "repo": "nixpkgs.lib",
"rev": "02e72200e6d56494f4a7c0da8118760736e41b60", "rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -31,30 +300,114 @@
"type": "github" "type": "github"
} }
}, },
"ren": { "nixpkgs_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": { "locked": {
"dir": "lib", "lastModified": 1717432640,
"lastModified": 1766497301, "narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"narHash": "sha256-W7WeOXMUZROMtbU1qQNWy/yai+k8gG09YACFQ7ImpsQ=", "owner": "NixOS",
"owner": "rensa-nix", "repo": "nixpkgs",
"repo": "core", "rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"rev": "e08c48b5db1052bfb8b8dad764e05decc1af893e", "type": "github"
"type": "gitlab"
}, },
"original": { "original": {
"dir": "lib", "owner": "NixOS",
"owner": "rensa-nix", "ref": "release-24.05",
"repo": "core", "repo": "nixpkgs",
"type": "gitlab" "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"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "devenv": "devenv",
"ren": "ren" "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"
} }
} }
}, },

270
flake.nix
View file

@ -1,39 +1,251 @@
{ {
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
ren.url = "gitlab:rensa-nix/core?dir=lib";
};
outputs = { outputs = {
ren, flake-parts,
self, systems,
... ...
} @ inputs: } @ inputs:
ren.buildWith flake-parts.lib.mkFlake {inherit inputs;} {
{ imports = [
inherit inputs; inputs.devenv.flakeModule
cellsFrom = ./nix; inputs.treefmt-nix.flakeModule
transformInputs = system: i: inputs.nix-gitlab-ci.flakeModule
i inputs.nix-devtools.flakeModule
// { inputs.nix-mkdocs.flakeModule
pkgs = import i.nixpkgs {inherit system;};
};
cellBlocks = with ren.blocks; [
(simple "devShells")
(simple "ci")
(simple "tests")
(simple "packages")
(simple "docs")
(simple "soonix")
]; ];
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";
};
} }
{ {
packages = ren.select self [ scheme = "slate";
["repo" "ci" "packages"] media = "(prefers-color-scheme: dark)";
["repo" "tests"] primary = "green";
["packages" "packages"] accent = "light green";
["repo" "docs"] toggle = {
["repo" "soonix" "packages"] 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.23.0 go 1.24.2
require ( require (
github.com/akedrou/textdiff v0.1.0 github.com/akedrou/textdiff v0.1.0
github.com/rs/zerolog v1.34.0 github.com/rs/zerolog v1.34.0
github.com/spf13/pflag v1.0.10 github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.10.0
) )
require ( require (
@ -19,9 +19,9 @@ require (
) )
require ( require (
github.com/jedib0t/go-pretty/v6 v6.7.8 github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/sergi/go-diff v1.4.0 github.com/sergi/go-diff v1.3.1
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.33.0 // indirect
) )

10
go.sum
View file

@ -7,10 +7,6 @@ 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/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 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.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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -36,18 +32,12 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= 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 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.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 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 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/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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 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.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.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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.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 JunitPath string
UpdateSnapshots bool UpdateSnapshots bool
SkipPattern string SkipPattern string
ImpureEnv bool PureEnv bool
NoColor 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.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.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.StringVarP(&cfg.SkipPattern, "skip", "s", "", "Regular expression to skip tests (e.g., 'test-.*|.*-b')")
flag.BoolVar(&cfg.ImpureEnv, "impure", false, "Don't unset all env vars before running script tests") flag.BoolVar(&cfg.PureEnv, "pure", false, "Unset all env vars before running script tests")
flag.BoolVar(&cfg.NoColor, "no-color", false, "Disable coloring") flag.BoolVar(&cfg.NoColor, "no-color", false, "Disable coloring")
helpRequested := flag.BoolP("help", "h", false, "Show this menu") helpRequested := flag.BoolP("help", "h", false, "Show this menu")

View file

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

View file

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

View file

@ -10,7 +10,7 @@ import (
"strings" "strings"
"testing" "testing"
apperrors "gitlab.com/TECHNOFAB/nixtest/internal/errors" apperrors "gitlab.com/technofab/nixtest/internal/errors"
) )
func TestHelperProcess(t *testing.T) { func TestHelperProcess(t *testing.T) {
@ -232,7 +232,7 @@ func TestDefaultService_BuildAndRunScript(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
derivation string derivation string
impureEnv bool pureEnv bool
mockBuildDrvOutput string mockBuildDrvOutput string
mockBuildDrvError string mockBuildDrvError string
mockBuildDrvExitCode string mockBuildDrvExitCode string
@ -252,7 +252,7 @@ func TestDefaultService_BuildAndRunScript(t *testing.T) {
0, "Hello", "ErrOut", false, nil, "", 0, "Hello", "ErrOut", false, nil, "",
}, },
{ {
"Success impure", "script.drv#sh", true, mockScriptPath, "", "0", "Success pure", "script.drv#sh", true, mockScriptPath, "", "0",
"Hello", "ErrOut", "0", "Hello", "ErrOut", "0",
0, "Hello", "ErrOut", false, nil, "", 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_STDERR", tt.mockScriptStderr)
os.Setenv("MOCK_SCRIPT_EXIT_CODE", tt.mockScriptExitCode) os.Setenv("MOCK_SCRIPT_EXIT_CODE", tt.mockScriptExitCode)
exitCode, stdout, stderr, err := service.BuildAndRunScript(tt.derivation, tt.impureEnv) exitCode, stdout, stderr, err := service.BuildAndRunScript(tt.derivation, tt.pureEnv)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Fatalf("BuildAndRunScript() error = %v, wantErr %v", err, 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/jedib0t/go-pretty/v6/text"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/sergi/go-diff/diffmatchpatch" "github.com/sergi/go-diff/diffmatchpatch"
"gitlab.com/TECHNOFAB/nixtest/internal/types" "gitlab.com/technofab/nixtest/internal/types"
"gitlab.com/TECHNOFAB/nixtest/internal/util" "gitlab.com/technofab/nixtest/internal/util"
) )
// PrintErrors prints error messages for failed tests // PrintErrors prints error messages for failed tests

View file

@ -12,7 +12,7 @@ import (
"time" "time"
"github.com/jedib0t/go-pretty/v6/text" "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 // captureOutput captures stdout and stderr during the execution of a function

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,7 +8,7 @@ import (
"github.com/akedrou/textdiff" "github.com/akedrou/textdiff"
"github.com/akedrou/textdiff/myers" "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) { func ComputeDiff(expected, actual string) (string, error) {

View file

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

View file

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

View file

@ -3,19 +3,7 @@
lib, lib,
... ...
}: let }: let
inherit inherit (lib) mkOptionType mkOption types;
(lib)
mkOptionType
mkOption
types
filterAttrs
isType
removePrefix
assertMsg
generators
literalExpression
xor
;
nixtest-lib = import ./default.nix {inherit pkgs lib;}; nixtest-lib = import ./default.nix {inherit pkgs lib;};
@ -28,26 +16,14 @@
unset = { unset = {
_type = "unset"; _type = "unset";
}; };
isUnset = isType "unset"; isUnset = lib.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: filterUnset = value:
if builtins.isAttrs value && !builtins.hasAttr "_type" value if builtins.isAttrs value && !builtins.hasAttr "_type" value
then let then let
filteredAttrs = builtins.mapAttrs (n: v: filterUnset v) value; filteredAttrs = builtins.mapAttrs (n: v: filterUnset v) value;
in in
filterAttrs (name: value: (!isUnset value)) filteredAttrs lib.filterAttrs (name: value: (!isUnset value)) filteredAttrs
else if builtins.isList value else if builtins.isList value
then builtins.filter (elem: !isUnset elem) (map filterUnset value) then builtins.filter (elem: !isUnset elem) (map filterUnset value)
else value; else value;
@ -59,95 +35,74 @@
... ...
}: { }: {
options = { options = {
pos = mkUnsetOption { pos = mkOption {
type = types.attrs; type = types.either types.attrs unsetType;
description = ''
Position of test, use `__curPos` for automatic insertion of current position.
'';
default = pos; default = pos;
apply = val: apply = val:
if isUnset val if isUnset val
then val then val
else let else let
fileRelative = removePrefix testsBase val.file; fileRelative = lib.removePrefix testsBase val.file;
in "${fileRelative}:${toString val.line}"; in "${fileRelative}:${toString val.line}";
}; };
type = mkOption { type = mkOption {
type = types.enum ["unit" "snapshot" "script" "vm"]; type = types.enum ["unit" "snapshot" "script"];
description = ''
Type of test, has to be one of "unit", "snapshot", "script", or "vm".
'';
default = "unit"; default = "unit";
apply = value: apply = value:
assert assertMsg (value == "script" -> !isUnset config.script) assert lib.assertMsg (value != "script" || !isUnset config.script)
"test '${config.name}' as type 'script' requires 'script' to be set"; "test '${config.name}' as type 'script' requires 'script' to be set";
assert assertMsg (value == "unit" -> !isUnset config.expected) assert lib.assertMsg (value != "unit" || !isUnset config.expected)
"test '${config.name}' as type 'unit' requires 'expected' to be set"; "test '${config.name}' as type 'unit' requires 'expected' to be set";
assert assertMsg (value == "unit" -> (xor (isUnset config.actual) (isUnset config.actualDrv))) assert lib.assertMsg (
let
actualIsUnset = isUnset config.actual;
actualDrvIsUnset = isUnset config.actualDrv;
in
(value != "unit")
|| (!actualIsUnset && actualDrvIsUnset)
|| (actualIsUnset && !actualDrvIsUnset)
)
"test '${config.name}' as type 'unit' requires only 'actual' OR 'actualDrv' to be set"; value; "test '${config.name}' as type 'unit' requires only 'actual' OR 'actualDrv' to be set"; value;
}; };
name = mkOption { name = mkOption {
type = types.str; type = types.str;
description = ''
Name of this test.
'';
}; };
description = mkUnsetOption { description = mkOption {
type = types.str; type = types.either types.str unsetType;
description = '' default = unset;
Short description of the test.
'';
}; };
format = mkOption { format = mkOption {
type = types.enum ["json" "pretty"]; 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"; default = "json";
}; };
expected = mkUnsetOption { expected = mkOption {
type = types.anything; type = types.anything;
description = '' default = unset;
Expected value of the test. Remember, the values are serialized (see [here](#suitesnametestsformat)).
'';
apply = val: apply = val:
if isUnset val || config.format == "json" if isUnset val || config.format == "json"
then val then val
else generators.toPretty {} val; else lib.generators.toPretty {} val;
}; };
actual = mkUnsetOption { actual = mkOption {
type = types.anything; type = types.anything;
description = '' default = unset;
Actual value of the test. Remember, the values are serialized (see [here](#suitesnametestsformat)).
'';
apply = val: apply = val:
if isUnset val || config.format == "json" if isUnset val || config.format == "json"
then val then val
else generators.toPretty {} val; else lib.generators.toPretty {} val;
}; };
actualDrv = mkUnsetOption { actualDrv = mkOption {
type = types.package; type = types.either types.package unsetType;
description = '' default = unset;
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: apply = val:
# keep unset value # keep unset value
if isUnset val if isUnset val
then val then val
else builtins.unsafeDiscardStringContext (val.drvPath or ""); else builtins.unsafeDiscardStringContext (val.drvPath or "");
}; };
script = mkUnsetOption { script = mkOption {
type = types.str; type = types.either types.str unsetType;
description = '' default = unset;
Script to run for the test.
Nixtest will run this, failing the test if it exits with a non-zero exit code.
'';
apply = val: apply = val:
if isUnset val if isUnset val
then val then val
@ -155,59 +110,6 @@
builtins.unsafeDiscardStringContext builtins.unsafeDiscardStringContext
(pkgs.writeShellScript "nixtest-${config.name}" val).drvPath; (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;
};
}; };
}; };
@ -220,19 +122,11 @@
options = { options = {
name = mkOption { name = mkOption {
type = types.str; type = types.str;
description = ''
Name of the suite, uses attrset name by default.
'';
default = name; default = name;
defaultText = literalExpression name;
}; };
pos = mkUnsetOption { pos = mkOption {
type = types.attrs; type = types.either types.attrs unsetType;
description = '' default = unset;
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 { tests = mkOption {
type = types.listOf (types.submoduleWith { type = types.listOf (types.submoduleWith {
@ -242,41 +136,20 @@
inherit testsBase; inherit testsBase;
}; };
}); });
description = ''
Define tests of this suite here.
'';
default = []; 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, ...}: { nixtestSubmodule = {config, ...}: {
_file = ./module.nix;
options = { options = {
base = mkOption { base = mkOption {
description = "Base directory of the tests, will be removed from the test file path";
type = types.str; 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 = ""; default = "";
}; };
skip = mkOption { skip = mkOption {
type = types.str; type = types.str;
description = ''
Tests to skip, is passed to Nixtest's `--skip` param.
'';
default = ""; default = "";
}; };
suites = mkOption { suites = mkOption {
@ -286,23 +159,14 @@
testsBase = config.base; testsBase = config.base;
}; };
}); });
description = ''
Define your test suites here, every test belongs to a suite.
'';
default = {}; default = {};
example = { apply = suites:
"Suite A".tests = [ map (
{ n: filterUnset (builtins.removeAttrs suites.${n} ["pos"])
name = "Some Test"; )
} (builtins.attrNames suites);
];
};
}; };
finalConfig = mkOption {
internal = true;
type = types.listOf types.attrs;
};
finalConfigJson = mkOption { finalConfigJson = mkOption {
internal = true; internal = true;
type = types.package; type = types.package;
@ -313,17 +177,10 @@
}; };
}; };
config = { config = {
finalConfig = map (suite: filterUnset suite.finalConfig) (builtins.attrValues config.suites); finalConfigJson = nixtest-lib.exportSuites config.suites;
finalConfigJson = app = nixtest-lib.mkBinary {
builtins.addErrorContext "[nixtest] while exporting suites"
(nixtest-lib.exportSuites config.finalConfig);
app =
(nixtest-lib.mkBinary {
nixtests = config.finalConfigJson; nixtests = config.finalConfigJson;
extraParams = ''--skip="${config.skip}"''; extraParams = ''--skip="${config.skip}"'';
})
// {
rawTests = config.finalConfig;
}; };
}; };
}; };

View file

@ -35,6 +35,16 @@ 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() { function run() {
output=$($@ 2>&1) output=$($@ 2>&1)
exit_code=$? exit_code=$?

View file

@ -1,8 +0,0 @@
{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
'';
}

View file

@ -1,85 +0,0 @@
{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";
}
];
};
};
};
}

View file

@ -1,33 +0,0 @@
{
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
];
};
}

View file

@ -1,64 +0,0 @@
{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
View file

@ -1,100 +0,0 @@
{
"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
}

View file

@ -1,22 +0,0 @@
{
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;
};
}

View file

@ -1,34 +0,0 @@
{
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

View file

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

View file

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

View file

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

View file

@ -49,39 +49,6 @@
grep -q "test" ${builtins.toFile "test" "test"} 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 = [ "other-suite".tests = [

View file

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