1
0
forked from clan/clan-core

Inventory: add eval tests

This commit is contained in:
Johannes Kirschbauer 2024-06-26 17:19:19 +02:00
parent 2535fdcb12
commit 1628fdeaee
Signed by: hsjobeki
SSH Key Fingerprint: SHA256:vX3utDqig7Ph5L0JPv87ZTPb/w7cMzREKVZzzLFg9qU
3 changed files with 226 additions and 31 deletions

View File

@ -13,13 +13,18 @@ let
++ (builtins.foldl' (
acc: tag:
let
# For error printing
availableTags = lib.foldlAttrs (
acc: _: v:
v.tags or [ ] ++ acc
) [ ] inventory.machines;
tagMembers = builtins.attrNames (
lib.filterAttrs (_n: v: builtins.elem tag v.tags or [ ]) inventory.machines
);
in
# throw "Machine tag ${tag} not found. Not machine with: tag ${tagName} not in inventory.";
if tagMembers == [ ] then
throw "Machine tag ${tag} not found. Not machine with: tag ${tag} not in inventory."
throw "Tag: '${tag}' not found. Available tags: ${builtins.toJSON (lib.unique availableTags)}"
else
acc ++ tagMembers
) [ ] members.tags or [ ]);
@ -76,7 +81,7 @@ let
if builtins.pathExists path then
path
else
throw "Role doesnt have a module: ${role}. Path: ${path} not found."
throw "Module doesn't have role: '${role}'. Path: ${path} not found."
) inverseRoles.${machineName} or [ ];
in
if isInService then
@ -101,6 +106,6 @@ let
acc2
) [ ] serviceConfigs)
) [ ] inventory.services
) inventory.machines;
) inventory.machines or { };
in
machines

View File

@ -1,42 +1,81 @@
{ self, ... }:
{ self, inputs, ... }:
let
inputOverrides = builtins.concatStringsSep " " (
builtins.map (input: " --override-input ${input} ${inputs.${input}}") (builtins.attrNames inputs)
);
in
{
flake.inventory = import ./example.nix { inherit self; };
perSystem =
{ pkgs, config, ... }:
{
pkgs,
lib,
config,
system,
...
}:
let
buildInventory = import ./build-inventory {
clan-core = self;
inherit lib;
};
in
{
devShells.inventory-schema = pkgs.mkShell {
inputsFrom = [ config.checks.inventory-schema-checks ];
inputsFrom = with config.checks; [
lib-inventory-schema
lib-inventory-eval
];
};
checks.inventory-schema-checks = pkgs.stdenv.mkDerivation {
name = "inventory-schema-checks";
src = ./.;
buildInputs = [ pkgs.cue ];
buildPhase = ''
echo "Running inventory tests..."
# Cue is easier to run in the same directory as the schema
cd spec
# Run: nix-unit --extra-experimental-features flakes --flake .#legacyPackages.x86_64-linux.evalTests
legacyPackages.evalTests = import ./tests {
inherit buildInventory;
clan-core = self;
};
echo "Export cue as json-schema..."
cue export --out openapi root.cue
checks = {
lib-inventory-eval = pkgs.runCommand "tests" { nativeBuildInputs = [ pkgs.nix-unit ]; } ''
export HOME="$(realpath .)"
echo "Validate test/*.json against inventory-schema..."
test_dir="../examples"
for file in "$test_dir"/*; do
# Check if the item is a file
if [ -f "$file" ]; then
# Print the filename
echo "Running test on: $file"
# Run the cue vet command
cue vet "$file" root.cue -d "#Root"
fi
done
nix-unit --eval-store "$HOME" \
--extra-experimental-features flakes \
${inputOverrides} \
--flake ${self}#legacyPackages.${system}.evalTests
touch $out
'';
lib-inventory-schema = pkgs.stdenv.mkDerivation {
name = "inventory-schema-checks";
src = ./.;
buildInputs = [ pkgs.cue ];
buildPhase = ''
echo "Running inventory tests..."
# Cue is easier to run in the same directory as the schema
cd spec
echo "Export cue as json-schema..."
cue export --out openapi root.cue
echo "Validate test/*.json against inventory-schema..."
test_dir="../examples"
for file in "$test_dir"/*; do
# Check if the item is a file
if [ -f "$file" ]; then
# Print the filename
echo "Running test on: $file"
# Run the cue vet command
cue vet "$file" root.cue -d "#Root"
fi
done
touch $out
'';
};
};
};
}

View File

@ -0,0 +1,151 @@
{ buildInventory, clan-core, ... }:
{
test_inventory_empty = {
# Empty inventory should return an empty module
expr = buildInventory { };
expected = { };
};
test_inventory_role_imports =
let
configs = buildInventory {
services = {
borgbackup.instance_1 = {
roles.server.machines = [ "backup_server" ];
roles.client.machines = [
"client_1_machine"
"client_2_machine"
];
};
};
machines = {
"backup_server" = { };
"client_1_machine" = { };
"client_2_machine" = { };
};
};
in
{
expr = {
server_imports = (builtins.head configs."backup_server").imports;
client_1_imports = (builtins.head configs."client_1_machine").imports;
client_2_imports = (builtins.head configs."client_2_machine").imports;
};
expected = {
server_imports = [
clan-core.clanModules.borgbackup
"${clan-core.clanModules.borgbackup}/roles/server.nix"
];
client_1_imports = [
clan-core.clanModules.borgbackup
"${clan-core.clanModules.borgbackup}/roles/client.nix"
];
client_2_imports = [
clan-core.clanModules.borgbackup
"${clan-core.clanModules.borgbackup}/roles/client.nix"
];
};
};
test_inventory_tag_resolve =
let
configs = buildInventory {
services = {
borgbackup.instance_1 = {
roles.client.tags = [ "backup" ];
};
};
machines = {
"not_used_machine" = { };
"client_1_machine" = {
tags = [ "backup" ];
};
"client_2_machine" = {
tags = [ "backup" ];
};
};
};
in
{
expr = {
client_1_machine = builtins.length configs.client_1_machine;
client_2_machine = builtins.length configs.client_2_machine;
not_used_machine = builtins.length configs.not_used_machine;
};
expected = {
client_1_machine = 2;
client_2_machine = 2;
not_used_machine = 0;
};
};
test_inventory_multiple_roles =
let
configs = buildInventory {
services = {
borgbackup.instance_1 = {
roles.client.machines = [ "machine_1" ];
roles.server.machines = [ "machine_1" ];
};
};
machines = {
"machine_1" = { };
};
};
in
{
expr = {
machine_1_imports = (builtins.head configs."machine_1").imports;
};
expected = {
machine_1_imports = [
clan-core.clanModules.borgbackup
"${clan-core.clanModules.borgbackup}/roles/client.nix"
"${clan-core.clanModules.borgbackup}/roles/server.nix"
];
};
};
test_inventory_role_doesnt_exist =
let
configs = buildInventory {
services = {
borgbackup.instance_1 = {
roles.roleXYZ.machines = [ "machine_1" ];
};
};
machines = {
"machine_1" = { };
};
};
in
{
expr = configs;
expectedError = {
type = "ThrownError";
msg = "Module doesn't have role.*";
};
};
test_inventory_tag_doesnt_exist =
let
configs = buildInventory {
services = {
borgbackup.instance_1 = {
roles.client.machines = [ "machine_1" ];
roles.client.tags = [ "tagXYZ" ];
};
};
machines = {
"machine_1" = {
tags = [ "tagABC" ];
};
};
};
in
{
expr = configs;
expectedError = {
type = "ThrownError";
msg = "Tag: '\\w+' not found";
};
};
}