diff --git a/README.md b/README.md new file mode 100644 index 0000000..657bbed --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Nixtest + +[![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) +[![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) + +Flexible test runner for testing Nix code, written in Go. + +## Features + +- Snapshot, Unit (equal checks) and Script-Tests (unit tests with assertions you could say) +- Supports testing against raw Nix code or derivation output +- Simple and easy to read summary of test results +- Junit report support (eg. for displaying the results in GitLab etc.) + +## Usage + +See the [docs](https://nixtest.projects.tf/usage). diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 0000000..9c69c9c --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,12 @@ +# CLI + +```sh title="nix run .#nixtests:run -- --help" +Usage of nixtest: + --junit string Path to generate JUNIT report to, leave empty to disable + --pure Unset all env vars before running script tests + --skip string Regular expression to skip (e.g., 'test-.*|.*-b') + --snapshot-dir string Directory where snapshots are stored (default "./snapshots") + --tests string Path to JSON file containing tests + --update-snapshots Update all snapshots + --workers int Amount of tests to run in parallel (default 4) +``` diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 0000000..4e3ad41 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,4 @@ +# Example Configs + +- [TECHNOFAB/nix-gitlab-ci](https://gitlab.com/TECHNOFAB/nix-gitlab-ci) + see tests/ diff --git a/docs/images/favicon.png b/docs/images/favicon.png new file mode 100755 index 0000000..4203f2a Binary files /dev/null and b/docs/images/favicon.png differ diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100755 index 0000000..b8ff5f8 Binary files /dev/null and b/docs/images/logo.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..37124d9 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,10 @@ +# Nixtest + +Flexible test runner for testing Nix code, written in Go. + +## Features + +- Snapshot, Unit (equal checks) and Script-Tests (unit tests with assertions you could say) +- Supports testing against raw Nix code or derivation output +- Simple and easy to read summary of test results +- Junit report support (eg. for displaying the results in GitLab etc.) diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..2c72e4a --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,104 @@ +# Usage + +## Flake Module + +```nix +{ + inputs.nixtest.url = "gitlab:TECHNOFAB/nixtest?dir=lib"; + # ... mkFlake ... + imports = [ + inputs.nixtest.flakeModule + ]; + + # perSystem + nixtest = { + # regex of tests to skip. Can also be passed as CLI arg + skip = ""; + suites = { + "Suite A" = { + # pos shows the file the test was declared in in the summary and + # junit report by setting it on the suite, all tests inherit this pos + pos = __curPos; + tests = [ + # define tests here (see below) + ]; + }; + "Suite B" = { + # etc. + }; + }; + }; + # ... +} +``` + +## Library + +You can also integrate nixtest in your own workflow by using the lib functions directly. +Check out `flakeModule.nix` to see how it's used there. + + + +## Define Tests + +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` + +Examples: + +```nix +[ + { + name = "unit-test"; # required + type = "unit"; # default is unit + expected = 1; + actual = 1; + } + { + name = "snapshot-test"; + type = "snapshot"; + # snapshot tests use snapshot files (stored by default in ./snapshots/) + # and compare the "actual" value below with these files + actual = 1; + } + { + name = "snapshot-derivation-test"; + type = "snapshot"; + # instead of passing a nix expression, we can also use a derivation to do + # more complex stuff. Will only be built when running the test (+ included + # in the test time). + actualDrv = pkgs.runCommand "test-snapshot" {} '' + echo '"snapshot drv"' > $out + ''; + } + { + name = "script-test"; + type = "script"; + script = + # there are two modes, "default"/"impure" and "pure" + # 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 + # mode which will unset all env variables before running the test. That + # requires you to set PATH yourself then: + '' + export PATH="${lib.makeBinPath [pkgs.gnugrep]}" + grep -q "test" ${builtins.toFile "test" "test"} + ''; + } + { + name = "pretty-test"; + # by default it uses json to serialize and compare the values. Derivations + # and functions don't really work that way though, so you can also use + # "pretty" to use lib.generators.pretty + format = "pretty"; + # you can also set the pos here + pos = __curPos; + expected = pkgs.hello; + actual = pkgs.hello; + } +] +``` diff --git a/flake.lock b/flake.lock index f6538f2..e4cecf7 100644 --- a/flake.lock +++ b/flake.lock @@ -169,6 +169,21 @@ "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": [ @@ -205,21 +220,38 @@ "nix-gitlab-ci": { "locked": { "dir": "lib", - "lastModified": 1746300997, - "narHash": "sha256-PuI1WaDFgvRh5d0yBAJzkbbonZaTxqWqm1hu3WP+9iU=", - "owner": "TECHNOFAB", + "lastModified": 1746973171, + "narHash": "sha256-q/LhPZlhJB2gXZ5BfgU1Wep/1x1y9Sct3/JU8A2fzjg=", + "owner": "technofab", "repo": "nix-gitlab-ci", - "rev": "9ee4ad02b8f950d48fb30ab11b8475a3f52d327c", + "rev": "dca2d724c155799e537a898cb9f948f8afae4921", "type": "gitlab" }, "original": { "dir": "lib", - "owner": "TECHNOFAB", - "ref": "2.0.0", + "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, @@ -319,7 +351,9 @@ "inputs": { "devenv": "devenv", "flake-parts": "flake-parts_2", + "mkdocs-material-umami": "mkdocs-material-umami", "nix-gitlab-ci": "nix-gitlab-ci", + "nix-mkdocs": "nix-mkdocs", "nixpkgs": "nixpkgs_4", "systems": "systems", "treefmt-nix": "treefmt-nix" diff --git a/flake.nix b/flake.nix index 940057a..8f90425 100644 --- a/flake.nix +++ b/flake.nix @@ -9,6 +9,7 @@ inputs.devenv.flakeModule inputs.treefmt-nix.flakeModule inputs.nix-gitlab-ci.flakeModule + inputs.nix-mkdocs.flakeModule ./lib/flakeModule.nix ]; systems = import systems; @@ -26,6 +27,12 @@ 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 {}; @@ -136,8 +143,84 @@ }; }; + 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";} + {"CLI" = "cli.md";} + {"Example Configs" = "examples.md";} + ]; + markdown_extensions = [ + "pymdownx.superfences" + ]; + 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"]; + stages = ["test" "build" "deploy"]; jobs = { "test" = { stage = "test"; @@ -150,6 +233,30 @@ reports.junit = "junit.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"; + } + ]; + }; }; }; @@ -165,7 +272,9 @@ 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.0?dir=lib"; + nix-gitlab-ci.url = "gitlab:technofab/nix-gitlab-ci/2.0.1?dir=lib"; + nix-mkdocs.url = "gitlab:technofab/nixmkdocs?dir=lib"; + mkdocs-material-umami.url = "gitlab:technofab/mkdocs-material-umami"; }; nixConfig = {