Skip to content

Commit

Permalink
Add more nixos module features and improve tests
Browse files Browse the repository at this point in the history
Ramblurr committed Oct 31, 2024

Verified

This commit was signed with the committer’s verified signature.
dwilkie David Wilkie
1 parent e95b876 commit 8951eb6
Showing 11 changed files with 537 additions and 70 deletions.
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -7,12 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [UNRELEASED]

## v0.2.0 (2024-10-30)

### Breaking

- `transactor` bin renamed to `datomic-transactor`
- `console` bin renamed to `datomic-console`
- nix pkg: `transactor` bin renamed to `datomic-transactor`
- nix pkg: `console` bin renamed to `datomic-console`
- nixos module: removed the default settings that leaned towards dev/h2 storage by default

### Added

@@ -22,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `unstable` container image tag that follows the `main` branch
- nix pkg: Added ability to override the build and add extra native libs or java libs
- nix pkg: Exposed more packages: `datomic-shell`, `datomic-run`, `datomic-repl`, `datomic-peer-server`
- nixos module: You can now configure: logging, extra classpath entries, and extra java options.

### Changed

26 changes: 19 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
DOCKER ?= docker

check:
nix flake check
test: check
nix --print-build-logs flake check

test/nixos:
nix --print-build-logs run '.#checks.x86_64-linux.moduleTest.driver'
test/container:
nix --print-build-logs run '.#checks.x86_64-linux.containerImageTest.driver'

test: test/nixos test/container

datomic-pro:
nix build .#datomic-pro -o result --show-trace

test-pkg: datomic-pro
./result/bin/datomic-transactor testsql.properties
#./result/bin/datomic-transactor ./result/share/datomic-pro/config/samples/dev-transactor-template.properties
test/pkg-dev: datomic-pro
mkdir -p data
./result/bin/datomic-transactor tests/fixtures/testdev.properties

test/pkg-sql: datomic-pro
mkdir -p data
./result/bin/datomic-transactor tests/fixtures/testsql.properties

test/pkg-console-dev: datomic-pro
./result/bin/datomic-console -p 8080 app 'datomic:dev://localhost:4334/?password=datpass'

test-pkg-console: datomic-pro
./result/bin/datomic-console -p 8080 app datomic:dev://localhost:4334/
test/pkg-console-sql: datomic-pro
./result/bin/datomic-console -p 8080 app 'datomic:sql://?jdbc:sqlite:data/db-sqlite.db'

datomic-pro-container:
nix build .#datomic-pro-container -o datomic-pro-container --show-trace
106 changes: 104 additions & 2 deletions nixos-modules/datomic-console.nix
Original file line number Diff line number Diff line change
@@ -7,11 +7,16 @@

