integration-tests: init
This commit is contained in:
parent
330f4e4ac7
commit
979108869d
|
@ -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);
|
||||||
|
|
13
flake.nix
13
flake.nix
|
@ -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
|
||||||
|
|
3
integration-tests/README.md
Normal file
3
integration-tests/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# End-to-End Tests
|
||||||
|
|
||||||
|
This directory contains some end-to-end tests for Attic.
|
204
integration-tests/basic/default.nix
Normal file
204
integration-tests/basic/default.nix
Normal 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")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
38
integration-tests/default.nix
Normal file
38
integration-tests/default.nix
Normal 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
|
7
integration-tests/nixpkgs.nix
Normal file
7
integration-tests/nixpkgs.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
let
|
||||||
|
flake = (import ../flake-compat.nix).defaultNix;
|
||||||
|
in import flake.inputs.nixpkgs.outPath {
|
||||||
|
overlays = [
|
||||||
|
flake.overlays.default
|
||||||
|
];
|
||||||
|
}
|
Loading…
Reference in a new issue