Scripts to (interactively) demonstrate capabilities of Nix. Mirror of https://gitlab.com/SFrijters/nix-container-demo
{
  description = "Example for running a VM network test";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs";

  outputs = { self, nixpkgs }:
    let
      # Single source of truth for all tutorial constants
      database      = "postgres";
      schema        = "api";
      table         = "todos";
      username      = "authenticator";
      groupname     = "authenticator";
      password      = "mysecretpassword";
      webRole       = "web_anon";
      postgrestPort = 3000;

      # NixOS module shared between server and client
      sharedModule = {
        # Since it's common for CI not to have $DISPLAY available,
        # we have to explicitly tell the tests "please don't expect any screen available"
        virtualisation.graphics = false;
      };

      # NixOS tests only support Linux for now:
      pkgs = import nixpkgs { system = "x86_64-linux"; };

      vm-test = pkgs.nixosTest ({
        # Name of the test
        name = "vm-test";
        nodes = {
          server = { config, pkgs, ... }: {
            imports = [ sharedModule ];

              networking.firewall.allowedTCPPorts = [ postgrestPort ];

              services.postgresql = {
                enable = true;

                initialScript = pkgs.writeText "initialScript.sql" ''
                  create schema ${schema};

                  create table ${schema}.${table} (
                      id serial primary key,
                      done boolean not null default false,
                      task text not null,
                      due timestamptz
                  );

                  insert into ${schema}.${table} (task) values ('finish tutorial 0'), ('pat self on back');

                  create role ${webRole} nologin;
                  grant usage on schema ${schema} to ${webRole};
                  grant select on ${schema}.${table} to ${webRole};

                  create role ${username} inherit login password '${password}';
                  grant ${webRole} to ${username};
                '';
              };

              users = {
                mutableUsers = false;
                users = {
                  # For ease of debugging the VM as the `root` user
                  root.password = "";

                  # Create a system user that matches the database user so that we
                  # can use peer authentication.  The tutorial defines a password,
                  # but it's not necessary.
                  "${username}" = {
                    isSystemUser = true;
                    group = groupname;
                  };
                };
                groups."${groupname}" = {};
              };

              systemd.services.postgrest = {
                wantedBy = [ "multi-user.target" ];
                after = [ "postgresql.service" ];
                script =
                  let
                    configuration = pkgs.writeText "tutorial.conf" ''
                        db-uri = "postgres://${username}:${password}@localhost:${toString config.services.postgresql.port}/${database}"
                        db-schema = "${schema}"
                        db-anon-role = "${username}"
                    '';
                  in "${pkgs.haskellPackages.postgrest}/bin/postgrest ${configuration}";
                serviceConfig.User = username;
              };
            };

            client = {
              imports = [ sharedModule ];
            };
          };

          # Disable linting for simpler debugging of the testScript
          # skipLint = true;

          testScript = ''
            import json

            start_all()

            server.wait_for_open_port(${toString postgrestPort})

            expected = [
                {"id": 1, "done": False, "task": "finish tutorial 0", "due": None},
                {"id": 2, "done": False, "task": "pat self on back", "due": None},
            ]

            actual = json.loads(
                client.succeed(
                    "${pkgs.curl}/bin/curl http://server:${toString postgrestPort}/${table}"
                )
            )

            assert expected == actual, "table query returns expected content"
          '';
        });
      in
        {
          checks.x86_64-linux.default = vm-test;
          packages.x86_64-linux.default = vm-test;
        };
}