integration-tests: init

This commit is contained in:
Zhaofeng Li 2023-01-06 00:59:38 -07:00
parent 330f4e4ac7
commit 979108869d
6 changed files with 265 additions and 2 deletions

View file

@ -24,7 +24,7 @@
let let
version = "0.1.0"; version = "0.1.0";
ignoredPaths = [ ".github" "target" "book" "nixos" ]; ignoredPaths = [ ".github" "target" "book" "nixos" "integration-tests" ];
src = lib.cleanSourceWith { src = lib.cleanSourceWith {
filter = name: type: !(type == "directory" && builtins.elem (baseNameOf name) ignoredPaths); filter = name: type: !(type == "directory" && builtins.elem (baseNameOf name) ignoredPaths);

View file

@ -25,7 +25,10 @@
craneLib = crane.mkLib pkgs; craneLib = crane.mkLib pkgs;
in pkgs.callPackage ./crane.nix { inherit craneLib; }; in pkgs.callPackage ./crane.nix { inherit craneLib; };
in flake-utils.lib.eachSystem supportedSystems (system: let in flake-utils.lib.eachSystem supportedSystems (system: let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs {
inherit system;
overlays = [];
};
cranePkgs = makeCranePkgs pkgs; cranePkgs = makeCranePkgs pkgs;
inherit (pkgs) lib; inherit (pkgs) lib;
@ -107,6 +110,14 @@
internal = { internal = {
inherit (cranePkgs) attic-tests cargoArtifacts; inherit (cranePkgs) attic-tests cargoArtifacts;
}; };
checks = lib.optionalAttrs pkgs.stdenv.isLinux (import ./integration-tests {
pkgs = import nixpkgs {
inherit system;
overlays = [ self.overlays.default ];
};
flake = self;
});
}) // { }) // {
overlays = { overlays = {
default = final: prev: let default = final: prev: let

View file

@ -0,0 +1,3 @@
# End-to-End Tests
This directory contains some end-to-end tests for Attic.

View file

@ -0,0 +1,204 @@
{ pkgs, lib, config, flake, attic, ... }:
let
inherit (lib) types;
serverConfigFile = config.nodes.server.services.atticd.configFile;
cmd = {
atticadm = ". /etc/atticd.env && export ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64 && atticadm -f ${serverConfigFile}";
atticd = ". /etc/atticd.env && export ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64 && atticd -f ${serverConfigFile}";
};
testDrv = pkgs.writeText "test.nix" ''
#!/bin/sh
/*/sh -c "echo hello > $out"; exit 0; */
derivation {
name = "hello.txt";
builder = ./test.nix;
system = builtins.currentSystem;
preferLocalBuild = true;
allowSubstitutes = false;
}
'';
databaseModules = {
sqlite = {};
postgres = {
server = {
services.postgresql = {
enable = true;
ensureDatabases = [ "attic" ];
ensureUsers = [
{
name = "atticd";
ensurePermissions = {
"DATABASE attic" = "ALL PRIVILEGES";
};
}
# For testing only - Don't actually do this
{
name = "root";
ensureClauses = {
superuser = true;
};
}
];
};
services.atticd.settings = {
database.url = "postgresql:///attic?host=/run/postgresql";
};
};
};
};
storageModules = {
local = {};
minio = let
accessKey = "legit";
secretKey = "111-1111111";
in {
server = {
services.minio = {
enable = true;
rootCredentialsFile = "/etc/minio.env";
};
# For testing only - Don't actually do this
environment.etc."minio.env".text = ''
MINIO_ROOT_USER=${accessKey}
MINIO_ROOT_PASSWORD=${secretKey}
'';
networking.firewall.allowedTCPPorts = [ 9000 ];
services.atticd.settings = {
storage = {
type = "s3";
endpoint = "http://server:9000";
region = "us-east-1";
bucket = "attic";
credentials = {
access_key_id = accessKey;
secret_access_key = secretKey;
};
};
};
};
testScript = ''
server.succeed("mkdir /var/lib/minio/data/attic")
server.succeed("chown minio: /var/lib/minio/data/attic")
client.wait_until_succeeds("curl http://server:9000", timeout=10)
'';
};
};
in {
options = {
database = lib.mkOption {
type = types.enum [ "sqlite" "postgres" ];
default = "sqlite";
};
storage = lib.mkOption {
type = types.enum [ "local" "minio" ];
default = "local";
};
};
config = {
name = "basic-${config.database}-${config.storage}";
nodes = {
server = {
imports = [
flake.nixosModules.atticd
(databaseModules.${config.database}.server or {})
(storageModules.${config.storage}.server or {})
];
# For testing only - Don't actually do this
environment.etc."atticd.env".text = ''
ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64="dGVzdCBzZWNyZXQ="
'';
services.atticd = {
enable = true;
credentialsFile = "/etc/atticd.env";
settings = {
listen = "[::]:8080";
};
};
networking.firewall.allowedTCPPorts = [ 8080 ];
};
client = {
environment.systemPackages = [ pkgs.attic ];
};
};
testScript = ''
import time
start_all()
${databaseModules.${config.database}.testScript or ""}
${storageModules.${config.storage}.testScript or ""}
server.wait_for_unit('atticd.service')
client.wait_until_succeeds("curl -sL http://server:8080", timeout=10)
root_token = server.succeed("${cmd.atticadm} make-token --sub 'e2e-root' --validity '1 month' --push '*' --pull '*' --delete '*' --create-cache '*' --destroy-cache '*' --configure-cache '*' --configure-cache-retention '*'")
readonly_token = server.succeed("${cmd.atticadm} make-token --sub 'e2e-root' --validity '1 month' --pull 'test'")
client.succeed(f"attic login --set-default root http://server:8080 {root_token}")
client.succeed(f"attic login readonly http://server:8080 {readonly_token}")
client.succeed("attic login anon http://server:8080")
# TODO: Make sure the correct status codes are returned
# (i.e., 500s shouldn't pass the "should fail" tests)
with subtest("Check that we can create a cache"):
client.succeed("attic cache create test")
with subtest("Check that we can push a path"):
client.succeed("cat ${testDrv} >test.nix && chmod +x test.nix")
test_file = client.succeed("nix-build --no-out-link test.nix")
test_file_hash = test_file.removeprefix("/nix/store/")[:32]
client.succeed(f"attic push test {test_file}")
client.succeed(f"nix-store --delete {test_file}")
client.fail(f"grep hello {test_file}")
with subtest("Check that we can pull a path"):
client.succeed("attic use readonly:test")
client.succeed(f"nix-store -r {test_file}")
client.succeed(f"grep hello {test_file}")
with subtest("Check that we cannot push without required permissions"):
client.fail(f"attic push readonly:test {test_file}")
client.fail(f"attic push anon:test {test_file} 2>&1")
with subtest("Check that we can make the cache public"):
client.fail("curl -sL --fail-with-body http://server:8080/test/nix-cache-info")
client.fail(f"curl -sL --fail-with-body http://server:8080/test/{test_file_hash}.narinfo")
client.succeed("attic cache configure test --public")
client.succeed("curl -sL --fail-with-body http://server:8080/test/nix-cache-info")
client.succeed(f"curl -sL --fail-with-body http://server:8080/test/{test_file_hash}.narinfo")
with subtest("Check that we can trigger garbage collection"):
test_file_hash = test_file.removeprefix("/nix/store/")[:32]
client.succeed(f"curl -sL --fail-with-body http://server:8080/test/{test_file_hash}.narinfo")
client.succeed("attic cache configure test --retention-period 1s")
time.sleep(2)
server.succeed("${cmd.atticd} --mode garbage-collector-once")
client.fail(f"curl -sL --fail-with-body http://server:8080/test/{test_file_hash}.narinfo")
with subtest("Check that we can destroy the cache"):
client.succeed("attic cache info test")
client.succeed("attic cache destroy --no-confirm test")
client.fail("attic cache info test")
client.fail("curl -sL --fail-with-body http://server:8080/test/nix-cache-info")
'';
};
}

View file

@ -0,0 +1,38 @@
{ pkgs ? import ./nixpkgs.nix
, flake ? (import ../flake-compat.nix).defaultNix
}:
let
inherit (pkgs) lib;
nixosLib = import (pkgs.path + "/nixos/lib") { };
runTest = module: (nixosLib.evalTest ({ config, ... }: {
imports = [
module
{
hostPkgs = pkgs;
_module.args.flake = flake;
}
];
result = config.test;
})).config.result;
basicTests = let
matrix = {
database = [ "sqlite" "postgres" ];
storage = [ "local" "minio" ];
};
in builtins.listToAttrs (map (e: {
name = "basic-${e.database}-${e.storage}";
value = runTest {
imports = [
./basic
{
inherit (e) database storage;
}
];
};
}) (lib.cartesianProductOfSets matrix));
in {
} // basicTests

View file

@ -0,0 +1,7 @@
let
flake = (import ../flake-compat.nix).defaultNix;
in import flake.inputs.nixpkgs.outPath {
overlays = [
flake.overlays.default
];
}