]> granicus.if.org Git - ejabberd/commitdiff
Initial Docker environment to run ejabberd test suite
authorMickael Remond <mremond@process-one.net>
Tue, 7 May 2019 15:59:05 +0000 (17:59 +0200)
committerMickael Remond <mremond@process-one.net>
Tue, 7 May 2019 15:59:05 +0000 (17:59 +0200)
test/docker/README.md [new file with mode: 0644]
test/docker/db/mysql/initdb/mysql.sql [new file with mode: 0644]
test/docker/db/postgres/initdb/pg.sql [new file with mode: 0644]
test/docker/db/riak/Dockerfile [new file with mode: 0644]
test/docker/db/riak/advanced.config [new file with mode: 0644]
test/docker/db/riak/ejabberd_riak.beam [new file with mode: 0644]
test/docker/db/riak/prestart.d/00-setup-networking.sh [new file with mode: 0755]
test/docker/db/riak/riak-cluster.sh [new file with mode: 0644]
test/docker/db/riak/riak.conf [new file with mode: 0644]
test/docker/docker-compose.yml [new file with mode: 0644]

diff --git a/test/docker/README.md b/test/docker/README.md
new file mode 100644 (file)
index 0000000..01bdeb8
--- /dev/null
@@ -0,0 +1,26 @@
+# Docker database images to run ejabberd tests
+
+You can start the Docker environment with Docker Compose, from ejabberd repository root.
+
+The following command will launch MySQL, PostgreSQL, Redis and Riak, and keep the console
+attached to it.
+
+```
+mkdir test/docker/db/mysql/data
+mkdir test/docker/db/postgres/data
+mkdir test/docker/db/riak/data
+(cd test/docker; docker-compose up)
+```
+
+You can stop all the databases with CTRL-C.
+
+You can fully clean up the environment with:
+
+```
+(cd test/docker; docker-compose down)
+```
+
+## TODO
+
+- Document how to fully clean the test data.
+
diff --git a/test/docker/db/mysql/initdb/mysql.sql b/test/docker/db/mysql/initdb/mysql.sql
new file mode 100644 (file)
index 0000000..a05f8c8
--- /dev/null
@@ -0,0 +1,465 @@
+--
+-- ejabberd, Copyright (C) 2002-2019   ProcessOne
+--
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of the
+-- License, or (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-- General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along
+-- with this program; if not, write to the Free Software Foundation, Inc.,
+-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+--
+
+CREATE TABLE users (
+    username varchar(191) PRIMARY KEY,
+    password text NOT NULL,
+    serverkey varchar(64) NOT NULL DEFAULT '',
+    salt varchar(64) NOT NULL DEFAULT '',
+    iterationcount integer NOT NULL DEFAULT 0,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+-- Add support for SCRAM auth to a database created before ejabberd 16.03:
+-- ALTER TABLE users ADD COLUMN serverkey varchar(64) NOT NULL DEFAULT '';
+-- ALTER TABLE users ADD COLUMN salt varchar(64) NOT NULL DEFAULT '';
+-- ALTER TABLE users ADD COLUMN iterationcount integer NOT NULL DEFAULT 0;
+
+CREATE TABLE last (
+    username varchar(191) PRIMARY KEY,
+    seconds text NOT NULL,
+    state text NOT NULl
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+
+CREATE TABLE rosterusers (
+    username varchar(191) NOT NULL,
+    jid varchar(191) NOT NULL,
+    nick text NOT NULL,
+    subscription character(1) NOT NULL,
+    ask character(1) NOT NULL,
+    askmessage text NOT NULL,
+    server character(1) NOT NULL,
+    subscribe text NOT NULL,
+    type text,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers(username(75), jid(75));
+CREATE INDEX i_rosteru_username ON rosterusers(username);
+CREATE INDEX i_rosteru_jid ON rosterusers(jid);
+
+CREATE TABLE rostergroups (
+    username varchar(191) NOT NULL,
+    jid varchar(191) NOT NULL,
+    grp text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX pk_rosterg_user_jid ON rostergroups(username(75), jid(75));
+
+CREATE TABLE sr_group (
+    name varchar(191) NOT NULL,
+    opts text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE sr_user (
+    jid varchar(191) NOT NULL,
+    grp varchar(191) NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_sr_user_jid_group ON sr_user(jid(75), grp(75));
+CREATE INDEX i_sr_user_jid ON sr_user(jid);
+CREATE INDEX i_sr_user_grp ON sr_user(grp);
+
+CREATE TABLE spool (
+    username varchar(191) NOT NULL,
+    xml mediumtext NOT NULL,
+    seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_despool USING BTREE ON spool(username);
+CREATE INDEX i_spool_created_at USING BTREE ON spool(created_at);
+
+CREATE TABLE archive (
+    username varchar(191) NOT NULL,
+    timestamp BIGINT UNSIGNED NOT NULL,
+    peer varchar(191) NOT NULL,
+    bare_peer varchar(191) NOT NULL,
+    xml mediumtext NOT NULL,
+    txt mediumtext,
+    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
+    kind varchar(10),
+    nick varchar(191),
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE FULLTEXT INDEX i_text ON archive(txt);
+CREATE INDEX i_username_timestamp USING BTREE ON archive(username(191), timestamp);
+CREATE INDEX i_username_peer USING BTREE ON archive(username(191), peer(191));
+CREATE INDEX i_username_bare_peer USING BTREE ON archive(username(191), bare_peer(191));
+CREATE INDEX i_timestamp USING BTREE ON archive(timestamp);
+
+CREATE TABLE archive_prefs (
+    username varchar(191) NOT NULL PRIMARY KEY,
+    def text NOT NULL,
+    always text NOT NULL,
+    never text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE vcard (
+    username varchar(191) PRIMARY KEY,
+    vcard mediumtext NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE vcard_search (
+    username varchar(191) NOT NULL,
+    lusername varchar(191) PRIMARY KEY,
+    fn text NOT NULL,
+    lfn varchar(191) NOT NULL,
+    family text NOT NULL,
+    lfamily varchar(191) NOT NULL,
+    given text NOT NULL,
+    lgiven varchar(191) NOT NULL,
+    middle text NOT NULL,
+    lmiddle varchar(191) NOT NULL,
+    nickname text NOT NULL,
+    lnickname varchar(191) NOT NULL,
+    bday text NOT NULL,
+    lbday varchar(191) NOT NULL,
+    ctry text NOT NULL,
+    lctry varchar(191) NOT NULL,
+    locality text NOT NULL,
+    llocality varchar(191) NOT NULL,
+    email text NOT NULL,
+    lemail varchar(191) NOT NULL,
+    orgname text NOT NULL,
+    lorgname varchar(191) NOT NULL,
+    orgunit text NOT NULL,
+    lorgunit varchar(191) NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_vcard_search_lfn       ON vcard_search(lfn);
+CREATE INDEX i_vcard_search_lfamily   ON vcard_search(lfamily);
+CREATE INDEX i_vcard_search_lgiven    ON vcard_search(lgiven);
+CREATE INDEX i_vcard_search_lmiddle   ON vcard_search(lmiddle);
+CREATE INDEX i_vcard_search_lnickname ON vcard_search(lnickname);
+CREATE INDEX i_vcard_search_lbday     ON vcard_search(lbday);
+CREATE INDEX i_vcard_search_lctry     ON vcard_search(lctry);
+CREATE INDEX i_vcard_search_llocality ON vcard_search(llocality);
+CREATE INDEX i_vcard_search_lemail    ON vcard_search(lemail);
+CREATE INDEX i_vcard_search_lorgname  ON vcard_search(lorgname);
+CREATE INDEX i_vcard_search_lorgunit  ON vcard_search(lorgunit);
+
+CREATE TABLE privacy_default_list (
+    username varchar(191) PRIMARY KEY,
+    name varchar(191) NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE privacy_list (
+    username varchar(191) NOT NULL,
+    name varchar(191) NOT NULL,
+    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_privacy_list_username  USING BTREE ON privacy_list(username);
+CREATE UNIQUE INDEX i_privacy_list_username_name USING BTREE ON privacy_list (username(75), name(75));
+
+CREATE TABLE privacy_list_data (
+    id bigint,
+    t character(1) NOT NULL,
+    value text NOT NULL,
+    action character(1) NOT NULL,
+    ord NUMERIC NOT NULL,
+    match_all boolean NOT NULL,
+    match_iq boolean NOT NULL,
+    match_message boolean NOT NULL,
+    match_presence_in boolean NOT NULL,
+    match_presence_out boolean NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_privacy_list_data_id ON privacy_list_data(id);
+
+CREATE TABLE private_storage (
+    username varchar(191) NOT NULL,
+    namespace varchar(191) NOT NULL,
+    data text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username);
+CREATE UNIQUE INDEX i_private_storage_username_namespace USING BTREE ON private_storage(username(75), namespace(75));
+
+-- Not tested in mysql
+CREATE TABLE roster_version (
+    username varchar(191) PRIMARY KEY,
+    version text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+-- To update from 1.x:
+-- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask;
+-- UPDATE rosterusers SET askmessage = '';
+-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
+
+CREATE TABLE pubsub_node (
+  host text NOT NULL,
+  node text NOT NULL,
+  parent VARCHAR(191) NOT NULL DEFAULT '',
+  plugin text NOT NULL,
+  nodeid bigint auto_increment primary key
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE INDEX i_pubsub_node_parent ON pubsub_node(parent(120));
+CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node(host(71), node(120));
+
+CREATE TABLE pubsub_node_option (
+  nodeid bigint,
+  name text NOT NULL,
+  val text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option(nodeid);
+ALTER TABLE `pubsub_node_option` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
+
+CREATE TABLE pubsub_node_owner (
+  nodeid bigint,
+  owner text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner(nodeid);
+ALTER TABLE `pubsub_node_owner` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
+
+CREATE TABLE pubsub_state (
+  nodeid bigint,
+  jid text NOT NULL,
+  affiliation character(1),
+  subscriptions VARCHAR(191) NOT NULL DEFAULT '',
+  stateid bigint auto_increment primary key
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE INDEX i_pubsub_state_jid ON pubsub_state(jid(60));
+CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state(nodeid, jid(60));
+ALTER TABLE `pubsub_state` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
+
+CREATE TABLE pubsub_item (
+  nodeid bigint,
+  itemid text NOT NULL,
+  publisher text NOT NULL,
+  creation varchar(32) NOT NULL,
+  modification varchar(32) NOT NULL,
+  payload mediumtext NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE INDEX i_pubsub_item_itemid ON pubsub_item(itemid(36));
+CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item(nodeid, itemid(36));
+ALTER TABLE `pubsub_item` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
+
+CREATE TABLE pubsub_subscription_opt (
+  subid text NOT NULL,
+  opt_name varchar(32),
+  opt_value text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt(subid(32), opt_name(32));
+
+CREATE TABLE muc_room (
+    name text NOT NULL,
+    host text NOT NULL,
+    opts mediumtext NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_muc_room_name_host USING BTREE ON muc_room(name(75), host(75));
+
+CREATE TABLE muc_registered (
+    jid text NOT NULL,
+    host text NOT NULL,
+    nick text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_muc_registered_nick USING BTREE ON muc_registered(nick(75));
+CREATE UNIQUE INDEX i_muc_registered_jid_host USING BTREE ON muc_registered(jid(75), host(75));
+
+CREATE TABLE muc_online_room (
+    name text NOT NULL,
+    host text NOT NULL,
+    node text NOT NULL,
+    pid text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_muc_online_room_name_host USING BTREE ON muc_online_room(name(75), host(75));
+
+CREATE TABLE muc_online_users (
+    username text NOT NULL,
+    server text NOT NULL,
+    resource text NOT NULL,
+    name text NOT NULL,
+    host text NOT NULL,
+    node text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75));
+CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75));
+
+CREATE TABLE muc_room_subscribers (
+   room varchar(191) NOT NULL,
+   host varchar(191) NOT NULL,
+   jid varchar(191) NOT NULL,
+   nick text NOT NULL,
+   nodes text NOT NULL,
+   created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  UNIQUE KEY i_muc_room_subscribers_host_room_jid (host, room, jid)
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_muc_room_subscribers_host_jid USING BTREE ON muc_room_subscribers(host, jid);
+
+CREATE TABLE motd (
+    username varchar(191) PRIMARY KEY,
+    xml text,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE caps_features (
+    node varchar(191) NOT NULL,
+    subnode varchar(191) NOT NULL,
+    feature text,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_caps_features_node_subnode ON caps_features(node(75), subnode(75));
+
+CREATE TABLE sm (
+    usec bigint NOT NULL,
+    pid text NOT NULL,
+    node text NOT NULL,
+    username varchar(191) NOT NULL,
+    resource varchar(191) NOT NULL,
+    priority text NOT NULL,
+    info text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_sid ON sm(usec, pid(75));
+CREATE INDEX i_node ON sm(node(75));
+CREATE INDEX i_username ON sm(username);
+
+CREATE TABLE oauth_token (
+    token varchar(191) NOT NULL PRIMARY KEY,
+    jid text NOT NULL,
+    scope text NOT NULL,
+    expire bigint NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE route (
+    domain text NOT NULL,
+    server_host text NOT NULL,
+    node text NOT NULL,
+    pid text NOT NULL,
+    local_hint text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_route ON route(domain(75), server_host(75), node(75), pid(75));
+CREATE INDEX i_route_domain ON route(domain(75));
+
+CREATE TABLE bosh (
+    sid text NOT NULL,
+    node text NOT NULL,
+    pid text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_bosh_sid ON bosh(sid(75));
+
+CREATE TABLE proxy65 (
+    sid text NOT NULL,
+    pid_t text NOT NULL,
+    pid_i text NOT NULL,
+    node_t text NOT NULL,
+    node_i text NOT NULL,
+    jid_i text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 (sid(191));
+CREATE INDEX i_proxy65_jid ON proxy65 (jid_i(191));
+
+CREATE TABLE push_session (
+    username text NOT NULL,
+    timestamp bigint NOT NULL,
+    service text NOT NULL,
+    node text NOT NULL,
+    xml text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_push_usn ON push_session (username(191), service(191), node(191));
+CREATE UNIQUE INDEX i_push_ut ON push_session (username(191), timestamp);
+
+CREATE TABLE mix_channel (
+    channel text NOT NULL,
+    service text NOT NULL,
+    username text NOT NULL,
+    domain text NOT NULL,
+    jid text NOT NULL,
+    hidden boolean NOT NULL,
+    hmac_key text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_mix_channel ON mix_channel (channel(191), service(191));
+CREATE INDEX i_mix_channel_serv ON mix_channel (service(191));
+
+CREATE TABLE mix_participant (
+    channel text NOT NULL,
+    service text NOT NULL,
+    username text NOT NULL,
+    domain text NOT NULL,
+    jid text NOT NULL,
+    id text NOT NULL,
+    nick text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel(191), service(191), username(191), domain(191));
+CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel(191), service(191));
+
+CREATE TABLE mix_subscription (
+    channel text NOT NULL,
+    service text NOT NULL,
+    username text NOT NULL,
+    domain text NOT NULL,
+    node text NOT NULL,
+    jid text NOT NULL
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel(153), service(153), username(153), domain(153), node(153));
+CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel(191), service(191), username(191), domain(191));
+CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel(191), service(191), node(191));
+CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel(191), service(191));
+
+CREATE TABLE mix_pam (
+    username text NOT NULL,
+    channel text NOT NULL,
+    service text NOT NULL,
+    id text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username(191), channel(191), service(191));
+CREATE INDEX i_mix_pam_u ON mix_pam (username(191));
+
+CREATE TABLE mqtt_pub (
+    username varchar(191) NOT NULL,
+    resource varchar(191) NOT NULL,
+    topic text NOT NULL,
+    qos tinyint NOT NULL,
+    payload blob NOT NULL,
+    payload_format tinyint NOT NULL,
+    content_type text NOT NULL,
+    response_topic text NOT NULL,
+    correlation_data blob NOT NULL,
+    user_properties blob NOT NULL,
+    expiry int unsigned NOT NULL,
+    UNIQUE KEY i_mqtt_topic (topic(191))
+);
diff --git a/test/docker/db/postgres/initdb/pg.sql b/test/docker/db/postgres/initdb/pg.sql
new file mode 100644 (file)
index 0000000..eae98d3
--- /dev/null
@@ -0,0 +1,470 @@
+--
+-- ejabberd, Copyright (C) 2002-2019   ProcessOne
+--
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of the
+-- License, or (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-- General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along
+-- with this program; if not, write to the Free Software Foundation, Inc.,
+-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+--
+
+CREATE TABLE users (
+    username text PRIMARY KEY,
+    "password" text NOT NULL,
+    serverkey text NOT NULL DEFAULT '',
+    salt text NOT NULL DEFAULT '',
+    iterationcount integer NOT NULL DEFAULT 0,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+-- Add support for SCRAM auth to a database created before ejabberd 16.03:
+-- ALTER TABLE users ADD COLUMN serverkey text NOT NULL DEFAULT '';
+-- ALTER TABLE users ADD COLUMN salt text NOT NULL DEFAULT '';
+-- ALTER TABLE users ADD COLUMN iterationcount integer NOT NULL DEFAULT 0;
+
+CREATE TABLE last (
+    username text PRIMARY KEY,
+    seconds text NOT NULL,
+    state text NOT NULL
+);
+
+
+CREATE TABLE rosterusers (
+    username text NOT NULL,
+    jid text NOT NULL,
+    nick text NOT NULL,
+    subscription character(1) NOT NULL,
+    ask character(1) NOT NULL,
+    askmessage text NOT NULL,
+    server character(1) NOT NULL,
+    subscribe text NOT NULL,
+    "type" text,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers USING btree (username, jid);
+CREATE INDEX i_rosteru_username ON rosterusers USING btree (username);
+CREATE INDEX i_rosteru_jid ON rosterusers USING btree (jid);
+
+
+CREATE TABLE rostergroups (
+    username text NOT NULL,
+    jid text NOT NULL,
+    grp text NOT NULL
+);
+
+CREATE INDEX pk_rosterg_user_jid ON rostergroups USING btree (username, jid);
+
+CREATE TABLE sr_group (
+    name text NOT NULL,
+    opts text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE TABLE sr_user (
+    jid text NOT NULL,
+    grp text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE UNIQUE INDEX i_sr_user_jid_grp ON sr_user USING btree (jid, grp);
+CREATE INDEX i_sr_user_jid ON sr_user USING btree (jid);
+CREATE INDEX i_sr_user_grp ON sr_user USING btree (grp);
+
+CREATE TABLE spool (
+    username text NOT NULL,
+    xml text NOT NULL,
+    seq SERIAL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_despool ON spool USING btree (username);
+
+CREATE TABLE archive (
+    username text NOT NULL,
+    timestamp BIGINT NOT NULL,
+    peer text NOT NULL,
+    bare_peer text NOT NULL,
+    xml text NOT NULL,
+    txt text,
+    id SERIAL,
+    kind text,
+    nick text,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_username_timestamp ON archive USING btree (username, timestamp);
+CREATE INDEX i_username_peer ON archive USING btree (username, peer);
+CREATE INDEX i_username_bare_peer ON archive USING btree (username, bare_peer);
+CREATE INDEX i_timestamp ON archive USING btree (timestamp);
+
+CREATE TABLE archive_prefs (
+    username text NOT NULL PRIMARY KEY,
+    def text NOT NULL,
+    always text NOT NULL,
+    never text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE TABLE vcard (
+    username text PRIMARY KEY,
+    vcard text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE TABLE vcard_search (
+    username text NOT NULL,
+    lusername text PRIMARY KEY,
+    fn text NOT NULL,
+    lfn text NOT NULL,
+    family text NOT NULL,
+    lfamily text NOT NULL,
+    given text NOT NULL,
+    lgiven text NOT NULL,
+    middle text NOT NULL,
+    lmiddle text NOT NULL,
+    nickname text NOT NULL,
+    lnickname text NOT NULL,
+    bday text NOT NULL,
+    lbday text NOT NULL,
+    ctry text NOT NULL,
+    lctry text NOT NULL,
+    locality text NOT NULL,
+    llocality text NOT NULL,
+    email text NOT NULL,
+    lemail text NOT NULL,
+    orgname text NOT NULL,
+    lorgname text NOT NULL,
+    orgunit text NOT NULL,
+    lorgunit text NOT NULL
+);
+
+CREATE INDEX i_vcard_search_lfn       ON vcard_search(lfn);
+CREATE INDEX i_vcard_search_lfamily   ON vcard_search(lfamily);
+CREATE INDEX i_vcard_search_lgiven    ON vcard_search(lgiven);
+CREATE INDEX i_vcard_search_lmiddle   ON vcard_search(lmiddle);
+CREATE INDEX i_vcard_search_lnickname ON vcard_search(lnickname);
+CREATE INDEX i_vcard_search_lbday     ON vcard_search(lbday);
+CREATE INDEX i_vcard_search_lctry     ON vcard_search(lctry);
+CREATE INDEX i_vcard_search_llocality ON vcard_search(llocality);
+CREATE INDEX i_vcard_search_lemail    ON vcard_search(lemail);
+CREATE INDEX i_vcard_search_lorgname  ON vcard_search(lorgname);
+CREATE INDEX i_vcard_search_lorgunit  ON vcard_search(lorgunit);
+
+CREATE TABLE privacy_default_list (
+    username text PRIMARY KEY,
+    name text NOT NULL
+);
+
+CREATE TABLE privacy_list (
+    username text NOT NULL,
+    name text NOT NULL,
+    id SERIAL UNIQUE,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_privacy_list_username ON privacy_list USING btree (username);
+CREATE UNIQUE INDEX i_privacy_list_username_name ON privacy_list USING btree (username, name);
+
+CREATE TABLE privacy_list_data (
+    id bigint REFERENCES privacy_list(id) ON DELETE CASCADE,
+    t character(1) NOT NULL,
+    value text NOT NULL,
+    action character(1) NOT NULL,
+    ord NUMERIC NOT NULL,
+    match_all boolean NOT NULL,
+    match_iq boolean NOT NULL,
+    match_message boolean NOT NULL,
+    match_presence_in boolean NOT NULL,
+    match_presence_out boolean NOT NULL
+);
+
+CREATE INDEX i_privacy_list_data_id ON privacy_list_data USING btree (id);
+
+CREATE TABLE private_storage (
+    username text NOT NULL,
+    namespace text NOT NULL,
+    data text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_private_storage_username ON private_storage USING btree (username);
+CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace);
+
+
+CREATE TABLE roster_version (
+    username text PRIMARY KEY,
+    version text NOT NULL
+);
+
+-- To update from 0.9.8:
+-- CREATE SEQUENCE spool_seq_seq;
+-- ALTER TABLE spool ADD COLUMN seq integer;
+-- ALTER TABLE spool ALTER COLUMN seq SET DEFAULT nextval('spool_seq_seq');
+-- UPDATE spool SET seq = DEFAULT;
+-- ALTER TABLE spool ALTER COLUMN seq SET NOT NULL;
+
+-- To update from 1.x:
+-- ALTER TABLE rosterusers ADD COLUMN askmessage text;
+-- UPDATE rosterusers SET askmessage = '';
+-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
+
+CREATE TABLE pubsub_node (
+  host text NOT NULL,
+  node text NOT NULL,
+  parent text NOT NULL DEFAULT '',
+  plugin text NOT NULL,
+  nodeid SERIAL UNIQUE
+);
+CREATE INDEX i_pubsub_node_parent ON pubsub_node USING btree (parent);
+CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node USING btree (host, node);
+
+CREATE TABLE pubsub_node_option (
+  nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+  name text NOT NULL,
+  val text NOT NULL
+);
+CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option USING btree (nodeid);
+
+CREATE TABLE pubsub_node_owner (
+  nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+  owner text NOT NULL
+);
+CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner USING btree (nodeid);
+
+CREATE TABLE pubsub_state (
+  nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+  jid text NOT NULL,
+  affiliation character(1),
+  subscriptions text NOT NULL DEFAULT '',
+  stateid SERIAL UNIQUE
+);
+CREATE INDEX i_pubsub_state_jid ON pubsub_state USING btree (jid);
+CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state USING btree (nodeid, jid);
+
+CREATE TABLE pubsub_item (
+  nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+  itemid text NOT NULL,
+  publisher text NOT NULL,
+  creation varchar(32) NOT NULL,
+  modification varchar(32) NOT NULL,
+  payload text NOT NULL DEFAULT ''
+);
+CREATE INDEX i_pubsub_item_itemid ON pubsub_item USING btree (itemid);
+CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item USING btree (nodeid, itemid);
+
+CREATE TABLE pubsub_subscription_opt (
+  subid text NOT NULL,
+  opt_name varchar(32),
+  opt_value text NOT NULL
+);
+CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt USING btree (subid, opt_name);
+
+CREATE TABLE muc_room (
+    name text NOT NULL,
+    host text NOT NULL,
+    opts text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE UNIQUE INDEX i_muc_room_name_host ON muc_room USING btree (name, host);
+
+CREATE TABLE muc_registered (
+    jid text NOT NULL,
+    host text NOT NULL,
+    nick text NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_muc_registered_nick ON muc_registered USING btree (nick);
+CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered USING btree (jid, host);
+
+CREATE TABLE muc_online_room (
+    name text NOT NULL,
+    host text NOT NULL,
+    node text NOT NULL,
+    pid text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room USING btree (name, host);
+
+CREATE TABLE muc_online_users (
+    username text NOT NULL,
+    server text NOT NULL,
+    resource text NOT NULL,
+    name text NOT NULL,
+    host text NOT NULL,
+    node text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
+CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
+
+CREATE TABLE muc_room_subscribers (
+   room text NOT NULL,
+   host text NOT NULL,
+   jid text NOT NULL,
+   nick text NOT NULL,
+   nodes text NOT NULL,
+   created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
+CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
+
+CREATE TABLE motd (
+    username text PRIMARY KEY,
+    xml text,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE TABLE caps_features (
+    node text NOT NULL,
+    subnode text NOT NULL,
+    feature text,
+    created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_caps_features_node_subnode ON caps_features USING btree (node, subnode);
+
+CREATE TABLE sm (
+    usec bigint NOT NULL,
+    pid text NOT NULL,
+    node text NOT NULL,
+    username text NOT NULL,
+    resource text NOT NULL,
+    priority text NOT NULL,
+    info text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_sm_sid ON sm USING btree (usec, pid);
+CREATE INDEX i_sm_node ON sm USING btree (node);
+CREATE INDEX i_sm_username ON sm USING btree (username);
+
+CREATE TABLE oauth_token (
+    token text NOT NULL,
+    jid text NOT NULL,
+    scope text NOT NULL,
+    expire bigint NOT NULL
+);
+
+CREATE UNIQUE INDEX i_oauth_token_token ON oauth_token USING btree (token);
+
+CREATE TABLE route (
+    domain text NOT NULL,
+    server_host text NOT NULL,
+    node text NOT NULL,
+    pid text NOT NULL,
+    local_hint text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_route ON route USING btree (domain, server_host, node, pid);
+CREATE INDEX i_route_domain ON route USING btree (domain);
+
+CREATE TABLE bosh (
+    sid text NOT NULL,
+    node text NOT NULL,
+    pid text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_bosh_sid ON bosh USING btree (sid);
+
+CREATE TABLE proxy65 (
+    sid text NOT NULL,
+    pid_t text NOT NULL,
+    pid_i text NOT NULL,
+    node_t text NOT NULL,
+    node_i text NOT NULL,
+    jid_i text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 USING btree (sid);
+CREATE INDEX i_proxy65_jid ON proxy65 USING btree (jid_i);
+
+CREATE TABLE push_session (
+    username text NOT NULL,
+    timestamp bigint NOT NULL,
+    service text NOT NULL,
+    node text NOT NULL,
+    xml text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_push_usn ON push_session USING btree (username, service, node);
+CREATE UNIQUE INDEX i_push_ut ON push_session USING btree (username, timestamp);
+
+CREATE TABLE mix_channel (
+    channel text NOT NULL,
+    service text NOT NULL,
+    username text NOT NULL,
+    domain text NOT NULL,
+    jid text NOT NULL,
+    hidden boolean NOT NULL,
+    hmac_key text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX i_mix_channel ON mix_channel (channel, service);
+CREATE INDEX i_mix_channel_serv ON mix_channel (service);
+
+CREATE TABLE mix_participant (
+    channel text NOT NULL,
+    service text NOT NULL,
+    username text NOT NULL,
+    domain text NOT NULL,
+    jid text NOT NULL,
+    id text NOT NULL,
+    nick text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel, service, username, domain);
+CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel, service);
+
+CREATE TABLE mix_subscription (
+    channel text NOT NULL,
+    service text NOT NULL,
+    username text NOT NULL,
+    domain text NOT NULL,
+    node text NOT NULL,
+    jid text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel, service, username, domain, node);
+CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel, service, username, domain);
+CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel, service, node);
+CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel, service);
+
+CREATE TABLE mix_pam (
+    username text NOT NULL,
+    channel text NOT NULL,
+    service text NOT NULL,
+    id text NOT NULL,
+    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username, channel, service);
+CREATE INDEX i_mix_pam_us ON mix_pam (username);
+
+CREATE TABLE mqtt_pub (
+    username text NOT NULL,
+    resource text NOT NULL,
+    topic text NOT NULL,
+    qos smallint NOT NULL,
+    payload bytea NOT NULL,
+    payload_format smallint NOT NULL,
+    content_type text NOT NULL,
+    response_topic text NOT NULL,
+    correlation_data bytea NOT NULL,
+    user_properties bytea NOT NULL,
+    expiry bigint NOT NULL
+);
+
+CREATE UNIQUE INDEX i_mqtt_topic ON mqtt_pub (topic);
diff --git a/test/docker/db/riak/Dockerfile b/test/docker/db/riak/Dockerfile
new file mode 100644 (file)
index 0000000..b0f539d
--- /dev/null
@@ -0,0 +1,53 @@
+# docker build -t ejabberd/riak .
+# docker run --rm -it -p 8087:8087 -p 8098:8098 -v "`pwd`/ebin:/usr/lib/ejabberd/ebin" --name ejabberd-riak ejabberd/riak
+# docker exec -it ejabberd-riak /bin/bash
+# docker push ejabberd/riak:latest
+FROM ubuntu:16.04
+
+ENV DEBIAN_FRONTEND noninteractive
+# ENV RIAK_VERSION 2.0.9-1
+# install riak=${RIAK_VERSION} to fallback to an older version
+
+RUN \
+    apt-get update -qq && \
+    apt-get install -y curl apt-utils iputils-ping && \
+    curl -s https://packagecloud.io/install/repositories/basho/riak/script.deb.sh | bash && \
+    apt-get install -y riak && \
+    apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+
+# Expose default ports
+EXPOSE 8087
+EXPOSE 8098
+
+# Expose volumes for data and logs
+VOLUME /var/log/riak
+VOLUME /var/lib/riak
+
+# Expose volumes for ejabberd code for map/reduce in Riak.
+# It can be overloaded to provide a new ejabberd_riak.beam file.
+# Note that ejabberd_riak.beam needs to be compiled with Erlang/OTP R16
+# as this is the version of Erlang Basho has packaged with Riak.
+COPY ejabberd_riak.beam /usr/lib/ejabberd/ebin/ejabberd_riak.beam
+VOLUME /usr/lib/ejabberd/ebin
+
+# Install custom start script
+COPY riak-cluster.sh /sbin/riak-cluster.sh
+RUN chmod a+x /sbin/riak-cluster.sh
+
+# Change configuration to make it work with ejabberd
+COPY advanced.config /etc/riak/advanced.config
+COPY riak.conf /etc/riak/riak.conf
+
+# Install custom hooks
+COPY prestart.d /etc/riak/prestart.d
+# COPY poststart.d /etc/riak/poststart.d
+
+# Prepare for bootstrapping schemas
+RUN mkdir -p /etc/riak/schemas
+
+# Clean up APT cache
+RUN rm -rf /var/lib/apt/lists/* /tmp/*
+
+WORKDIR /var/lib/riak
+
+CMD ["/sbin/riak-cluster.sh"]
diff --git a/test/docker/db/riak/advanced.config b/test/docker/db/riak/advanced.config
new file mode 100644 (file)
index 0000000..e5d5f87
--- /dev/null
@@ -0,0 +1,27 @@
+%% Config file used to set advanced configuration options
+
+[{lager,
+   [
+      {extra_sinks,
+           [
+            {object_lager_event,
+             [{handlers,
+               [{lager_file_backend,
+                 [{file, "/var/log/riak/object.log"},
+                  {level, info},
+                  {formatter_config, [date, " ", time," [",severity,"] ",message, "\n"]}
+                 ]
+                }]
+              },
+              {async_threshold, 500},
+              {async_threshold_window, 50}]
+            }
+            ]
+      }
+    ]},
+
+ {riak_kv, [
+    %% Other configs
+    {add_paths, ["/usr/lib/ejabberd/ebin"]}
+    ]}
+].
diff --git a/test/docker/db/riak/ejabberd_riak.beam b/test/docker/db/riak/ejabberd_riak.beam
new file mode 100644 (file)
index 0000000..3bebb29
Binary files /dev/null and b/test/docker/db/riak/ejabberd_riak.beam differ
diff --git a/test/docker/db/riak/prestart.d/00-setup-networking.sh b/test/docker/db/riak/prestart.d/00-setup-networking.sh
new file mode 100755 (executable)
index 0000000..07ca617
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Add standard config items
+cat <<END >>$RIAK_CONF
+nodename = riak@$HOST
+distributed_cookie = $CLUSTER_NAME
+listener.protobuf.internal = $HOST:$PB_PORT
+listener.http.internal = $HOST:$HTTP_PORT
+END
diff --git a/test/docker/db/riak/riak-cluster.sh b/test/docker/db/riak/riak-cluster.sh
new file mode 100644 (file)
index 0000000..11f344f
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Cluster start script to bootstrap a Riak cluster.
+#
+set -ex
+
+if [[ -x /usr/sbin/riak ]]; then
+  export RIAK=/usr/sbin/riak
+else
+  export RIAK=$RIAK_HOME/bin/riak
+fi
+export RIAK_CONF=/etc/riak/riak.conf
+export USER_CONF=/etc/riak/user.conf
+export RIAK_ADVANCED_CONF=/etc/riak/advanced.config
+if [[ -x /usr/sbin/riak-admin ]]; then
+  export RIAK_ADMIN=/usr/sbin/riak-admin
+else
+  export RIAK_ADMIN=$RIAK_HOME/bin/riak-admin
+fi
+export SCHEMAS_DIR=/etc/riak/schemas/
+
+# Set ports for PB and HTTP
+export PB_PORT=${PB_PORT:-8087}
+export HTTP_PORT=${HTTP_PORT:-8098}
+
+# Use ping to discover our HOSTNAME because it's easier and more reliable than other methods
+export HOST=$(ping -c1 $HOSTNAME | awk '/^PING/ {print $3}' | sed 's/[()]//g')||'127.0.0.1'
+
+# CLUSTER_NAME is used to name the nodes and is the value used in the distributed cookie
+export CLUSTER_NAME=${CLUSTER_NAME:-riak}
+
+# The COORDINATOR_NODE is the first node in a cluster to which other nodes will eventually join
+export COORDINATOR_NODE=${COORDINATOR_NODE:-$HOSTNAME}
+export COORDINATOR_NODE_HOST=$(ping -c1 $COORDINATOR_NODE | awk '/^PING/ {print $3}' | sed 's/[()]//g')||'127.0.0.1'
+
+# Run all prestart scripts
+PRESTART=$(find /etc/riak/prestart.d -name *.sh -print | sort)
+for s in $PRESTART; do
+  . $s
+done
+
+# Start the node and wait until fully up
+$RIAK start
+$RIAK_ADMIN wait-for-service riak_kv
+
+# Run all poststart scripts
+POSTSTART=$(find /etc/riak/poststart.d -name *.sh -print | sort)
+for s in $POSTSTART; do
+  . $s
+done
+
+# Trap SIGTERM and SIGINT and tail the log file indefinitely
+tail -n 1024 -f /var/log/riak/console.log &
+PID=$!
+trap "$RIAK stop; kill $PID" SIGTERM SIGINT
+wait $PID
diff --git a/test/docker/db/riak/riak.conf b/test/docker/db/riak/riak.conf
new file mode 100644 (file)
index 0000000..3c8c0c0
--- /dev/null
@@ -0,0 +1,682 @@
+## Where to emit the default log messages (typically at 'info'
+## severity):
+## off: disabled
+## file: the file specified by log.console.file
+## console: to standard output (seen when using `riak attach-direct`)
+## both: log.console.file and standard out.
+## 
+## Default: file
+## 
+## Acceptable values:
+##   - one of: off, file, console, both
+log.console = file
+
+## The severity level of the console log, default is 'info'.
+## 
+## Default: info
+## 
+## Acceptable values:
+##   - one of: debug, info, notice, warning, error, critical, alert, emergency, none
+log.console.level = info
+
+## When 'log.console' is set to 'file' or 'both', the file where
+## console messages will be logged.
+## 
+## Default: $(platform_log_dir)/console.log
+## 
+## Acceptable values:
+##   - the path to a file
+log.console.file = $(platform_log_dir)/console.log
+
+## The file where error messages will be logged.
+## 
+## Default: $(platform_log_dir)/error.log
+## 
+## Acceptable values:
+##   - the path to a file
+log.error.file = $(platform_log_dir)/error.log
+
+## When set to 'on', enables log output to syslog.
+## 
+## Default: off
+## 
+## Acceptable values:
+##   - on or off
+log.syslog = off
+
+## Whether to enable the crash log.
+## 
+## Default: on
+## 
+## Acceptable values:
+##   - on or off
+log.crash = on
+
+## If the crash log is enabled, the file where its messages will
+## be written.
+## 
+## Default: $(platform_log_dir)/crash.log
+## 
+## Acceptable values:
+##   - the path to a file
+log.crash.file = $(platform_log_dir)/crash.log
+
+## Maximum size in bytes of individual messages in the crash log
+## 
+## Default: 64KB
+## 
+## Acceptable values:
+##   - a byte size with units, e.g. 10GB
+log.crash.maximum_message_size = 64KB
+
+## Maximum size of the crash log in bytes, before it is rotated
+## 
+## Default: 10MB
+## 
+## Acceptable values:
+##   - a byte size with units, e.g. 10GB
+log.crash.size = 10MB
+
+## The schedule on which to rotate the crash log.  For more
+## information see:
+## https://github.com/basho/lager/blob/master/README.md#internal-log-rotation
+## 
+## Default: $D0
+## 
+## Acceptable values:
+##   - text
+log.crash.rotation = $D0
+
+## The number of rotated crash logs to keep. When set to
+## 'current', only the current open log file is kept.
+## 
+## Default: 5
+## 
+## Acceptable values:
+##   - an integer
+##   - the text "current"
+log.crash.rotation.keep = 5
+
+## Name of the Erlang node
+## 
+## Default: riak@127.0.0.1
+## 
+## Acceptable values:
+##   - text
+## nodename = riak@127.0.0.1
+
+## Cookie for distributed node communication.  All nodes in the
+## same cluster should use the same cookie or they will not be able to
+## communicate.
+## 
+## Default: riak
+## 
+## Acceptable values:
+##   - text
+distributed_cookie = riak
+
+## Sets the number of threads in async thread pool, valid range
+## is 0-1024. If thread support is available, the default is 64.
+## More information at: http://erlang.org/doc/man/erl.html
+## 
+## Default: 64
+## 
+## Acceptable values:
+##   - an integer
+erlang.async_threads = 64
+
+## The number of concurrent ports/sockets
+## Valid range is 1024-134217727
+## 
+## Default: 262144
+## 
+## Acceptable values:
+##   - an integer
+erlang.max_ports = 262144
+
+## Set scheduler forced wakeup interval. All run queues will be
+## scanned each Interval milliseconds. While there are sleeping
+## schedulers in the system, one scheduler will be woken for each
+## non-empty run queue found. An Interval of zero disables this
+## feature, which also is the default.
+## This feature is a workaround for lengthy executing native code, and
+## native code that do not bump reductions properly.
+## More information: http://www.erlang.org/doc/man/erl.html#+sfwi
+## 
+## Default: 500
+## 
+## Acceptable values:
+##   - an integer
+## erlang.schedulers.force_wakeup_interval = 500
+
+## Enable or disable scheduler compaction of load. By default
+## scheduler compaction of load is enabled. When enabled, load
+## balancing will strive for a load distribution which causes as many
+## scheduler threads as possible to be fully loaded (i.e., not run out
+## of work). This is accomplished by migrating load (e.g. runnable
+## processes) into a smaller set of schedulers when schedulers
+## frequently run out of work. When disabled, the frequency with which
+## schedulers run out of work will not be taken into account by the
+## load balancing logic.
+## More information: http://www.erlang.org/doc/man/erl.html#+scl
+## 
+## Default: false
+## 
+## Acceptable values:
+##   - one of: true, false
+## erlang.schedulers.compaction_of_load = false
+
+## Enable or disable scheduler utilization balancing of load. By
+## default scheduler utilization balancing is disabled and instead
+## scheduler compaction of load is enabled which will strive for a
+## load distribution which causes as many scheduler threads as
+## possible to be fully loaded (i.e., not run out of work). When
+## scheduler utilization balancing is enabled the system will instead
+## try to balance scheduler utilization between schedulers. That is,
+## strive for equal scheduler utilization on all schedulers.
+## More information: http://www.erlang.org/doc/man/erl.html#+sub
+## 
+## Acceptable values:
+##   - one of: true, false
+## erlang.schedulers.utilization_balancing = true
+
+## Number of partitions in the cluster (only valid when first
+## creating the cluster). Must be a power of 2, minimum 8 and maximum
+## 1024.
+## 
+## Default: 64
+## 
+## Acceptable values:
+##   - an integer
+## ring_size = 64
+
+## Number of concurrent node-to-node transfers allowed.
+## 
+## Default: 2
+## 
+## Acceptable values:
+##   - an integer
+## transfer_limit = 2
+
+## Default cert location for https can be overridden
+## with the ssl config variable, for example:
+## 
+## Acceptable values:
+##   - the path to a file
+## ssl.certfile = $(platform_etc_dir)/cert.pem
+
+## Default key location for https can be overridden with the ssl
+## config variable, for example:
+## 
+## Acceptable values:
+##   - the path to a file
+## ssl.keyfile = $(platform_etc_dir)/key.pem
+
+## Default signing authority location for https can be overridden
+## with the ssl config variable, for example:
+## 
+## Acceptable values:
+##   - the path to a file
+## ssl.cacertfile = $(platform_etc_dir)/cacertfile.pem
+
+## DTrace support Do not enable 'dtrace' unless your Erlang/OTP
+## runtime is compiled to support DTrace.  DTrace is available in
+## R15B01 (supported by the Erlang/OTP official source package) and in
+## R14B04 via a custom source repository & branch.
+## 
+## Default: off
+## 
+## Acceptable values:
+##   - on or off
+dtrace = off
+
+## Platform-specific installation paths (substituted by rebar)
+## 
+## Default: /usr/sbin
+## 
+## Acceptable values:
+##   - the path to a directory
+platform_bin_dir = /usr/sbin
+
+## 
+## Default: /var/lib/riak
+## 
+## Acceptable values:
+##   - the path to a directory
+platform_data_dir = /var/lib/riak
+
+## 
+## Default: /etc/riak
+## 
+## Acceptable values:
+##   - the path to a directory
+platform_etc_dir = /etc/riak
+
+## 
+## Default: /usr/lib/riak/lib
+## 
+## Acceptable values:
+##   - the path to a directory
+platform_lib_dir = /usr/lib/riak/lib
+
+## 
+## Default: /var/log/riak
+## 
+## Acceptable values:
+##   - the path to a directory
+platform_log_dir = /var/log/riak
+
+## Enable consensus subsystem. Set to 'on' to enable the
+## consensus subsystem used for strongly consistent Riak operations.
+## 
+## Default: off
+## 
+## Acceptable values:
+##   - on or off
+## strong_consistency = on
+
+## listener.http.<name> is an IP address and TCP port that the Riak
+## HTTP interface will bind.
+## 
+## Default: 127.0.0.1:8098
+## 
+## Acceptable values:
+##   - an IP/port pair, e.g. 127.0.0.1:10011
+## listener.http.internal = 127.0.0.1:8098
+
+## listener.protobuf.<name> is an IP address and TCP port that the Riak
+## Protocol Buffers interface will bind.
+## 
+## Default: 127.0.0.1:8087
+## 
+## Acceptable values:
+##   - an IP/port pair, e.g. 127.0.0.1:10011
+## listener.protobuf.internal = 127.0.0.1:8087
+
+## The maximum length to which the queue of pending connections
+## may grow. If set, it must be an integer > 0. If you anticipate a
+## huge number of connections being initialized *simultaneously*, set
+## this number higher.
+## 
+## Default: 128
+## 
+## Acceptable values:
+##   - an integer
+## protobuf.backlog = 128
+
+## listener.https.<name> is an IP address and TCP port that the Riak
+## HTTPS interface will bind.
+## 
+## Acceptable values:
+##   - an IP/port pair, e.g. 127.0.0.1:10011
+## listener.https.internal = 127.0.0.1:8098
+
+## How Riak will repair out-of-sync keys. Some features require
+## this to be set to 'active', including search.
+## * active: out-of-sync keys will be repaired in the background
+## * passive: out-of-sync keys are only repaired on read
+## * active-debug: like active, but outputs verbose debugging
+## information
+## 
+## Default: active
+## 
+## Acceptable values:
+##   - one of: active, passive, active-debug
+anti_entropy = active
+
+## Specifies the storage engine used for Riak's key-value data
+## and secondary indexes (if supported).
+## 
+## Default: bitcask
+## 
+## Acceptable values:
+##   - one of: bitcask, leveldb, memory, multi, prefix_multi
+storage_backend = leveldb
+
+## Simplify prefix_multi configuration for Riak CS. Keep this
+## commented out unless Riak is configured for Riak CS.
+## 
+## Acceptable values:
+##   - an integer
+## cs_version = 20000
+
+## Controls which binary representation of a riak value is stored
+## on disk.
+## * 0: Original erlang:term_to_binary format. Higher space overhead.
+## * 1: New format for more compact storage of small values.
+## 
+## Default: 1
+## 
+## Acceptable values:
+##   - the integer 1
+##   - the integer 0
+object.format = 1
+
+## Reading or writing objects bigger than this size will write a
+## warning in the logs.
+## 
+## Default: 5MB
+## 
+## Acceptable values:
+##   - a byte size with units, e.g. 10GB
+object.size.warning_threshold = 5MB
+
+## Writing an object bigger than this will send a failure to the
+## client.
+## 
+## Default: 50MB
+## 
+## Acceptable values:
+##   - a byte size with units, e.g. 10GB
+object.size.maximum = 50MB
+
+## Writing an object with more than this number of siblings will
+## generate a warning in the logs.
+## 
+## Default: 25
+## 
+## Acceptable values:
+##   - an integer
+object.siblings.warning_threshold = 25
+
+## Writing an object with more than this number of siblings will
+## send a failure to the client.
+## 
+## Default: 100
+## 
+## Acceptable values:
+##   - an integer
+object.siblings.maximum = 100
+
+## Whether to allow list buckets.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.list_buckets = enabled
+
+## Whether to allow streaming list buckets.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.stream_list_buckets = enabled
+
+## Whether to allow list keys.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.list_keys = enabled
+
+## Whether to allow streaming list keys.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.stream_list_keys = enabled
+
+## Whether to allow secondary index queries.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.secondary_index = enabled
+
+## Whether to allow streaming secondary index queries.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.stream_secondary_index = enabled
+
+## Whether to allow term-based map-reduce.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.map_reduce = enabled
+
+## Whether to allow JavaScript map-reduce.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_kv.map_reduce_js = enabled
+
+## A path under which bitcask data files will be stored.
+## 
+## Default: $(platform_data_dir)/bitcask
+## 
+## Acceptable values:
+##   - the path to a directory
+bitcask.data_root = $(platform_data_dir)/bitcask
+
+## Configure how Bitcask writes data to disk.
+## erlang: Erlang's built-in file API
+## nif: Direct calls to the POSIX C API
+## The NIF mode provides higher throughput for certain
+## workloads, but has the potential to negatively impact
+## the Erlang VM, leading to higher worst-case latencies
+## and possible throughput collapse.
+## 
+## Default: erlang
+## 
+## Acceptable values:
+##   - one of: erlang, nif
+bitcask.io_mode = erlang
+
+## Set to 'off' to disable the admin panel.
+## 
+## Default: off
+## 
+## Acceptable values:
+##   - on or off
+riak_control = off
+
+## Authentication mode used for access to the admin panel.
+## 
+## Default: off
+## 
+## Acceptable values:
+##   - one of: off, userlist
+riak_control.auth.mode = off
+
+## If riak control's authentication mode (riak_control.auth.mode)
+## is set to 'userlist' then this is the list of usernames and
+## passwords for access to the admin panel.
+## To create users with given names, add entries of the format:
+## riak_control.auth.user.USERNAME.password = PASSWORD
+## replacing USERNAME with the desired username and PASSWORD with the
+## desired password for that user.
+## 
+## Acceptable values:
+##   - text
+## riak_control.auth.user.admin.password = pass
+
+## This parameter defines the percentage of total server memory
+## to assign to LevelDB. LevelDB will dynamically adjust its internal
+## cache sizes to stay within this size.  The memory size can
+## alternately be assigned as a byte count via leveldb.maximum_memory
+## instead.
+## 
+## Default: 70
+## 
+## Acceptable values:
+##   - an integer
+leveldb.maximum_memory.percent = 70
+
+## Enables or disables the compression of data on disk.
+## Enabling (default) saves disk space.  Disabling may reduce read
+## latency but increase overall disk activity.  Option can be
+## changed at any time, but will not impact data on disk until
+## next time a file requires compaction.
+## 
+## Default: on
+## 
+## Acceptable values:
+##   - on or off
+leveldb.compression = on
+
+## Selection of compression algorithms.  snappy is
+## original compression supplied for leveldb.  lz4 is new
+## algorithm that compresses to similar volume but averages twice
+## as fast on writes and four times as fast on reads.
+## 
+## Acceptable values:
+##   - one of: snappy, lz4
+leveldb.compression.algorithm = lz4
+
+## 
+## Default: on
+## 
+## Acceptable values:
+##   - on or off
+## multi_backend.name.leveldb.compression = on
+
+## 
+## Acceptable values:
+##   - one of: snappy, lz4
+## multi_backend.name.leveldb.compression.algorithm = lz4
+
+## Whether to allow search queries.
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.riak_search.query = enabled
+
+## To enable Search set this 'on'.
+## 
+## Default: off
+## 
+## Acceptable values:
+##   - on or off
+search = off
+
+## How long Riak will wait for Solr to start. The start sequence
+## will be tried twice. If both attempts timeout, then the Riak node
+## will be shutdown. This may need to be increased as more data is
+## indexed and Solr takes longer to start. Values lower than 1s will
+## be rounded up to the minimum 1s.
+## 
+## Default: 30s
+## 
+## Acceptable values:
+##   - a time duration with units, e.g. '10s' for 10 seconds
+search.solr.start_timeout = 30s
+
+## The port number which Solr binds to.
+## NOTE: Binds on every interface.
+## 
+## Default: 8093
+## 
+## Acceptable values:
+##   - an integer
+search.solr.port = 8093
+
+## The port number which Solr JMX binds to.
+## NOTE: Binds on every interface.
+## 
+## Default: 8985
+## 
+## Acceptable values:
+##   - an integer
+search.solr.jmx_port = 8985
+
+## The options to pass to the Solr JVM.  Non-standard options,
+## i.e. -XX, may not be portable across JVM implementations.
+## E.g. -XX:+UseCompressedStrings
+## 
+## Default: -d64 -Xms1g -Xmx1g -XX:+UseStringCache -XX:+UseCompressedOops
+## 
+## Acceptable values:
+##   - text
+search.solr.jvm_options = -d64 -Xms1g -Xmx1g -XX:+UseStringCache -XX:+UseCompressedOops
+
+## The minimum batch size, in number of Riak objects. Any batches that
+## are smaller than this amount will not be immediately flushed to Solr,
+## but are guaranteed to be flushed within the
+## "search.queue.batch.flush_interval".
+## 
+## Default: 10
+## 
+## Acceptable values:
+##   - an integer
+## search.queue.batch.minimum = 10
+
+## The maximum batch size, in number of Riak objects. Any batches that are
+## larger than this amount will be split, where the first
+## search.queue.batch.maximum set of objects will be flushed to Solr, and
+## the remaining objects enqueued for that index will be retained until the
+## next batch is delivered. This parameter ensures that at most
+## "search.queue.batch.maximum object" will be delivered into Solr in any
+## given request.
+## 
+## Default: 500
+## 
+## Acceptable values:
+##   - an integer
+## search.queue.batch.maximum = 500
+
+## The maximum delay between notification to flush batches to Solr. This
+## setting is used to increase or decrease the frequency of batch delivery
+## into Solr, specifically for relatively low-volume input into Riak. This
+## setting ensures that data will be delivered into Solr in accordance with
+## the "search.queue.batch.minimum" and "search.queue.batch.maximum"
+## settings within the specified interval. Batches that are smaller than
+## "search.queue.batch.minimum" will be delivered to Solr within this
+## interval. This setting will generally hav no effect on heavily loaded
+## systems.
+## 
+## Default: 500ms
+## 
+## Acceptable values:
+##   - a time duration with units, e.g. '10s' for 10 seconds
+##   - the text "infinity"
+## search.queue.batch.flush_interval = 500ms
+
+## The queue high watermark. If the total number of queued messages in a
+## Solr Queue Worker instance exceeds this limit, then the calling vnode
+## will be blocked until the total number falls below this limit. This
+## parameter exercises flow control between Riak and the Riak
+## Search batching subsystem if writes into Solr start to fall behind.
+## 
+## Default: 1000
+## 
+## Acceptable values:
+##   - an integer
+## search.queue.high_watermark = 1000
+
+## The strategy for how we handle purging when we hit the
+## search.queue.high_watermark.
+## - purge_one -> Removes the oldest item on the queue from an
+## erroring (references to fuses blown in the code) index in
+## order to get below the search.queue.high_watermark.
+## - purge_index -> Removes all items associated with one random
+## erroring (references to fuses blown in the code) index in
+## order to get below the search.queue.high_watermark.
+## - off -> purging is disabled
+## 
+## Default: purge_one
+## 
+## Acceptable values:
+##   - one of: purge_one, purge_index, off
+## search.queue.high_watermark.purge_strategy = purge_one
+
+## Whether to allow Yokozuna queries on this node
+## 
+## Default: enabled
+## 
+## Acceptable values:
+##   - enabled or disabled
+## cluster.job.yokozuna.query = enabled
diff --git a/test/docker/docker-compose.yml b/test/docker/docker-compose.yml
new file mode 100644 (file)
index 0000000..e6026ac
--- /dev/null
@@ -0,0 +1,48 @@
+version: '3.7'
+
+services:
+  mysql:
+    image: mysql:latest
+    container_name: ejabberd-mysql
+    volumes:
+      - ./db/mysql/data:/var/lib/mysql
+      - ./db/mysql/initdb:/docker-entrypoint-initdb.d:ro
+    command: --default-authentication-plugin=mysql_native_password
+    restart: always
+    ports:
+      - 3306:3306
+    environment:
+      MYSQL_ROOT_PASSWORD: root
+      MYSQL_DATABASE: ejabberd_test
+      MYSQL_USER: ejabberd_test
+      MYSQL_PASSWORD: ejabberd_test
+
+  postgres:
+    image: postgres:latest
+    container_name: ejabberd-postgres
+    volumes:
+      - ./db/postgres/data:/var/lib/postgresql/data
+      - ./db/postgres/initdb:/docker-entrypoint-initdb.d:ro
+    ports:
+      - 5432:5432
+    environment:
+      POSTGRES_PASSWORD: ejabberd_test
+      POSTGRES_USER: ejabberd_test
+      POSTGRES_DB: ejabberd_test
+
+  redis:
+    image: redis:latest
+    container_name: ejabberd-redis
+    ports:
+      - 6379:6379
+
+  riak:
+    image: ejabberd/riak:latest
+    container_name: ejabberd-riak
+    ports:
+      - 8087:8087
+      - 8098:8098
+    volumes:
+      - ./db/riak/data:/var/lib/riak
+    environment:
+      WAIT_FOR_ERLANG: 60