let
cfg = config.services.datomic-console;
logbackConfigFile = pkgs.writeText "logback.xml" cfg.logbackConfig;
extraJavaOptions =
cfg.extraJavaOptions
++ lib.optional (cfg.logbackConfig != "") "-Dlogback.configurationFile=${logbackConfigFile}";
extraClasspath = lib.concatStringsSep ":" cfg.extraClasspathEntries;
in
{
options = {
services.datomic-console = {
enable = lib.mkEnableOption "Datomic Pro Console";
enable = lib.mkEnableOption "Datomic Console";
package = lib.mkPackageOption pkgs "datomic-pro" { };
javaPackage = lib.mkPackageOption pkgs "jdk21_headless" { };
port = lib.mkOption {
@@ -37,6 +42,96 @@ in
default = "datomic-console";
description = "The name of the directory under /var/lib that will be used as the state directory for datomic.";
};

extraJavaOptions = lib.mkOption {
description = "Extra command line options for Java.";
default = [ ];
type = lib.types.listOf lib.types.str;
example = [
"-Dfoo=bar"
"-Xbaz=bar"
];
};
extraClasspathEntries = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Extra entries added to the Java classpath when running Datomic Console
'';
example = [
"/path/to/my.jer"
"/path/to/folder/of/jars/*"
];
};
logbackConfig = lib.mkOption {
type = lib.types.lines;
default = ''
<configuration>
<!-- prevent per-message overhead for jul logging calls, e.g. Hornet -->
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-10contextName %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="datomic.cast2slf4j" level="DEBUG"/>
<!-- uncomment to log storage access -->
<!-- <logger name="datomic.kv-cluster" level="DEBUG"/> -->
<!-- uncomment to log transactor heartbeat -->
<!-- <logger name="datomic.lifecycle" level="DEBUG"/> -->
<!-- uncomment to log transactions (transactor side) -->
<!-- <logger name="datomic.transaction" level="DEBUG"/> -->
<!-- uncomment to log transactions (peer side) -->
<!-- <logger name="datomic.peer" level="DEBUG"/> -->
<!-- uncomment to log the transactor log -->
<!-- <logger name="datomic.log" level="DEBUG"/> -->
<!-- uncomment to log peer connection to transactor -->
<!-- <logger name="datomic.connector" level="DEBUG"/> -->
<!-- uncomment to log storage gc -->
<!-- <logger name="datomic.garbage" level="DEBUG"/> -->
<!-- uncomment to log indexing jobs -->
<!-- <logger name="datomic.index" level="DEBUG"/> -->
<!-- these namespsaces create a ton of log noise -->
<logger name="org.apache.activemq.audit" level="WARN"/>
<logger name="httpclient" level="INFO"/>
<logger name="org.apache.commons.httpclient" level="INFO"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="org.jets3t" level="INFO"/>
<logger name="com.amazonaws" level="INFO"/>
<logger name="com.amazonaws.request" level="WARN"/>
<logger name="sun.rmi" level="INFO"/>
<logger name="datomic.spy.memcached" level="INFO"/>
<logger name="com.couchbase.client" level="INFO"/>
<logger name="com.ning.http.client.providers.netty" level="INFO"/>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="org.hornetq.core.client.impl" level="INFO"/>
<logger name="org.apache.tomcat.jdbc.pool" level="INFO"/>
<logger name="datomic.cast2slf4j" level="DEBUG"/>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
'';
description = ''
XML logback configuration for the datomic-pro transactor.
'';
};

};
};
config = lib.mkIf cfg.enable {
@@ -50,13 +145,20 @@ in
}
];
systemd.services.datomic-console = {
description = "Datomic Pro Console";
description = "Datomic Console";
wantedBy = [ "multi-user.target" ];
script = ''
db_uri="$(<"$CREDENTIALS_DIRECTORY/datomic-console-db-uri")"
${cfg.package}/bin/datomic-console -p ${toString cfg.port} "${cfg.alias}" "$db_uri"
'';
path = [ cfg.javaPackage ];
environment =
{
DATOMIC_JAVA_OPTS = toString extraJavaOptions;
}
// lib.optionalAttrs (cfg.extraClasspathEntries != [ ]) {
CLASSPATH = extraClasspath;
};
serviceConfig = {
Type = "simple";
LoadCredential = [ "datomic-console-db-uri:${cfg.dbUriFile}" ];
141 changes: 118 additions & 23 deletions nixos-modules/datomic-pro.nix
Original file line number Diff line number Diff line change
@@ -10,25 +10,23 @@ let
settingsFormat = pkgs.formats.javaProperties { };
stateDir = "/var/lib/${cfg.stateDirectoryName}";
runtimePropertiesPath = "${stateDir}/transactor.properties";
# default settings that will be used unless overriden by the user
settingsDefault = {
host = "localhost";
memory-index-max = "256m";
memory-index-threshold = "32m";
object-cache-max = "128m";
host = "127.0.0.1";
port = 4334;
protocol = "dev";
data-dir = "${stateDir}/data";
log-dir = "${stateDir}/log";
};
propertiesFile = settingsFormat.generate "transactor.properties" (settingsDefault // cfg.settings);
logbackConfigFile = pkgs.writeText "logback.xml" cfg.logbackConfig;
extraJavaOptions =
cfg.extraJavaOptions
++ lib.optional (cfg.logbackConfig != "") "-Dlogback.configurationFile=${logbackConfigFile}";
extraClasspath = lib.concatStringsSep ":" cfg.extraClasspathEntries;
in
{
options = {
services.datomic-pro = {
enable = lib.mkEnableOption "Datomic Pro";
package = lib.mkPackageOption pkgs "datomic-pro" { };
javaPackage = lib.mkPackageOption pkgs "jdk21_headless" { };
secretsFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
@@ -38,6 +36,94 @@ in
Should be owned by root and have 0600 permissions.
'';
};
extraJavaOptions = lib.mkOption {
description = "Extra command line options for Java.";
default = [ ];
type = lib.types.listOf lib.types.str;
example = [
"-Dfoo=bar"
"-Xbaz=bar"
];
};
extraClasspathEntries = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Extra entries added to the Java classpath when running Datomic Pro.
'';
example = [
"/path/to/my.jer"
"/path/to/folder/of/jars/*"
];
};
logbackConfig = lib.mkOption {
type = lib.types.lines;
default = ''
<configuration>
<!-- prevent per-message overhead for jul logging calls, e.g. Hornet -->
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-10contextName %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="datomic.cast2slf4j" level="DEBUG"/>
<!-- uncomment to log storage access -->
<!-- <logger name="datomic.kv-cluster" level="DEBUG"/> -->
<!-- uncomment to log transactor heartbeat -->
<!-- <logger name="datomic.lifecycle" level="DEBUG"/> -->
<!-- uncomment to log transactions (transactor side) -->
<!-- <logger name="datomic.transaction" level="DEBUG"/> -->
<!-- uncomment to log transactions (peer side) -->
<!-- <logger name="datomic.peer" level="DEBUG"/> -->
<!-- uncomment to log the transactor log -->
<!-- <logger name="datomic.log" level="DEBUG"/> -->
<!-- uncomment to log peer connection to transactor -->
<!-- <logger name="datomic.connector" level="DEBUG"/> -->
<!-- uncomment to log storage gc -->
<!-- <logger name="datomic.garbage" level="DEBUG"/> -->
<!-- uncomment to log indexing jobs -->
<!-- <logger name="datomic.index" level="DEBUG"/> -->
<!-- these namespsaces create a ton of log noise -->
<logger name="org.apache.activemq.audit" level="WARN"/>
<logger name="httpclient" level="INFO"/>
<logger name="org.apache.commons.httpclient" level="INFO"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="org.jets3t" level="INFO"/>
<logger name="com.amazonaws" level="INFO"/>
<logger name="com.amazonaws.request" level="WARN"/>
<logger name="sun.rmi" level="INFO"/>
<logger name="datomic.spy.memcached" level="INFO"/>
<logger name="com.couchbase.client" level="INFO"/>
<logger name="com.ning.http.client.providers.netty" level="INFO"/>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="org.hornetq.core.client.impl" level="INFO"/>
<logger name="org.apache.tomcat.jdbc.pool" level="INFO"/>
<logger name="datomic.cast2slf4j" level="DEBUG"/>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
'';
description = ''
XML logback configuration for the datomic-pro transactor.
'';
};

stateDirectoryName = lib.mkOption {
type = lib.types.str;
@@ -47,16 +133,7 @@ in

settings = lib.mkOption {
type = lib.types.submodule { freeformType = settingsFormat.type; };
default = {
host = "localhost";
memory-index-max = "256m";
memory-index-threshold = "32m";
object-cache-max = "128m";
port = 4334;
protocol = "dev";
data-dir = "${stateDir}/data";
log-dir = "${stateDir}/log";
};
default = settingsDefault;
description = ''
Configuration written to `transactor.properties`.
@@ -70,17 +147,31 @@ in
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = lib.attrsets.hasAttr "protocol" cfg.settings;
message = ''
You must define your storage procotol with the `protocol` key in <option>services.datomic-pro.settings</option> , refer to the Datomic Pro documentation.
Some possible values are `"dev"`, `"sql"`, etc. Each protocol will have additional required settings that are not validated by this NixOS module.
'';
}
{
assertion = lib.strings.hasInfix "/" cfg.stateDirectoryName == false;
message = ''
<option>services.datomic-pro.stateDirectoryName> must be a single directory name, not a path with /.
<option>services.datomic-pro.stateDirectoryName</option> must be a single directory name, not a path with /.
'';
}

{
assertion = !(lib.attrsets.hasAttr "log-dir" cfg.settings);
message = ''<option>services.datomic-pro.settings</option> must not contain the `log-dir` key, use <option>services.datomic-pro.logbackConfig</option> instead.'';
# Ok intrepid spelunker, why can we not use log-dir? Because as of 2024-10, the log-dir is specially handled by datomic code and hardcodes a lookup for
# logback.xml in the `bin/` dir of the datomic tarball. This obviously doesn't work on NixOS.
# The solution is to NOT define log-dir, but instead just define your own logback configuration, we include a variation of the default that logs to stdout and ends up in systemd's journal.
}
];
systemd.services.datomic-pro = {
description = "Datomic Pro";
wantedBy = [ "multi-user.target" ];
path = [ cfg.javaPackage ];
preStart = ''
cat ${propertiesFile} > ${runtimePropertiesPath}
chmod 0600 ${runtimePropertiesPath}
@@ -92,9 +183,13 @@ in
script = ''
${cfg.package}/bin/datomic-transactor ${runtimePropertiesPath}
'';
environment = {
DATOMIC_JAVA_OPTS = "-Dlogback.configurationFile ${cfg.package}/share/datomic-pro/logback-sample.xml";
};
environment =
{
DATOMIC_JAVA_OPTS = toString extraJavaOptions;
}
// lib.optionalAttrs (cfg.extraClasspathEntries != [ ]) {
CLASSPATH = extraClasspath;
};
serviceConfig = {
Type = "simple";
DynamicUser = true;
4 changes: 4 additions & 0 deletions pkgs/datomic-pro-container-image.nix
Original file line number Diff line number Diff line change
@@ -66,6 +66,10 @@ let
env-shim = runCommand "env-shim" { } ''
mkdir -p $out/usr/bin
ln -s ${coreutils}/bin/env $out/usr/bin/env
# conveniently symlink these in place so an admin can access them with podman run -it
for cmd in transactor console shell run repl; do
ln -s ${datomicBuild}/bin/datomic-$cmd $out/usr/bin/datomic-$cmd
done
'';
in
dockerTools.buildLayeredImage {
128 changes: 104 additions & 24 deletions tests/container-image.nix
Original file line number Diff line number Diff line change
@@ -5,46 +5,126 @@
nixpkgs,
}:

with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system pkgs; };
with pkgs.lib;

let
inherit
(import (nixpkgs + "/nixos/lib/testing-python.nix") {
inherit system pkgs;
})
makeTest
;
in
makeTest {
name = "datomic-pro dev-mode container test";
nodes = {
docker =
{ ... }:
{ pkgs, lib, ... }:
{
nixpkgs.overlays = [ self.overlays."${system}" ];
virtualisation = {
diskSize = 8192;
memorySize = 2048;
docker.enable = true;
};
environment.systemPackages = with pkgs; [ jq ];
environment.systemPackages = [
pkgs.jq
pkgs.clojure
pkgs.datomic-pro
pkgs.bash
pkgs.vim
];
environment.etc."datomic-docker/logback.xml".text = ''
<configuration>
<!-- prevent per-message overhead for jul logging calls, e.g. Hornet -->
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-10contextName %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="datomic.cast2slf4j" level="DEBUG"/>
<!-- uncomment to log storage access -->
<!-- <logger name="datomic.kv-cluster" level="DEBUG"/> -->
<!-- uncomment to log transactor heartbeat -->
<!-- <logger name="datomic.lifecycle" level="DEBUG"/> -->
<!-- uncomment to log transactions (transactor side) -->
<!-- <logger name="datomic.transaction" level="DEBUG"/> -->
<!-- uncomment to log transactions (peer side) -->
<!-- <logger name="datomic.peer" level="DEBUG"/> -->
<!-- uncomment to log the transactor log -->
<!-- <logger name="datomic.log" level="DEBUG"/> -->
<!-- uncomment to log peer connection to transactor -->
<!-- <logger name="datomic.connector" level="DEBUG"/> -->
<!-- uncomment to log storage gc -->
<!-- <logger name="datomic.garbage" level="DEBUG"/> -->
<!-- uncomment to log indexing jobs -->
<!-- <logger name="datomic.index" level="DEBUG"/> -->
<!-- these namespsaces create a ton of log noise -->
<logger name="org.apache.activemq.audit" level="WARN"/>
<logger name="httpclient" level="INFO"/>
<logger name="org.apache.commons.httpclient" level="INFO"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="org.jets3t" level="INFO"/>
<logger name="com.amazonaws" level="INFO"/>
<logger name="com.amazonaws.request" level="WARN"/>
<logger name="sun.rmi" level="INFO"/>
<logger name="datomic.spy.memcached" level="INFO"/>
<logger name="com.couchbase.client" level="INFO"/>
<logger name="com.ning.http.client.providers.netty" level="INFO"/>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="org.hornetq.core.client.impl" level="INFO"/>
<logger name="org.apache.tomcat.jdbc.pool" level="INFO"/>
<logger name="datomic.cast2slf4j" level="DEBUG"/>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
'';
environment.etc."datomic-docker/docker-compose.yml".text = builtins.readFile ./fixtures/docker-compose-sqlite.yml;

environment.etc."datomic-docker/deps.edn".text = ''
{:paths ["."]
:deps {com.datomic/peer {:local/root "${pkgs.datomic-pro}/share/datomic-pro/peer-${pkgs.datomic-pro.version}.jar"}
org.xerial/sqlite-jdbc {:local/root "${pkgs.sqlite-jdbc}/share/java/sqlite-jdbc-${pkgs.sqlite-jdbc.version}.jar"}}
:aliases {:run {:jvm-opts ["-Ddatomic.uri=datomic:sql://app?jdbc:sqlite:/var/lib/datomic-docker/data/datomic-sqlite.db"]
:main-opts ["-m" "hello"]}}}
'';
environment.etc."datomic-docker/hello.clj".text = builtins.readFile ./fixtures/hello.clj;
environment.etc."datomic-docker/.env".text = "IMAGE=ghcr.io/ramblurr/datomic-pro:${pkgs.datomic-pro.version}";
};
};

testScript = ''
start_all()
docker.wait_for_unit("sockets.target")
docker.succeed(
"docker load --input='${pkgs.datomic-pro-container}'"
)
docker.succeed("rm -rf ./data && mkdir ./data")
docker.succeed(
"""
docker run -d --name datomic -v ./data:/data -p 4335:4334 -e DATOMIC_STORAGE_ADMIN_PASSWORD=unsafe -e DATOMIC_STORAGE_DATOMIC_PASSWORD=unsafe ghcr.io/ramblurr/datomic-pro:${pkgs.datomic-pro.version}
"""
)
docker.wait_for_open_port(4335)
def try_logs(_) -> bool:
status, _ = docker.execute("docker logs datomic | grep -q 'System started'")
return status == 0
with docker.nested("waiting for datomic to start"):
retry(try_logs)
docker.wait_for_file("./data/db/datomic.trace.db")
docker.succeed("docker rm -f datomic")
docker.wait_for_closed_port(4335)
docker.succeed("mkdir -p /var/lib/datomic-docker/data")
docker.succeed("mkdir -p /var/lib/datomic-docker/config")
docker.succeed("docker load --input='${pkgs.datomic-pro-container}'")
docker.succeed("cd /etc/datomic-docker && docker compose up -d")
docker.wait_for_file("/var/lib/datomic-docker/data/datomic-sqlite.db")
docker.wait_for_open_port(4334)
docker.wait_until_succeeds("cd /etc/datomic-docker && docker compose logs datomic-transactor | grep -q 'System started'")
docker.wait_for_open_port(8081)
# Note: running the clojure test requires internet, because maven deps will be downloaded
# unfortunately the datomic distribution does not include all deps for the peer lib.
machine.succeed("cd /etc/datomic-docker && clojure -M:run")
'';
}
60 changes: 60 additions & 0 deletions tests/fixtures/docker-compose-sqlite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
services:
datomic-transactor:
image: ${IMAGE}
environment:
DATOMIC_PROTOCOL: sql
DATOMIC_SQL_URL: jdbc:sqlite:/data/datomic-sqlite.db
DATOMIC_SQL_DRIVER_CLASS: org.sqlite.JDBC
DATOMIC_JAVA_OPTS: -Dlogback.configurationFile=/logback.xml
# this one is for the other containers
DATOMIC_HOST: datomic-transactor
# this one is for the host machine
DATOMIC_ALT_HOST: "127.0.0.1"
# shrink ram requirements for test environment
DATOMIC_MEMORY_INDEX_MAX: 32m
DATOMIC_OBJECT_CACHE_MAX: 32m
DATOMIC_MEMORY_INDEX_THRESHOLD: 32m
volumes:
- "/var/lib/datomic-docker/data:/data:z"
- "/var/lib/datomic-docker/config:/config:z"
- "/etc/datomic-docker/logback.xml:/logback.xml:ro"
ports:
- 127.0.0.1:4334:4334
depends_on:
datomic-storage-migrator:
condition: service_completed_successfully

datomic-console:
image: ${IMAGE}
command: console
environment:
# you don’t specify the db name in the uri (because console can access all dbs)
DB_URI: "datomic:sql://?jdbc:sqlite:/data/datomic-sqlite.db"
DATOMIC_JAVA_OPTS: -Dlogback.configurationFile=/logback.xml
volumes:
- "/var/lib/datomic-docker/data:/data:z"
- "/etc/datomic-docker/logback.xml:/logback.xml:ro"
ports:
- 127.0.0.1:8081:8080
depends_on:
datomic-storage-migrator:
condition: service_completed_successfully

datomic-storage-migrator:
image: ${IMAGE}
volumes:
- "/var/lib/datomic-docker/data:/data:z"
entrypoint: /bin/sh
command: |
-c '
echo "Creating SQLite database and schema..."
sqlite3 /data/datomic-sqlite.db "
CREATE TABLE IF NOT EXISTS datomic_kvs (
id TEXT NOT NULL PRIMARY KEY,
rev INTEGER,
map TEXT,
val BLOB
);"
echo "Database initialization complete."
'
47 changes: 47 additions & 0 deletions tests/fixtures/hello.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
(ns hello
(:require [datomic.api :as d]))

(def db-uri (let [uri (System/getProperty "datomic.uri")]
(assert uri "datomic.uri property is nil!")
uri))

(def schema
[{:db/ident :hello/message
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/doc "A hello world message"}

{:db/ident :hello/timestamp
:db/valueType :db.type/instant
:db/cardinality :db.cardinality/one
:db/doc "When the message was created"}])

(defn create-database [ts]
(d/create-database db-uri)
(let [conn (d/connect db-uri)]
@(d/transact conn schema)
@(d/transact
conn
[{:hello/message "Hello, Datomic!"
:hello/timestamp ts}])
conn))

(defn -main []
(println "Creating database and schema...")
(try
(let [ts (java.util.Date.)
conn (create-database ts)
db (d/db conn)
results (d/q '[:find ?m ?t
:where
[?e :hello/message ?m]
[?e :hello/timestamp ?t]]
db)]
(println "Query results:")
(doseq [[message timestamp] results]
(assert (= timestamp ts))
(println message "at" timestamp))
(println "Database setup complete!"))
(finally
(d/shutdown true))))

10 changes: 10 additions & 0 deletions tests/fixtures/testdev.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
data-dir = ./data
host = 127.0.0.1
memory-index-max = 64m
memory-index-threshold = 16m
object-cache-max = 64m
port = 4334
protocol = dev
storage-access = remote
storage-admin-password=adminpass
storage-datomic-password=datpass
9 changes: 9 additions & 0 deletions tests/fixtures/testsql.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data-dir=./data
host=0.0.0.0
memory-index-max=256m
memory-index-threshold=32m
object-cache-max=128m
port=4334
protocol=sql
sql-driver-class=org.sqlite.JDBC
sql-url=jdbc:sqlite:data/db-sqlite.db
68 changes: 58 additions & 10 deletions tests/nixos-module.nix
Original file line number Diff line number Diff line change
@@ -5,14 +5,28 @@
nixpkgs,
}:

with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system pkgs; };
with pkgs.lib;

let
inherit
(import (nixpkgs + "/nixos/lib/testing-python.nix") {
inherit system pkgs;
})
makeTest
;
in
makeTest {
name = "datomic-pro module test";
nodes = {
client =
{ ... }:
{
config,
pkgs,
lib,
...
}:
let
package = config.services.datomic-pro.package;
version = config.services.datomic-pro.package.version;
in
{
nixpkgs.overlays = [ self.overlays."${system}" ];
virtualisation.memorySize = 2048;
@@ -23,27 +37,27 @@ makeTest {
environment.etc."datomic-pro/do-not-do-this.properties" = {
text = ''
storage-admin-password=do-not-do-it-this-way-in-prod
storage-datomic-password=do-not-do-it-this-way-in-prod
storage-datomic-password=do-not-do-it-this-way-in-prod-peer
'';
mode = "0600";
};
services.datomic-pro = {
enable = true;
secretsFile = "/etc/datomic-pro/do-not-do-this.properties";
settings = {
enable = true;
host = "localhost";
port = 4334;
memory-index-max = "256m";
memory-index-threshold = "32m";
object-cache-max = "128m";
protocol = "dev";
storage-access = "remote";
# the follow memory tweaks are only for the test env
memory-index-max = "64m";
memory-index-threshold = "16m";
object-cache-max = "64m";
};
};

environment.etc."datomic-console/do-not-do-this" = {
text = "datomic:dev://localhost:4334/?password=do-not-do-it-this-way-in-prod";
text = "datomic:dev://localhost:4334/?password=do-not-do-it-this-way-in-prod-peer";
mode = "0600";
};
services.datomic-console = {
@@ -52,16 +66,50 @@ makeTest {
port = 8080;
dbUriFile = "/etc/datomic-console/do-not-do-this";
};
environment.systemPackages = [
pkgs.clojure
pkgs.vim
pkgs.bash
package
];
users.users.root = {
hashedPassword = lib.mkForce null;
hashedPasswordFile = lib.mkForce null;
initialPassword = lib.mkForce null;
password = lib.mkForce "root";
};
environment.etc."datomic-test/deps.edn" = {
mode = "0600";
text = ''
{:paths ["."]
:deps {com.datomic/peer {:local/root "${package}/share/datomic-pro/peer-${version}.jar"}}
:aliases {:run {:jvm-opts ["-Ddatomic.uri=datomic:dev://localhost:4334/test-db?password=do-not-do-it-this-way-in-prod-peer"]
:main-opts ["-m" "hello"]}}}
'';
};
environment.etc."datomic-test/hello.clj" = {
mode = "0600";
text = builtins.readFile ./fixtures/hello.clj;
};
};
};

testScript = ''
start_all()
machine.wait_for_unit("datomic-pro.service")
machine.wait_for_open_port(4334)
machine.wait_until_succeeds("journalctl -u datomic-pro -o cat | grep -q 'System started'")
# Note: running the clojure test requires internet, because maven deps will be downloaded
# unfortunately the datomic distribution does not include all deps for the peer lib.
machine.succeed("cd /etc/datomic-test && clojure -M:run")
machine.wait_for_unit("datomic-console.service")
machine.wait_for_open_port(8080)
machine.succeed("curl --fail http://localhost:8080/browse")
print(machine.succeed("datomic-run -m datomic.integrity 'datomic:dev://localhost:4334/test-db?password=do-not-do-it-this-way-in-prod-peer'"))
'';
}

0 comments on commit 8951eb6

Please sign in to comment.