summaryrefslogtreecommitdiff
path: root/ctdb/tests/UNIT
diff options
context:
space:
mode:
authorMartin Schwenke <martin@meltin.net>2019-09-09 10:51:17 +1000
committerAmitay Isaacs <amitay@samba.org>2019-09-26 04:45:37 +0000
commit1061bdf29dce60251a53dcc0623efb8815b144ae (patch)
tree12a89f897743259a40a520bad489f23ae6effb53 /ctdb/tests/UNIT
parent9585ece00c8c7eb215da9928e54dae92f55eaac0 (diff)
downloadsamba-1061bdf29dce60251a53dcc0623efb8815b144ae.tar.gz
ctdb-tests: Move tool tests to UNIT/ subdirectory
Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com>
Diffstat (limited to 'ctdb/tests/UNIT')
-rw-r--r--ctdb/tests/UNIT/tool/README17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.attach.001.sh35
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.attach.002.sh35
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.attach.003.sh35
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ban.001.sh35
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ban.002.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ban.003.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.catdb.001.sh80
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.catdb.002.sh86
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.cattdb.001.sh80
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.cattdb.002.sh86
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.continue.001.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.continue.002.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.continue.003.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.deletekey.001.sh34
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.disable.001.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.disable.002.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.disable.003.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.disable.004.sh15
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.enable.001.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.enable.002.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.enable.003.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getcapabilities.001.sh19
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getcapabilities.002.sh19
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getcapabilities.003.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getcapabilities.004.sh39
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getdbmap.001.sh34
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getdbseqnum.001.sh41
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getdbseqnum.002.sh36
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getdbstatus.001.sh108
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getdbstatus.002.sh108
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getpid.001.sh17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getreclock.001.sh16
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getreclock.002.sh21
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getvar.001.sh35
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.getvar.002.sh17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ifaces.001.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.001.sh17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.002.sh17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.003.sh30
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.004.sh29
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.005.sh30
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.006.sh30
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ip.007.sh36
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ipinfo.001.sh18
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ipinfo.002.sh32
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ipinfo.003.sh35
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.listnodes.001.sh20
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.listnodes.002.sh19
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.listvars.001.sh67
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.001.sh36
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.002.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.003.sh43
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.004.sh45
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.005.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.006.sh44
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.007.sh42
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.lvs.008.sh66
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.001.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.002.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.003.sh43
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.004.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.005.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.006.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.007.sh45
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.natgw.008.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.nodestatus.001.sh33
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.nodestatus.002.sh33
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.nodestatus.003.sh33
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.nodestatus.004.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.nodestatus.005.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.nodestatus.006.sh40
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.pdelete.001.sh27
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ping.001.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.pnn.001.sh15
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.process-exists.001.sh26
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.process-exists.002.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.process-exists.003.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.pstore.001.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.ptrans.001.sh49
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.readkey.001.sh20
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.recmaster.001.sh16
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.recmaster.002.sh16
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.recover.001.sh22
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.001.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.002.sh30
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.003.sh29
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.011.sh25
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.012.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.013.sh26
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.014.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.015.sh26
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.016.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.017.sh26
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.018.sh29
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.019.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.020.sh28
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.021.sh26
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.023.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.reloadnodes.024.sh24
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.runstate.001.sh15
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.runstate.002.sh15
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.runstate.003.sh17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.runstate.004.sh15
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.runstate.005.sh15
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbreadonly.001.sh53
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbreadonly.002.sh37
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbreadonly.003.sh39
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbreadonly.004.sh37
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbreadonly.005.sh39
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbsticky.001.sh53
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbsticky.002.sh37
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbsticky.003.sh39
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbsticky.004.sh37
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdbsticky.005.sh39
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdebug.001.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdebug.002.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setdebug.003.sh32
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setifacelink.001.sh76
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setifacelink.002.sh22
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setvar.001.sh49
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.setvar.002.sh17
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.status.001.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.status.002.sh46
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.stop.001.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.stop.002.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.stop.003.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.unban.001.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.unban.002.sh34
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.unban.003.sh23
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.uptime.001.sh36
-rwxr-xr-xctdb/tests/UNIT/tool/ctdb.writekey.001.sh31
-rw-r--r--ctdb/tests/UNIT/tool/scripts/local.sh114
133 files changed, 4523 insertions, 0 deletions
diff --git a/ctdb/tests/UNIT/tool/README b/ctdb/tests/UNIT/tool/README
new file mode 100644
index 00000000000..816052862fd
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/README
@@ -0,0 +1,17 @@
+Unit tests for the ctdb tool (i.e. tools/ctdb).
+
+Test case filenames can take 2 forms:
+
+* func.<some_function>.NNN.sh
+
+ Run <some_function> in the ctdb tool code using the
+ ctdb_tool_functest test program. This test program uses test stubs
+ for CTDB client functions.
+
+* stubby.<command>.NNN.sh
+
+ Run the ctdb_tool_stubby test program with <command> as the 1st
+ argument - subsequent are passed to simple_test(). ctdb_tool_stubby
+ is linked against the test stubs for CTDB client functions.
+
+To add tests here you may need to add appropriate test stubs.
diff --git a/ctdb/tests/UNIT/tool/ctdb.attach.001.sh b/ctdb/tests/UNIT/tool/ctdb.attach.001.sh
new file mode 100755
index 00000000000..82c333282a9
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.attach.001.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "attach volatile database"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test "volatile.tdb"
+
+ok <<EOF
+Number of databases:1
+dbid:0x211bf47b name:volatile.tdb path:${ctdbd_dbdir}/volatile.tdb
+EOF
+
+simple_test_other getdbmap
+
+ok <<EOF
+dbid: 0x211bf47b
+name: volatile.tdb
+path: ${ctdbd_dbdir}/volatile.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+
+simple_test_other getdbstatus "volatile.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.attach.002.sh b/ctdb/tests/UNIT/tool/ctdb.attach.002.sh
new file mode 100755
index 00000000000..a4719bff3bf
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.attach.002.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "attach persistent database"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test "persistent.tdb" persistent
+
+ok <<EOF
+Number of databases:1
+dbid:0x54ef7d5e name:persistent.tdb path:${ctdbd_dbdir}/persistent.tdb PERSISTENT
+EOF
+
+simple_test_other getdbmap
+
+ok <<EOF
+dbid: 0x54ef7d5e
+name: persistent.tdb
+path: ${ctdbd_dbdir}/persistent.tdb
+PERSISTENT: yes
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+
+simple_test_other getdbstatus "persistent.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.attach.003.sh b/ctdb/tests/UNIT/tool/ctdb.attach.003.sh
new file mode 100755
index 00000000000..1a4cdebc123
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.attach.003.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "attach replicated database"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test "replicated.tdb" replicated
+
+ok <<EOF
+Number of databases:1
+dbid:0x84241f7c name:replicated.tdb path:${ctdbd_dbdir}/replicated.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
+
+ok <<EOF
+dbid: 0x84241f7c
+name: replicated.tdb
+path: ${ctdbd_dbdir}/replicated.tdb
+PERSISTENT: no
+REPLICATED: yes
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+
+simple_test_other getdbstatus "replicated.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.ban.001.sh b/ctdb/tests/UNIT/tool/ctdb.ban.001.sh
new file mode 100755
index 00000000000..3c17f752d76
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ban.001.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "ban default (0), wait for timeout"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test 4
+
+required_result 8 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 BANNED|INACTIVE (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
+
+echo
+echo "Waiting 5 seconds for ban to expire..."
+sleep 5
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.ban.002.sh b/ctdb/tests/UNIT/tool/ctdb.ban.002.sh
new file mode 100755
index 00000000000..47a9995886f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ban.002.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "ban node 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test 60 -n 1
+
+required_result 8 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 BANNED|INACTIVE
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.ban.003.sh b/ctdb/tests/UNIT/tool/ctdb.ban.003.sh
new file mode 100755
index 00000000000..95acf500b5b
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ban.003.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "already banned"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x8
+2 192.168.20.43 0x0
+EOF
+
+ok "Node 1 is already banned"
+simple_test 60 -n 1
+
+required_result 8 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 BANNED|INACTIVE
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.catdb.001.sh b/ctdb/tests/UNIT/tool/ctdb.catdb.001.sh
new file mode 100755
index 00000000000..7fef1f17304
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.catdb.001.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "volatile traverse"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "volatile.tdb"
+
+for i in $(seq 1 9) ; do
+ ok_null
+ simple_test_other writekey "volatile.tdb" "key$i" "value$i"
+done
+
+ok <<EOF
+key(4) = "key2"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value2"
+
+key(4) = "key4"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value4"
+
+key(4) = "key9"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value9"
+
+key(4) = "key8"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value8"
+
+key(4) = "key6"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value6"
+
+key(4) = "key3"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value3"
+
+key(4) = "key7"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value7"
+
+key(4) = "key5"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value5"
+
+key(4) = "key1"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value1"
+
+Dumped 9 records
+EOF
+
+simple_test "volatile.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.catdb.002.sh b/ctdb/tests/UNIT/tool/ctdb.catdb.002.sh
new file mode 100755
index 00000000000..52583088a59
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.catdb.002.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "persistent traverse"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "persistent.tdb" persistent
+
+for i in $(seq 1 9) ; do
+ ok_null
+ simple_test_other pstore "persistent.tdb" "key$i" "value$i"
+done
+
+ok <<EOF
+key(23) = "__db_sequence_number__\00"
+dmaster: 0
+rsn: 9
+flags: 0x00000000
+data(8) = "\09\00\00\00\00\00\00\00"
+
+key(4) = "key9"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value9"
+
+key(4) = "key8"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value8"
+
+key(4) = "key7"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value7"
+
+key(4) = "key6"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value6"
+
+key(4) = "key5"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value5"
+
+key(4) = "key4"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value4"
+
+key(4) = "key3"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value3"
+
+key(4) = "key2"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value2"
+
+key(4) = "key1"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value1"
+
+Dumped 10 records
+EOF
+
+simple_test "persistent.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.cattdb.001.sh b/ctdb/tests/UNIT/tool/ctdb.cattdb.001.sh
new file mode 100755
index 00000000000..be549e2bda9
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.cattdb.001.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "volatile traverse"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "volatile.tdb"
+
+for i in $(seq 1 9) ; do
+ ok_null
+ simple_test_other writekey "volatile.tdb" "key$i" "value$i"
+done
+
+ok <<EOF
+key(4) = "key2"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value2"
+
+key(4) = "key4"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value4"
+
+key(4) = "key9"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value9"
+
+key(4) = "key8"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value8"
+
+key(4) = "key6"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value6"
+
+key(4) = "key3"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value3"
+
+key(4) = "key7"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value7"
+
+key(4) = "key5"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value5"
+
+key(4) = "key1"
+dmaster: 0
+rsn: 0
+flags: 0x00000000
+data(6) = "value1"
+
+Dumped 9 record(s)
+EOF
+
+simple_test "volatile.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.cattdb.002.sh b/ctdb/tests/UNIT/tool/ctdb.cattdb.002.sh
new file mode 100755
index 00000000000..03c5e7f07d8
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.cattdb.002.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "persistent traverse"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "persistent.tdb" persistent
+
+for i in $(seq 1 9) ; do
+ ok_null
+ simple_test_other pstore "persistent.tdb" "key$i" "value$i"
+done
+
+ok <<EOF
+key(23) = "__db_sequence_number__\00"
+dmaster: 0
+rsn: 9
+flags: 0x00000000
+data(8) = "\09\00\00\00\00\00\00\00"
+
+key(4) = "key9"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value9"
+
+key(4) = "key8"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value8"
+
+key(4) = "key7"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value7"
+
+key(4) = "key6"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value6"
+
+key(4) = "key5"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value5"
+
+key(4) = "key4"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value4"
+
+key(4) = "key3"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value3"
+
+key(4) = "key2"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value2"
+
+key(4) = "key1"
+dmaster: 0
+rsn: 1
+flags: 0x00000000
+data(6) = "value1"
+
+Dumped 10 record(s)
+EOF
+
+simple_test "persistent.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.continue.001.sh b/ctdb/tests/UNIT/tool/ctdb.continue.001.sh
new file mode 100755
index 00000000000..fef1e00c65a
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.continue.001.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "continue default (0)"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x20 CURRENT
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 RECMASTER
+EOF
+
+ok_null
+simple_test
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.continue.002.sh b/ctdb/tests/UNIT/tool/ctdb.continue.002.sh
new file mode 100755
index 00000000000..55ce7f502bf
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.continue.002.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "continue 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT
+1 192.168.20.42 0x20
+2 192.168.20.43 0x0 RECMASTER
+EOF
+
+ok_null
+simple_test -n 1
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.continue.003.sh b/ctdb/tests/UNIT/tool/ctdb.continue.003.sh
new file mode 100755
index 00000000000..72801256011
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.continue.003.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "node is not stopped"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "Node 2 is not stopped"
+simple_test -n 2
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.deletekey.001.sh b/ctdb/tests/UNIT/tool/ctdb.deletekey.001.sh
new file mode 100755
index 00000000000..f530801bf7f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.deletekey.001.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "volatile delete"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "volatile.tdb"
+
+ok_null
+simple_test "volatile.tdb" "key1"
+
+ok_null
+simple_test_other writekey "volatile.tdb" "key1" "value1"
+
+ok <<EOF
+Data: size:6 ptr:[value1]
+EOF
+simple_test_other readkey "volatile.tdb" "key1"
+
+ok_null
+simple_test "volatile.tdb" "key1"
+
+ok <<EOF
+Data: size:0 ptr:[]
+EOF
+simple_test_other readkey "volatile.tdb" "key1"
diff --git a/ctdb/tests/UNIT/tool/ctdb.disable.001.sh b/ctdb/tests/UNIT/tool/ctdb.disable.001.sh
new file mode 100755
index 00000000000..b2e419b96bd
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.disable.001.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "disable default (0)"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test
+
+required_result 4 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 DISABLED (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.disable.002.sh b/ctdb/tests/UNIT/tool/ctdb.disable.002.sh
new file mode 100755
index 00000000000..ac90c75f615
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.disable.002.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "disable node 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test -n 1
+
+required_result 4 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 DISABLED
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.disable.003.sh b/ctdb/tests/UNIT/tool/ctdb.disable.003.sh
new file mode 100755
index 00000000000..ef02ba0bb21
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.disable.003.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "already disabled"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x4
+2 192.168.20.43 0x0
+EOF
+
+ok "Node 1 is already disabled"
+simple_test -n 1
+
+required_result 4 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 DISABLED
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.disable.004.sh b/ctdb/tests/UNIT/tool/ctdb.disable.004.sh
new file mode 100755
index 00000000000..da39d67ca73
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.disable.004.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "invalid node"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 "Node 4 does not exist"
+simple_test -n 4
diff --git a/ctdb/tests/UNIT/tool/ctdb.enable.001.sh b/ctdb/tests/UNIT/tool/ctdb.enable.001.sh
new file mode 100755
index 00000000000..9234f195967
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.enable.001.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "enable default (0)"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x4 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.enable.002.sh b/ctdb/tests/UNIT/tool/ctdb.enable.002.sh
new file mode 100755
index 00000000000..ee9b2103b20
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.enable.002.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "enable node 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x4
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test -n 1
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.enable.003.sh b/ctdb/tests/UNIT/tool/ctdb.enable.003.sh
new file mode 100755
index 00000000000..37656c24f68
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.enable.003.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "not disabled"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "Node 1 is not disabled"
+simple_test -n 1
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.getcapabilities.001.sh b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.001.sh
new file mode 100755
index 00000000000..d04db04b60d
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.001.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+RECMASTER: YES
+LMASTER: YES
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getcapabilities.002.sh b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.002.sh
new file mode 100755
index 00000000000..f54786290e5
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.002.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, 1 disconnected"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x1
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+RECMASTER: YES
+LMASTER: YES
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getcapabilities.003.sh b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.003.sh
new file mode 100755
index 00000000000..74702d5b5e7
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.003.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, current disconnected"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+# Don't setup ctdbd - disconnected on current node
+#setup_ctdbd <<EOF
+#NODEMAP
+#0 192.168.20.41 0x1 CURRENT RECMASTER
+#1 192.168.20.42 0x0
+#2 192.168.20.43 0x0
+#EOF
+
+required_result 1 <<EOF
+connect() failed, errno=2
+Failed to connect to CTDB daemon ($ctdbd_socket)
+Failed to detect PNN of the current node.
+Is this node part of CTDB cluster?
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getcapabilities.004.sh b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.004.sh
new file mode 100755
index 00000000000..ae4ad2b5246
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getcapabilities.004.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, non-default capabilities"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0 -CTDB_CAP_LMASTER
+2 192.168.20.43 0x0 -CTDB_CAP_RECMASTER
+EOF
+
+# node 0
+
+required_result 0 <<EOF
+RECMASTER: YES
+LMASTER: YES
+EOF
+
+simple_test -n 0
+
+# node 1
+
+required_result 0 <<EOF
+RECMASTER: YES
+LMASTER: NO
+EOF
+
+simple_test -n 1
+
+# node 2
+
+required_result 0 <<EOF
+RECMASTER: NO
+LMASTER: YES
+EOF
+
+simple_test -n 2
diff --git a/ctdb/tests/UNIT/tool/ctdb.getdbmap.001.sh b/ctdb/tests/UNIT/tool/ctdb.getdbmap.001.sh
new file mode 100755
index 00000000000..f766e9c0e38
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getdbmap.001.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "getdbmap from default (0)"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb READONLY
+0x4e66c2b2 brlock.tdb STICKY
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb READONLY
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb STICKY
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getdbseqnum.001.sh b/ctdb/tests/UNIT/tool/ctdb.getdbseqnum.001.sh
new file mode 100755
index 00000000000..95ef244a69b
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getdbseqnum.001.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "by ID"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 0x42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 0x23
+EOF
+
+# locking.tdb
+ok "0x0"
+simple_test 0x7a19d84d
+
+# secrets.tdb
+ok "0x0"
+simple_test 0x7132c184
+
+# registry.tdb
+ok "0x42"
+simple_test 0x6cf2837d
+
+# ctdb-ip.tdb
+ok "0x0"
+simple_test 0xbc57b384
+
+# ctdb-conn.tdb
+ok "0x23"
+simple_test 0xbec75f0b
diff --git a/ctdb/tests/UNIT/tool/ctdb.getdbseqnum.002.sh b/ctdb/tests/UNIT/tool/ctdb.getdbseqnum.002.sh
new file mode 100755
index 00000000000..e0274f339be
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getdbseqnum.002.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 0x42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 0x23
+EOF
+
+ok "0x0"
+simple_test locking.tdb
+
+ok "0x0"
+simple_test secrets.tdb
+
+ok "0x42"
+simple_test registry.tdb
+
+ok "0x0"
+simple_test ctdb-ip.tdb
+
+ok "0x23"
+simple_test ctdb-conn.tdb
diff --git a/ctdb/tests/UNIT/tool/ctdb.getdbstatus.001.sh b/ctdb/tests/UNIT/tool/ctdb.getdbstatus.001.sh
new file mode 100755
index 00000000000..5a2b79e0b6f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getdbstatus.001.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "by ID"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb READONLY
+0x4e66c2b2 brlock.tdb STICKY
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok <<EOF
+dbid: 0x7a19d84d
+name: locking.tdb
+path: ${ctdbd_dbdir}/locking.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: no
+READONLY: yes
+HEALTH: OK
+EOF
+simple_test 0x7a19d84d
+
+ok <<EOF
+dbid: 0x4e66c2b2
+name: brlock.tdb
+path: ${ctdbd_dbdir}/brlock.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: yes
+READONLY: no
+HEALTH: OK
+EOF
+simple_test 0x4e66c2b2
+
+ok <<EOF
+dbid: 0x4d2a432b
+name: g_lock.tdb
+path: ${ctdbd_dbdir}/g_lock.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test 0x4d2a432b
+
+ok <<EOF
+dbid: 0x7132c184
+name: secrets.tdb
+path: ${ctdbd_dbdir}/secrets.tdb
+PERSISTENT: yes
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test 0x7132c184
+
+ok <<EOF
+dbid: 0x6cf2837d
+name: registry.tdb
+path: ${ctdbd_dbdir}/registry.tdb
+PERSISTENT: yes
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test 0x6cf2837d
+
+ok <<EOF
+dbid: 0xbc57b384
+name: ctdb-ip.tdb
+path: ${ctdbd_dbdir}/ctdb-ip.tdb
+PERSISTENT: no
+REPLICATED: yes
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test 0xbc57b384
+
+ok <<EOF
+dbid: 0xbec75f0b
+name: ctdb-conn.tdb
+path: ${ctdbd_dbdir}/ctdb-conn.tdb
+PERSISTENT: no
+REPLICATED: yes
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test 0xbec75f0b
+
+required_result 1 "No database matching '0xdeadc0de' found"
+simple_test 0xdeadc0de
diff --git a/ctdb/tests/UNIT/tool/ctdb.getdbstatus.002.sh b/ctdb/tests/UNIT/tool/ctdb.getdbstatus.002.sh
new file mode 100755
index 00000000000..2ff6e7b926c
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getdbstatus.002.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "by name, node 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb READONLY
+0x4e66c2b2 brlock.tdb STICKY
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok <<EOF
+dbid: 0x7a19d84d
+name: locking.tdb
+path: ${ctdbd_dbdir}/locking.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: no
+READONLY: yes
+HEALTH: OK
+EOF
+simple_test locking.tdb -n 1
+
+ok <<EOF
+dbid: 0x4e66c2b2
+name: brlock.tdb
+path: ${ctdbd_dbdir}/brlock.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: yes
+READONLY: no
+HEALTH: OK
+EOF
+simple_test brlock.tdb -n 1
+
+ok <<EOF
+dbid: 0x4d2a432b
+name: g_lock.tdb
+path: ${ctdbd_dbdir}/g_lock.tdb
+PERSISTENT: no
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test g_lock.tdb -n 1
+
+ok <<EOF
+dbid: 0x7132c184
+name: secrets.tdb
+path: ${ctdbd_dbdir}/secrets.tdb
+PERSISTENT: yes
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test secrets.tdb -n 1
+
+ok <<EOF
+dbid: 0x6cf2837d
+name: registry.tdb
+path: ${ctdbd_dbdir}/registry.tdb
+PERSISTENT: yes
+REPLICATED: no
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test registry.tdb -n 1
+
+ok <<EOF
+dbid: 0xbc57b384
+name: ctdb-ip.tdb
+path: ${ctdbd_dbdir}/ctdb-ip.tdb
+PERSISTENT: no
+REPLICATED: yes
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test ctdb-ip.tdb -n 1
+
+ok <<EOF
+dbid: 0xbec75f0b
+name: ctdb-conn.tdb
+path: ${ctdbd_dbdir}/ctdb-conn.tdb
+PERSISTENT: no
+REPLICATED: yes
+STICKY: no
+READONLY: no
+HEALTH: OK
+EOF
+simple_test ctdb-conn.tdb -n 1
+
+required_result 1 "No database matching 'ctdb.tdb' found"
+simple_test ctdb.tdb -n 1
diff --git a/ctdb/tests/UNIT/tool/ctdb.getpid.001.sh b/ctdb/tests/UNIT/tool/ctdb.getpid.001.sh
new file mode 100755
index 00000000000..57141022f84
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getpid.001.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "simple getpid"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+pid=$(ctdbd_getpid)
+ok "$pid"
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getreclock.001.sh b/ctdb/tests/UNIT/tool/ctdb.getreclock.001.sh
new file mode 100755
index 00000000000..bfa08d06e51
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getreclock.001.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "No reclock set"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getreclock.002.sh b/ctdb/tests/UNIT/tool/ctdb.getreclock.002.sh
new file mode 100755
index 00000000000..6543f8f6534
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getreclock.002.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "No reclock set"
+
+reclock="/some/place/on/shared/storage"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+RECLOCK
+${reclock}
+EOF
+
+ok "$reclock"
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.getvar.001.sh b/ctdb/tests/UNIT/tool/ctdb.getvar.001.sh
new file mode 100755
index 00000000000..480788ada07
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getvar.001.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "confirm that getvar matches listvar"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+# Squash whitespace for predictable output
+result_filter ()
+{
+ sed -e 's|[[:space:]][[:space:]]*| |g'
+}
+
+$CTDB -d $CTDB_DEBUGLEVEL listvars |
+ while read variable equals value ; do
+ # Variable, as per listvars
+ ok "${variable} = ${value}"
+ simple_test "$variable"
+
+ # Uppercase variable
+ v_upper=$(echo "$variable" | tr "a-z" "A-Z")
+ ok "${v_upper} = ${value}"
+ simple_test "$v_upper"
+
+ # Lowercase variable
+ v_lower=$(echo "$variable" | tr "A-Z" "a-z")
+ ok "${v_lower} = ${value}"
+ simple_test "$v_lower"
+ done
diff --git a/ctdb/tests/UNIT/tool/ctdb.getvar.002.sh b/ctdb/tests/UNIT/tool/ctdb.getvar.002.sh
new file mode 100755
index 00000000000..c8aa302b768
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.getvar.002.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "invalid variable"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+No such tunable TheQuickBrownFoxJumpsOverTheLazyDog
+EOF
+simple_test "TheQuickBrownFoxJumpsOverTheLazyDog"
diff --git a/ctdb/tests/UNIT/tool/ctdb.ifaces.001.sh b/ctdb/tests/UNIT/tool/ctdb.ifaces.001.sh
new file mode 100755
index 00000000000..5b9278765e1
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ifaces.001.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "basic interface listing test"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+ok <<EOF
+Interfaces on node 0
+name:eth2 link:up references:2
+name:eth1 link:up references:4
+EOF
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.001.sh b/ctdb/tests/UNIT/tool/ctdb.ip.001.sh
new file mode 100755
index 00000000000..df0d1416295
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.001.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, no ips"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+Public IPs on node 0
+EOF
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.002.sh b/ctdb/tests/UNIT/tool/ctdb.ip.002.sh
new file mode 100755
index 00000000000..98a821fd1c6
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.002.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, no ips"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+Public IPs on ALL nodes
+EOF
+simple_test all
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.003.sh b/ctdb/tests/UNIT/tool/ctdb.ip.003.sh
new file mode 100755
index 00000000000..eec46346c4a
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.003.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, same ips on all nodes"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0
+10.0.0.32 1
+10.0.0.33 2
+EOF
+
+required_result 0 <<EOF
+Public IPs on node 0
+10.0.0.31 0
+10.0.0.32 1
+10.0.0.33 2
+EOF
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.004.sh b/ctdb/tests/UNIT/tool/ctdb.ip.004.sh
new file mode 100755
index 00000000000..53f090c4dd7
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.004.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, IP missing on node 0"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0 0,1,2
+10.0.0.32 1 0,1,2
+10.0.0.33 2 1,2
+EOF
+
+required_result 0 <<EOF
+Public IPs on node 0
+10.0.0.31 0
+10.0.0.32 1
+EOF
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.005.sh b/ctdb/tests/UNIT/tool/ctdb.ip.005.sh
new file mode 100755
index 00000000000..f84ac29a0f3
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.005.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, IP missing on node 0, get all"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0 0,1,2
+10.0.0.32 1 0,1,2
+10.0.0.33 2 1,2
+EOF
+
+required_result 0 <<EOF
+Public IPs on ALL nodes
+10.0.0.31 0
+10.0.0.32 1
+10.0.0.33 2
+EOF
+simple_test all
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.006.sh b/ctdb/tests/UNIT/tool/ctdb.ip.006.sh
new file mode 100755
index 00000000000..975a98c8d25
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.006.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, same ips on all nodes, 1 unassigned"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0
+10.0.0.32 -1
+10.0.0.33 2
+EOF
+
+required_result 0 <<EOF
+Public IPs on ALL nodes
+10.0.0.31 node[0] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+10.0.0.32 node[-1] active[] available[] configured[]
+10.0.0.33 node[2] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+EOF
+simple_test -v all
diff --git a/ctdb/tests/UNIT/tool/ctdb.ip.007.sh b/ctdb/tests/UNIT/tool/ctdb.ip.007.sh
new file mode 100755
index 00000000000..cb7939d3507
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ip.007.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, same ips on all nodes, IPv6, 1 unassigned"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0
+fd00::5357:5f01 2
+10.0.0.32 -1
+fd00::5357:5f02 1
+10.0.0.33 2
+fd00::5357:5f03 0
+EOF
+
+required_result 0 <<EOF
+Public IPs on ALL nodes
+10.0.0.31 node[0] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+10.0.0.32 node[-1] active[] available[] configured[]
+10.0.0.33 node[2] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+fd00::5357:5f01 node[2] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+fd00::5357:5f02 node[1] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+fd00::5357:5f03 node[0] active[eth2] available[eth2,eth1] configured[eth2,eth1]
+EOF
+simple_test -v all
diff --git a/ctdb/tests/UNIT/tool/ctdb.ipinfo.001.sh b/ctdb/tests/UNIT/tool/ctdb.ipinfo.001.sh
new file mode 100755
index 00000000000..60f9462f0fd
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ipinfo.001.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, no ips"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+Control GET_PUBLIC_IP_INFO failed, ret=-1
+Node 0 does not know about IP 10.0.0.31
+EOF
+simple_test 10.0.0.31
diff --git a/ctdb/tests/UNIT/tool/ctdb.ipinfo.002.sh b/ctdb/tests/UNIT/tool/ctdb.ipinfo.002.sh
new file mode 100755
index 00000000000..366cfd69cbc
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ipinfo.002.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, same ips on all nodes"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0
+10.0.0.32 1
+10.0.0.33 2
+EOF
+
+required_result 0 <<EOF
+Public IP[10.0.0.32] info on node 0
+IP:10.0.0.32
+CurrentNode:1
+NumInterfaces:2
+Interface[1]: Name:eth2 Link:up References:2 (active)
+Interface[2]: Name:eth1 Link:up References:4
+EOF
+simple_test 10.0.0.32
diff --git a/ctdb/tests/UNIT/tool/ctdb.ipinfo.003.sh b/ctdb/tests/UNIT/tool/ctdb.ipinfo.003.sh
new file mode 100755
index 00000000000..383f1c71c36
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ipinfo.003.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all ok, same ips on all nodes, IPv6"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+PUBLICIPS
+10.0.0.31 0
+10.0.0.32 1
+10.0.0.33 2
+fd00::5357:5f01 2
+fd00::5357:5f02 1
+fd00::5357:5f03 0
+EOF
+
+required_result 0 <<EOF
+Public IP[fd00::5357:5f02] info on node 0
+IP:fd00::5357:5f02
+CurrentNode:1
+NumInterfaces:2
+Interface[1]: Name:eth2 Link:up References:2 (active)
+Interface[2]: Name:eth1 Link:up References:4
+EOF
+simple_test fd00::5357:5f02
diff --git a/ctdb/tests/UNIT/tool/ctdb.listnodes.001.sh b/ctdb/tests/UNIT/tool/ctdb.listnodes.001.sh
new file mode 100755
index 00000000000..5a494ee8c9e
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.listnodes.001.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "missing nodes file"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+f="${CTDB_BASE}/nodes"
+rm -f "$f"
+
+required_result 1 <<EOF
+${TEST_DATE_STAMP}Failed to read nodes file "${f}"
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.listnodes.002.sh b/ctdb/tests/UNIT/tool/ctdb.listnodes.002.sh
new file mode 100755
index 00000000000..95315d75b64
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.listnodes.002.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "missing nodes file"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+required_result 0 <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.listvars.001.sh b/ctdb/tests/UNIT/tool/ctdb.listvars.001.sh
new file mode 100755
index 00000000000..a304942af43
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.listvars.001.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "exact check of output"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok << EOF
+SeqnumInterval = 1000
+ControlTimeout = 60
+TraverseTimeout = 20
+KeepaliveInterval = 5
+KeepaliveLimit = 5
+RecoverTimeout = 30
+RecoverInterval = 1
+ElectionTimeout = 3
+TakeoverTimeout = 9
+MonitorInterval = 15
+TickleUpdateInterval = 20
+EventScriptTimeout = 30
+MonitorTimeoutCount = 20
+RecoveryGracePeriod = 120
+RecoveryBanPeriod = 300
+DatabaseHashSize = 100001
+DatabaseMaxDead = 5
+RerecoveryTimeout = 10
+EnableBans = 1
+NoIPFailback = 0
+VerboseMemoryNames = 0
+RecdPingTimeout = 60
+RecdFailCount = 10
+LogLatencyMs = 0
+RecLockLatencyMs = 1000
+RecoveryDropAllIPs = 120
+VacuumInterval = 10
+VacuumMaxRunTime = 120
+RepackLimit = 10000
+VacuumLimit = 5000
+VacuumFastPathCount = 60
+MaxQueueDropMsg = 1000000
+AllowUnhealthyDBRead = 0
+StatHistoryInterval = 1
+DeferredAttachTO = 120
+AllowClientDBAttach = 1
+FetchCollapse = 1
+HopcountMakeSticky = 50
+StickyDuration = 600
+StickyPindown = 200
+NoIPTakeover = 0
+DBRecordCountWarn = 100000
+DBRecordSizeWarn = 10000000
+DBSizeWarn = 100000000
+PullDBPreallocation = 10485760
+LockProcessesPerDB = 200
+RecBufferSizeLimit = 1000000
+QueueBufferSize = 1024
+IPAllocAlgorithm = 2
+AllowMixedVersions = 0
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.001.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.001.sh
new file mode 100755
index 00000000000..411072c5da4
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.001.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, no LVS, all ok"
+
+setup_lvs <<EOF
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 255 <<EOF
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.002.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.002.sh
new file mode 100755
index 00000000000..5344b166a4e
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.002.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all LVS, all ok"
+
+setup_lvs <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+0
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+0 192.168.20.41
+1 192.168.20.42
+2 192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.003.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.003.sh
new file mode 100755
index 00000000000..c3d1f7221f1
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.003.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, some LVS, all ok"
+
+setup_lvs <<EOF
+192.168.20.41
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+0
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+0 192.168.20.41
+2 192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.004.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.004.sh
new file mode 100755
index 00000000000..ea1d1887fe6
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.004.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all LVS, node 0 unhealthy"
+
+setup_lvs <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+1
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+1 192.168.20.42
+2 192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 UNHEALTHY (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.005.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.005.sh
new file mode 100755
index 00000000000..592224863ea
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.005.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all LVS, all unhealthy"
+
+setup_lvs <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2 CURRENT RECMASTER
+1 192.168.20.42 0x2
+2 192.168.20.43 0x2
+EOF
+
+#####
+
+required_result 0 <<EOF
+0
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+0 192.168.20.41
+1 192.168.20.42
+2 192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 UNHEALTHY (THIS NODE)
+pnn:1 192.168.20.42 UNHEALTHY
+pnn:2 192.168.20.43 UNHEALTHY
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.006.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.006.sh
new file mode 100755
index 00000000000..2f9859a6be8
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.006.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all LVS, nodes 0,1 disabled, node 2 unhealthy"
+
+setup_lvs <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x4 CURRENT RECMASTER
+1 192.168.20.42 0x4
+2 192.168.20.43 0x2
+EOF
+
+#####
+
+required_result 0 <<EOF
+2
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+2 192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 DISABLED (THIS NODE)
+pnn:1 192.168.20.42 DISABLED
+pnn:2 192.168.20.43 UNHEALTHY
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.007.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.007.sh
new file mode 100755
index 00000000000..dd47b9e69ca
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.007.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all LVS, all nodes disabled"
+
+setup_lvs <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x4 CURRENT RECMASTER
+1 192.168.20.42 0x4
+2 192.168.20.43 0x4
+EOF
+
+#####
+
+required_result 255 <<EOF
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 DISABLED (THIS NODE)
+pnn:1 192.168.20.42 DISABLED
+pnn:2 192.168.20.43 DISABLED
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.lvs.008.sh b/ctdb/tests/UNIT/tool/ctdb.lvs.008.sh
new file mode 100755
index 00000000000..6cdd702c57c
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.lvs.008.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, no LVS, current disconnected"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_lvs <<EOF
+EOF
+
+# Don't setup ctdbd - disconnected on current node
+#setup_ctdbd <<EOF
+#NODEMAP
+#0 192.168.20.41 0x1 CURRENT RECMASTER
+#1 192.168.20.42 0x0
+#2 192.168.20.43 0x0
+#EOF
+
+#####
+
+required_result 1 <<EOF
+connect() failed, errno=2
+Failed to connect to CTDB daemon ($ctdbd_socket)
+Failed to detect PNN of the current node.
+Is this node part of CTDB cluster?
+EOF
+
+simple_test list
+
+#####
+
+required_result 1 <<EOF
+connect() failed, errno=2
+Failed to connect to CTDB daemon ($ctdbd_socket)
+Failed to detect PNN of the current node.
+Is this node part of CTDB cluster?
+EOF
+
+simple_test master
+
+#####
+
+required_result 1 <<EOF
+connect() failed, errno=2
+Failed to connect to CTDB daemon ($ctdbd_socket)
+Failed to detect PNN of the current node.
+Is this node part of CTDB cluster?
+EOF
+
+simple_test list
+
+#####
+
+required_result 1 <<EOF
+connect() failed, errno=2
+Failed to connect to CTDB daemon ($ctdbd_socket)
+Failed to detect PNN of the current node.
+Is this node part of CTDB cluster?
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.001.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.001.sh
new file mode 100755
index 00000000000..b73ce24c986
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.001.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all in natgw group, all ok"
+
+setup_natgw <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+0 192.168.20.41
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41 MASTER
+192.168.20.42
+192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.002.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.002.sh
new file mode 100755
index 00000000000..259c8695e64
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.002.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all in natgw group, 1 unhealthy"
+
+setup_natgw <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2
+1 192.168.20.42 0x0 CURRENT RECMASTER
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+1 192.168.20.42
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41
+192.168.20.42 MASTER
+192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 UNHEALTHY
+pnn:1 192.168.20.42 OK (THIS NODE)
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.003.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.003.sh
new file mode 100755
index 00000000000..af48b48c622
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.003.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, 2 in natgw group, 1 unhealthy"
+
+setup_natgw <<EOF
+192.168.20.41
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2
+1 192.168.20.42 0x0 CURRENT RECMASTER
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+2 192.168.20.43
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41
+192.168.20.43 MASTER
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 UNHEALTHY
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.004.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.004.sh
new file mode 100755
index 00000000000..8e48dcf432f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.004.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all unhealthy, all but 1 stopped"
+
+setup_natgw <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x22
+1 192.168.20.42 0x22 CURRENT RECMASTER
+2 192.168.20.43 0x2
+EOF
+
+#####
+
+required_result 0 <<EOF
+2 192.168.20.43
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43 MASTER
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 UNHEALTHY|STOPPED|INACTIVE
+pnn:1 192.168.20.42 UNHEALTHY|STOPPED|INACTIVE (THIS NODE)
+pnn:2 192.168.20.43 UNHEALTHY
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.005.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.005.sh
new file mode 100755
index 00000000000..ccb05e8d8af
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.005.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all stopped"
+
+setup_natgw <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x20
+1 192.168.20.42 0x20 CURRENT RECMASTER
+2 192.168.20.43 0x20
+EOF
+
+#####
+
+required_result 0 <<EOF
+0 192.168.20.41
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41 MASTER
+192.168.20.42
+192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 STOPPED|INACTIVE
+pnn:1 192.168.20.42 STOPPED|INACTIVE (THIS NODE)
+pnn:2 192.168.20.43 STOPPED|INACTIVE
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.006.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.006.sh
new file mode 100755
index 00000000000..0f194d81809
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.006.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, node 0 is slave-only, all stopped"
+
+setup_natgw <<EOF
+192.168.20.41 slave-only
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x20
+1 192.168.20.42 0x20 CURRENT RECMASTER
+2 192.168.20.43 0x20
+EOF
+
+#####
+
+required_result 0 <<EOF
+1 192.168.20.42
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41 slave-only
+192.168.20.42 MASTER
+192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 STOPPED|INACTIVE
+pnn:1 192.168.20.42 STOPPED|INACTIVE (THIS NODE)
+pnn:2 192.168.20.43 STOPPED|INACTIVE
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.007.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.007.sh
new file mode 100755
index 00000000000..9fdfc302f3b
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.007.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all nodes are slave-only, all stopped"
+
+setup_natgw <<EOF
+192.168.20.41 slave-only
+192.168.20.42 slave-only
+192.168.20.43 slave-only
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x20
+1 192.168.20.42 0x20 CURRENT RECMASTER
+2 192.168.20.43 0x20
+EOF
+
+#####
+
+required_result 2 <<EOF
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41 slave-only
+192.168.20.42 slave-only
+192.168.20.43 slave-only
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 STOPPED|INACTIVE
+pnn:1 192.168.20.42 STOPPED|INACTIVE (THIS NODE)
+pnn:2 192.168.20.43 STOPPED|INACTIVE
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.natgw.008.sh b/ctdb/tests/UNIT/tool/ctdb.natgw.008.sh
new file mode 100755
index 00000000000..db204a51383
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.natgw.008.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, all in natgw group, 1 disconnected"
+
+setup_natgw <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x1
+1 192.168.20.42 0x0 CURRENT RECMASTER
+2 192.168.20.43 0x0
+EOF
+
+#####
+
+required_result 0 <<EOF
+1 192.168.20.42
+EOF
+
+simple_test master
+
+#####
+
+required_result 0 <<EOF
+192.168.20.41
+192.168.20.42 MASTER
+192.168.20.43
+EOF
+
+simple_test list
+
+#####
+
+required_result 0 <<EOF
+pnn:0 192.168.20.41 DISCONNECTED|INACTIVE
+pnn:1 192.168.20.42 OK (THIS NODE)
+pnn:2 192.168.20.43 OK
+EOF
+
+simple_test status
diff --git a/ctdb/tests/UNIT/tool/ctdb.nodestatus.001.sh b/ctdb/tests/UNIT/tool/ctdb.nodestatus.001.sh
new file mode 100755
index 00000000000..2217afcc0b9
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.nodestatus.001.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "all, 3 nodes, all OK"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 0 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK (THIS NODE)
+EOF
+simple_test all
+
+required_result 0 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|0|0|0|0|0|N|
+|1|192.168.20.42|0|0|0|0|0|0|0|N|
+|2|192.168.20.43|0|0|0|0|0|0|0|Y|
+EOF
+simple_test -X all
diff --git a/ctdb/tests/UNIT/tool/ctdb.nodestatus.002.sh b/ctdb/tests/UNIT/tool/ctdb.nodestatus.002.sh
new file mode 100755
index 00000000000..c1706fd98e7
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.nodestatus.002.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "all, 3 nodes, 1 disconnected"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0
+1 192.168.20.42 0x1
+2 192.168.20.43 0x0 CURRENT RECMASTER
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 1 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK
+pnn:1 192.168.20.42 DISCONNECTED|INACTIVE
+pnn:2 192.168.20.43 OK (THIS NODE)
+EOF
+simple_test all
+
+required_result 1 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|0|0|0|0|0|N|
+|1|192.168.20.42|1|0|0|0|0|1|0|N|
+|2|192.168.20.43|0|0|0|0|0|0|0|Y|
+EOF
+simple_test -X all
diff --git a/ctdb/tests/UNIT/tool/ctdb.nodestatus.003.sh b/ctdb/tests/UNIT/tool/ctdb.nodestatus.003.sh
new file mode 100755
index 00000000000..5912e6501aa
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.nodestatus.003.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "all, 3 nodes, 1 unhealthy"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 2 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 UNHEALTHY
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK (THIS NODE)
+EOF
+simple_test all
+
+required_result 2 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|0|1|0|0|0|N|
+|1|192.168.20.42|0|0|0|0|0|0|0|N|
+|2|192.168.20.43|0|0|0|0|0|0|0|Y|
+EOF
+simple_test -X all
diff --git a/ctdb/tests/UNIT/tool/ctdb.nodestatus.004.sh b/ctdb/tests/UNIT/tool/ctdb.nodestatus.004.sh
new file mode 100755
index 00000000000..01ccd5129b4
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.nodestatus.004.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "current, 3 nodes, node 0 unhealthy"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 0 <<EOF
+pnn:2 192.168.20.43 OK (THIS NODE)
+EOF
+simple_test
+
+required_result 0 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|2|192.168.20.43|0|0|0|0|0|0|0|Y|
+EOF
+simple_test -X
diff --git a/ctdb/tests/UNIT/tool/ctdb.nodestatus.005.sh b/ctdb/tests/UNIT/tool/ctdb.nodestatus.005.sh
new file mode 100755
index 00000000000..0cd24ba9cab
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.nodestatus.005.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "current, 3 nodes, node 0 unhealthy, query node 0"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 2 <<EOF
+pnn:0 192.168.20.41 UNHEALTHY
+EOF
+simple_test 0
+
+required_result 2 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|0|1|0|0|0|N|
+EOF
+simple_test -X 0
diff --git a/ctdb/tests/UNIT/tool/ctdb.nodestatus.006.sh b/ctdb/tests/UNIT/tool/ctdb.nodestatus.006.sh
new file mode 100755
index 00000000000..ec189fc4690
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.nodestatus.006.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "current, 3 nodes, node 0 disabled+stopped, various queries"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x24
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 36 <<EOF
+pnn:0 192.168.20.41 DISABLED|STOPPED|INACTIVE
+EOF
+simple_test 0
+
+required_result 36 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|1|0|1|1|0|N|
+EOF
+simple_test -X 0
+
+required_result 36 <<EOF
+pnn:0 192.168.20.41 DISABLED|STOPPED|INACTIVE
+pnn:1 192.168.20.42 OK
+EOF
+simple_test 0,1
+
+required_result 0 <<EOF
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK (THIS NODE)
+EOF
+simple_test 1,2
diff --git a/ctdb/tests/UNIT/tool/ctdb.pdelete.001.sh b/ctdb/tests/UNIT/tool/ctdb.pdelete.001.sh
new file mode 100755
index 00000000000..c0b7c17ac31
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.pdelete.001.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "persistent delete"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "persistent.tdb" persistent
+
+ok_null
+simple_test_other pstore "persistent.tdb" "key1" "value1"
+
+ok_null
+simple_test "persistent.tdb" "key1"
+
+ok_null
+simple_test_other pfetch "persistent.tdb" "key1"
+
+ok "0x2"
+simple_test_other getdbseqnum "persistent.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.ping.001.sh b/ctdb/tests/UNIT/tool/ctdb.ping.001.sh
new file mode 100755
index 00000000000..1e6d7c1808c
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ping.001.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "simple ping"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+result_filter ()
+{
+ sed -e "s@=[.0-9]* sec@=NUM sec@"
+}
+
+
+ok <<EOF
+response from 0 time=NUM sec (1 clients)
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.pnn.001.sh b/ctdb/tests/UNIT/tool/ctdb.pnn.001.sh
new file mode 100755
index 00000000000..a492071aca0
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.pnn.001.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "local and remote nodes"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "0"
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.process-exists.001.sh b/ctdb/tests/UNIT/tool/ctdb.process-exists.001.sh
new file mode 100755
index 00000000000..1b6d213b3ad
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.process-exists.001.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "ctdbd process on node 0"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+dummy_client -s $ctdbd_socket &
+pid=$!
+
+wait_until 10 $CTDB process-exists "$pid"
+
+ok "PID $pid exists"
+simple_test "$pid"
+
+kill -9 $pid
+
+pid=$(ctdbd_getpid)
+required_result 1 "PID $pid does not exist"
+simple_test "$pid"
diff --git a/ctdb/tests/UNIT/tool/ctdb.process-exists.002.sh b/ctdb/tests/UNIT/tool/ctdb.process-exists.002.sh
new file mode 100755
index 00000000000..ace77493565
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.process-exists.002.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "ctdbd process on node 0"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+srvid="0xaebbccdd12345678"
+
+dummy_client -d INFO -s "$ctdbd_socket" -S "$srvid" &
+pid=$!
+
+wait_until 10 $CTDB process-exists "$pid"
+
+srvid2="0x1234567812345678"
+required_result 1 "PID $pid with SRVID $srvid2 does not exist"
+simple_test "$pid" "$srvid2"
+
+ok "PID $pid with SRVID $srvid exists"
+simple_test "$pid" "$srvid"
+
+kill -9 $pid
diff --git a/ctdb/tests/UNIT/tool/ctdb.process-exists.003.sh b/ctdb/tests/UNIT/tool/ctdb.process-exists.003.sh
new file mode 100755
index 00000000000..29c42a1a627
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.process-exists.003.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "ctdbd process with multiple connections on node 0"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+srvid="0xaebbccdd12345678"
+
+dummy_client -d INFO -s "$ctdbd_socket" -n 10 -S "$srvid" &
+pid=$!
+
+wait_until 10 $CTDB process-exists "$pid"
+
+srvid2="0x1234567812345678"
+required_result 1 "PID $pid with SRVID $srvid2 does not exist"
+simple_test "$pid" "$srvid2"
+
+ok "PID $pid with SRVID $srvid exists"
+simple_test "$pid" "$srvid"
+
+kill -9 $pid
diff --git a/ctdb/tests/UNIT/tool/ctdb.pstore.001.sh b/ctdb/tests/UNIT/tool/ctdb.pstore.001.sh
new file mode 100755
index 00000000000..393b5a9891f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.pstore.001.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "persistent store"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "persistent.tdb" persistent
+
+ok_null
+simple_test "persistent.tdb" "key1" "value1"
+
+ok "value1"
+simple_test_other pfetch "persistent.tdb" "key1"
+
+ok "0x1"
+simple_test_other getdbseqnum "persistent.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.ptrans.001.sh b/ctdb/tests/UNIT/tool/ctdb.ptrans.001.sh
new file mode 100755
index 00000000000..40ef1a2d2d4
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.ptrans.001.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "persistent transactions"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "persistent.tdb" persistent
+
+ok_null
+simple_test_other pstore "persistent.tdb" "key0" "value0"
+
+ok_null
+simple_test "persistent.tdb" <<EOF
+"key1" "value1"
+"key2" "value2"
+"key1" ""
+"key2" "value3"
+EOF
+
+ok "value0"
+simple_test_other pfetch "persistent.tdb" "key0"
+
+ok_null
+simple_test_other pfetch "persistent.tdb" "key1"
+
+ok "value3"
+simple_test_other pfetch "persistent.tdb" "key2"
+
+ok "0x2"
+simple_test_other getdbseqnum "persistent.tdb"
+
+ok_null
+simple_test "persistent.tdb" <<EOF
+"key0" "value0"
+EOF
+
+ok "value0"
+simple_test_other pfetch "persistent.tdb" "key0"
+
+ok "0x2"
+simple_test_other getdbseqnum "persistent.tdb"
diff --git a/ctdb/tests/UNIT/tool/ctdb.readkey.001.sh b/ctdb/tests/UNIT/tool/ctdb.readkey.001.sh
new file mode 100755
index 00000000000..e2c58fd3843
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.readkey.001.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "volatile read"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "volatile.tdb"
+
+ok <<EOF
+Data: size:0 ptr:[]
+EOF
+simple_test "volatile.tdb" "key1"
diff --git a/ctdb/tests/UNIT/tool/ctdb.recmaster.001.sh b/ctdb/tests/UNIT/tool/ctdb.recmaster.001.sh
new file mode 100755
index 00000000000..28553046703
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.recmaster.001.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "node 0"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok 0
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.recmaster.002.sh b/ctdb/tests/UNIT/tool/ctdb.recmaster.002.sh
new file mode 100755
index 00000000000..93a9dafcfe5
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.recmaster.002.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "node 2"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 RECMASTER
+EOF
+
+ok 2
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.recover.001.sh b/ctdb/tests/UNIT/tool/ctdb.recover.001.sh
new file mode 100755
index 00000000000..15e05ca0cb5
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.recover.001.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "Just a recovery"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT
+1 192.168.20.42 0x0 RECMASTER
+2 192.168.20.43 0x0
+
+VNNMAP
+654321
+0
+1
+2
+EOF
+
+ok_null
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.001.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.001.sh
new file mode 100755
index 00000000000..68d6cfb5b3b
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.001.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, no change"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok <<EOF
+No change in nodes file, skipping unnecessary reload
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.002.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.002.sh
new file mode 100755
index 00000000000..570786d4e78
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.002.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, no change, inconsistent file on 1"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_nodes 1 <<EOF
+192.168.20.41
+#192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+ERROR: Nodes file on node 1 differs from current node (0)
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.003.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.003.sh
new file mode 100755
index 00000000000..99974d072dd
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.003.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, missing file on 1"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+# fake_ctdbd returns error for empty file
+setup_nodes 1 <<EOF
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+Control GET_NODES_FILE failed, ret=-1
+ERROR: Failed to get nodes file from node 1
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.011.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.011.sh
new file mode 100755
index 00000000000..261962e97e2
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.011.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, add a node"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+192.168.20.44
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+Node 3 is NEW
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.012.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.012.sh
new file mode 100755
index 00000000000..c3ca0fe3911
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.012.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete last node"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+#192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x1
+EOF
+
+required_result 0 <<EOF
+Node 2 is DELETED
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.013.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.013.sh
new file mode 100755
index 00000000000..1402b9dcb6d
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.013.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete connected last node"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+#192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+Node 2 is DELETED
+ERROR: Node 2 is still connected
+ERROR: Nodes will not be reloaded due to previous error
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.014.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.014.sh
new file mode 100755
index 00000000000..30e51485b6f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.014.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete first node"
+
+setup_nodes <<EOF
+#192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x1
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+EOF
+
+required_result 0 <<EOF
+Node 0 is DELETED
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.015.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.015.sh
new file mode 100755
index 00000000000..5fad9ded590
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.015.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete connected first node"
+
+setup_nodes <<EOF
+#192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 CURRENT RECMASTER
+EOF
+
+required_result 1 <<EOF
+Node 0 is DELETED
+ERROR: Node 0 is still connected
+ERROR: Nodes will not be reloaded due to previous error
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.016.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.016.sh
new file mode 100755
index 00000000000..d444a46c85f
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.016.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete middle node"
+
+setup_nodes <<EOF
+192.168.20.41
+#192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x1
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+Node 1 is DELETED
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.017.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.017.sh
new file mode 100755
index 00000000000..b9a969410f6
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.017.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete connected middle node"
+
+setup_nodes <<EOF
+192.168.20.41
+#192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+Node 1 is DELETED
+ERROR: Node 1 is still connected
+ERROR: Nodes will not be reloaded due to previous error
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.018.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.018.sh
new file mode 100755
index 00000000000..30be5961552
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.018.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, add a 3 nodes"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+192.168.20.44
+192.168.20.45
+192.168.20.46
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+Node 3 is NEW
+Node 4 is NEW
+Node 5 is NEW
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.019.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.019.sh
new file mode 100755
index 00000000000..5069485b811
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.019.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete middle, add 2 nodes"
+
+setup_nodes <<EOF
+192.168.20.41
+#192.168.20.42
+192.168.20.43
+192.168.20.44
+192.168.20.45
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x1
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+Node 1 is DELETED
+Node 3 is NEW
+Node 4 is NEW
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.020.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.020.sh
new file mode 100755
index 00000000000..66384c935bb
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.020.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, delete last, add 2 nodes"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+#192.168.20.43
+192.168.20.44
+192.168.20.45
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x1
+EOF
+
+required_result 0 <<EOF
+Node 2 is DELETED
+Node 3 is NEW
+Node 4 is NEW
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.021.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.021.sh
new file mode 100755
index 00000000000..0f5f0d58d46
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.021.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, 1 disconnected, add a node"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+192.168.20.44
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x1
+2 192.168.20.43 0x0
+EOF
+
+required_result 0 <<EOF
+WARNING: Node 1 is disconnected. You MUST fix this node manually!
+Node 3 is NEW
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.023.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.023.sh
new file mode 100755
index 00000000000..b3823d30be4
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.023.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, undelete middle"
+
+setup_nodes <<EOF
+192.168.20.41
+192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x11
+2 192.168.20.43 0x0
+EOF
+
+ok <<EOF
+Node 1 is UNDELETED
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.reloadnodes.024.sh b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.024.sh
new file mode 100755
index 00000000000..9aa0d4255e6
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.reloadnodes.024.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "3 nodes, middle node remains deleted"
+
+setup_nodes <<EOF
+192.168.20.41
+#192.168.20.42
+192.168.20.43
+EOF
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x11
+2 192.168.20.43 0x0
+EOF
+
+ok <<EOF
+No change in nodes file, skipping unnecessary reload
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.runstate.001.sh b/ctdb/tests/UNIT/tool/ctdb.runstate.001.sh
new file mode 100755
index 00000000000..d9559bdaf2e
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.runstate.001.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "get runstate, should be RUNNING"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "RUNNING"
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.runstate.002.sh b/ctdb/tests/UNIT/tool/ctdb.runstate.002.sh
new file mode 100755
index 00000000000..b75b2ecd2ce
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.runstate.002.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "check if RUNNING"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "RUNNING"
+simple_test "RUNNING"
diff --git a/ctdb/tests/UNIT/tool/ctdb.runstate.003.sh b/ctdb/tests/UNIT/tool/ctdb.runstate.003.sh
new file mode 100755
index 00000000000..eba41f8ce30
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.runstate.003.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "check non-RUNNING states"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+for i in "INIT" "SETUP" "FIRST_RECOVERY" "STARTUP" "SHUTDOWN" ; do
+ required_result 1 "CTDB not in required run state (got RUNNING)"
+ simple_test "$i"
+done
diff --git a/ctdb/tests/UNIT/tool/ctdb.runstate.004.sh b/ctdb/tests/UNIT/tool/ctdb.runstate.004.sh
new file mode 100755
index 00000000000..666e84d5c30
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.runstate.004.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "check invalid state"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 "Invalid run state (foobar)"
+simple_test "foobar"
diff --git a/ctdb/tests/UNIT/tool/ctdb.runstate.005.sh b/ctdb/tests/UNIT/tool/ctdb.runstate.005.sh
new file mode 100755
index 00000000000..972783c39e0
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.runstate.005.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "check from multiple states"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "RUNNING"
+simple_test "STARTUP" "RUNNING"
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.001.sh b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.001.sh
new file mode 100755
index 00000000000..0a0cfe2c922
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.001.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set volatile non-read-only to read-only by ID"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok_null
+simple_test 0x7a19d84d
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb READONLY
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
+
+ok_null
+simple_test 0x7a19d84d
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb READONLY
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.002.sh b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.002.sh
new file mode 100755
index 00000000000..246fb60503b
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.002.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set volatile non-read-only to read-only by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok_null
+simple_test locking.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb READONLY
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.003.sh b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.003.sh
new file mode 100755
index 00000000000..3a11c791c05
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.003.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set persistent read-only by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+required_result 1 <<EOF
+READONLY can be set only on volatile DB
+EOF
+simple_test secrets.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.004.sh b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.004.sh
new file mode 100755
index 00000000000..5d6561dca02
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.004.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set volatile sticky to sticky and read-only by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb STICKY
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok_null
+simple_test locking.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb STICKY READONLY
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.005.sh b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.005.sh
new file mode 100755
index 00000000000..ae336dd8bac
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbreadonly.005.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set replicated read-only by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+required_result 1 <<EOF
+READONLY can be set only on volatile DB
+EOF
+simple_test ctdb-ip.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbsticky.001.sh b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.001.sh
new file mode 100755
index 00000000000..28cbfd747b6
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.001.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set volatile non-sticky to sticky by ID"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok_null
+simple_test 0x4e66c2b2
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb STICKY
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
+
+ok_null
+simple_test 0x4e66c2b2
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb STICKY
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbsticky.002.sh b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.002.sh
new file mode 100755
index 00000000000..1c39f54b221
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.002.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set volatile non-sticky to sticky by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok_null
+simple_test brlock.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb STICKY
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbsticky.003.sh b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.003.sh
new file mode 100755
index 00000000000..206fed94fd3
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.003.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set persistent sticky by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+required_result 1 <<EOF
+STICKY can be set only on volatile DB
+EOF
+simple_test secrets.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbsticky.004.sh b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.004.sh
new file mode 100755
index 00000000000..a322a57b923
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.004.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set volatile read-only to read-only and sticky by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb READONLY
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+ok_null
+simple_test brlock.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb STICKY READONLY
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdbsticky.005.sh b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.005.sh
new file mode 100755
index 00000000000..9a9bec1bd58
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdbsticky.005.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "set replicated sticky by name"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+DBMAP
+0x7a19d84d locking.tdb
+0x4e66c2b2 brlock.tdb
+0x4d2a432b g_lock.tdb
+0x7132c184 secrets.tdb PERSISTENT
+0x6cf2837d registry.tdb PERSISTENT 42
+0xbc57b384 ctdb-ip.tdb REPLICATED
+0xbec75f0b ctdb-conn.tdb REPLICATED 23
+EOF
+
+required_result 1 <<EOF
+STICKY can be set only on volatile DB
+EOF
+simple_test ctdb-ip.tdb
+
+ok <<EOF
+Number of databases:7
+dbid:0x7a19d84d name:locking.tdb path:${ctdbd_dbdir}/locking.tdb
+dbid:0x4e66c2b2 name:brlock.tdb path:${ctdbd_dbdir}/brlock.tdb
+dbid:0x4d2a432b name:g_lock.tdb path:${ctdbd_dbdir}/g_lock.tdb
+dbid:0x7132c184 name:secrets.tdb path:${ctdbd_dbdir}/secrets.tdb PERSISTENT
+dbid:0x6cf2837d name:registry.tdb path:${ctdbd_dbdir}/registry.tdb PERSISTENT
+dbid:0xbc57b384 name:ctdb-ip.tdb path:${ctdbd_dbdir}/ctdb-ip.tdb REPLICATED
+dbid:0xbec75f0b name:ctdb-conn.tdb path:${ctdbd_dbdir}/ctdb-conn.tdb REPLICATED
+EOF
+
+simple_test_other getdbmap
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdebug.001.sh b/ctdb/tests/UNIT/tool/ctdb.setdebug.001.sh
new file mode 100755
index 00000000000..bec32a334ea
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdebug.001.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "bogus debug level string, ensure no change"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+orig=$($CTDB -d $CTDB_DEBUGLEVEL getdebug)
+
+required_result 1 <<EOF
+Invalid debug level 'foobar'. Valid levels are:
+ ERROR | WARNING | NOTICE | INFO | DEBUG
+EOF
+simple_test foobar
+
+ok "$orig"
+simple_test_other getdebug
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdebug.002.sh b/ctdb/tests/UNIT/tool/ctdb.setdebug.002.sh
new file mode 100755
index 00000000000..7819b0b450a
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdebug.002.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "bogus debug level integer, ensure no change"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+orig=$($CTDB -d $CTDB_DEBUGLEVEL getdebug)
+
+required_result 1 <<EOF
+Invalid debug level '42'. Valid levels are:
+ ERROR | WARNING | NOTICE | INFO | DEBUG
+EOF
+simple_test 42
+
+ok "$orig"
+simple_test_other getdebug
diff --git a/ctdb/tests/UNIT/tool/ctdb.setdebug.003.sh b/ctdb/tests/UNIT/tool/ctdb.setdebug.003.sh
new file mode 100755
index 00000000000..2a8be1892da
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setdebug.003.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "all possible legal levels, including some abbreviations"
+
+debug_set_result ()
+{
+ case "$1" in
+ 0|ERR*) ok "ERROR" ;;
+ 1|2|WARN*) ok "WARNING" ;;
+ 3|4|NOTICE) ok "NOTICE" ;;
+ 5|6|7|8|9|INFO) ok "INFO" ;;
+ 10|DEBUG) ok "DEBUG" ;;
+ *) required_result 42 "foo" ;;
+ esac
+}
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+for i in "ERROR" "WARNING" "NOTICE" "INFO" "DEBUG" $(seq 0 10) "ERR" "WARN" ; do
+ ok_null
+ simple_test "$i"
+
+ debug_set_result "$i"
+ simple_test_other getdebug
+done
diff --git a/ctdb/tests/UNIT/tool/ctdb.setifacelink.001.sh b/ctdb/tests/UNIT/tool/ctdb.setifacelink.001.sh
new file mode 100755
index 00000000000..53104cfc1b1
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setifacelink.001.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "toggle state of 2 interfaces"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:0:4:
+EOF
+
+# eth1: down -> down
+
+ok_null
+simple_test eth1 down
+
+ok <<EOF
+Interfaces on node 0
+name:eth2 link:up references:2
+name:eth1 link:down references:4
+EOF
+simple_test_other ifaces
+
+# eth1: down -> up
+
+ok_null
+simple_test eth1 up
+
+ok <<EOF
+Interfaces on node 0
+name:eth2 link:up references:2
+name:eth1 link:up references:4
+EOF
+simple_test_other ifaces
+
+# eth1: up -> down
+ok_null
+simple_test eth1 down
+
+ok <<EOF
+Interfaces on node 0
+name:eth2 link:up references:2
+name:eth1 link:down references:4
+EOF
+simple_test_other ifaces
+
+# eth2: up -> down
+
+ok_null
+simple_test eth2 down
+
+ok <<EOF
+Interfaces on node 0
+name:eth2 link:down references:2
+name:eth1 link:down references:4
+EOF
+simple_test_other ifaces
+
+# eth1: down -> up
+
+ok_null
+simple_test eth1 up
+
+ok <<EOF
+Interfaces on node 0
+name:eth2 link:down references:2
+name:eth1 link:up references:4
+EOF
+simple_test_other ifaces
diff --git a/ctdb/tests/UNIT/tool/ctdb.setifacelink.002.sh b/ctdb/tests/UNIT/tool/ctdb.setifacelink.002.sh
new file mode 100755
index 00000000000..a27062ed055
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setifacelink.002.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "invalid interface"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:0:4:
+EOF
+
+required_result 1 <<EOF
+Interface eth0 not configured on node 0
+EOF
+simple_test eth0 down
diff --git a/ctdb/tests/UNIT/tool/ctdb.setvar.001.sh b/ctdb/tests/UNIT/tool/ctdb.setvar.001.sh
new file mode 100755
index 00000000000..e11ff9c8205
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setvar.001.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "get a variable, change its value"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+# Squash whitespace for predictable output
+result_filter ()
+{
+ sed -e 's|[[:space:]][[:space:]]*| |g'
+}
+
+$CTDB -d $CTDB_DEBUGLEVEL listvars |
+ tail -n 1 |
+ {
+ read variable equals value
+
+ # Increment original variable
+ newvalue=$((value + 1))
+ ok_null
+ simple_test "$variable" "$newvalue"
+
+ ok "${variable} = ${newvalue}"
+ simple_test_other getvar "$variable"
+
+ # Increment uppercase variable
+ v_upper=$(echo "$variable" | tr "a-z" "A-Z")
+ newvalue=$((newvalue + 1))
+ ok_null
+ simple_test "$v_upper" "$newvalue"
+
+ ok "${variable} = ${newvalue}"
+ simple_test_other getvar "$variable"
+
+ # Put back original, lowercase
+ v_lower=$(echo "$variable" | tr "A-Z" "a-z")
+ ok_null
+ simple_test "$v_lower" "$value"
+
+ ok "${variable} = ${value}"
+ simple_test_other getvar "$variable"
+ }
diff --git a/ctdb/tests/UNIT/tool/ctdb.setvar.002.sh b/ctdb/tests/UNIT/tool/ctdb.setvar.002.sh
new file mode 100755
index 00000000000..bf788a27fca
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.setvar.002.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "invalid variable"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+required_result 1 <<EOF
+No such tunable TheQuickBrownFoxJumpsOverTheLazyDog
+EOF
+simple_test "TheQuickBrownFoxJumpsOverTheLazyDog" 42
diff --git a/ctdb/tests/UNIT/tool/ctdb.status.001.sh b/ctdb/tests/UNIT/tool/ctdb.status.001.sh
new file mode 100755
index 00000000000..13324ef0dd9
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.status.001.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "all, 3 nodes, all ok"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+
+VNNMAP
+654321
+0
+1
+2
+EOF
+
+required_result 0 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+Generation:654321
+Size:3
+hash:0 lmaster:0
+hash:1 lmaster:1
+hash:2 lmaster:2
+Recovery mode:NORMAL (0)
+Recovery master:0
+EOF
+simple_test
+
+required_result 0 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|0|0|0|0|0|Y|
+|1|192.168.20.42|0|0|0|0|0|0|0|N|
+|2|192.168.20.43|0|0|0|0|0|0|0|N|
+EOF
+simple_test -X
diff --git a/ctdb/tests/UNIT/tool/ctdb.status.002.sh b/ctdb/tests/UNIT/tool/ctdb.status.002.sh
new file mode 100755
index 00000000000..3fd8d1cf711
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.status.002.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "all, 3 nodes, 1 unhealthy"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x2
+1 192.168.20.42 0x0 CURRENT RECMASTER
+2 192.168.20.43 0x0
+
+VNNMAP
+654321
+0
+1
+2
+
+IFACES
+:Name:LinkStatus:References:
+:eth2:1:2:
+:eth1:1:4:
+EOF
+
+required_result 0 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 UNHEALTHY
+pnn:1 192.168.20.42 OK (THIS NODE)
+pnn:2 192.168.20.43 OK
+Generation:654321
+Size:3
+hash:0 lmaster:0
+hash:1 lmaster:1
+hash:2 lmaster:2
+Recovery mode:NORMAL (0)
+Recovery master:1
+EOF
+simple_test
+
+required_result 0 <<EOF
+|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|
+|0|192.168.20.41|0|0|0|1|0|0|0|N|
+|1|192.168.20.42|0|0|0|0|0|0|0|Y|
+|2|192.168.20.43|0|0|0|0|0|0|0|N|
+EOF
+simple_test -X
diff --git a/ctdb/tests/UNIT/tool/ctdb.stop.001.sh b/ctdb/tests/UNIT/tool/ctdb.stop.001.sh
new file mode 100755
index 00000000000..d374ebf946d
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.stop.001.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "stop default (0)"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test
+
+required_result 32 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 STOPPED|INACTIVE (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.stop.002.sh b/ctdb/tests/UNIT/tool/ctdb.stop.002.sh
new file mode 100755
index 00000000000..f8cc79299c5
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.stop.002.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "stop 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test -n 1
+
+required_result 32 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 STOPPED|INACTIVE
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.stop.003.sh b/ctdb/tests/UNIT/tool/ctdb.stop.003.sh
new file mode 100755
index 00000000000..3e4981c0f05
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.stop.003.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "node is already stopped"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x20
+EOF
+
+ok "Node 2 is already stopped"
+simple_test -n 2
+
+required_result 32 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 STOPPED|INACTIVE
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.unban.001.sh b/ctdb/tests/UNIT/tool/ctdb.unban.001.sh
new file mode 100755
index 00000000000..c771fb4d199
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.unban.001.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "unban default (0)"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x8 CURRENT
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0 RECMASTER
+EOF
+
+ok_null
+simple_test
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.unban.002.sh b/ctdb/tests/UNIT/tool/ctdb.unban.002.sh
new file mode 100755
index 00000000000..b65143d4a3b
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.unban.002.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "ban, unban node 1"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other ban 60 -n 1
+
+required_result 8 <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 BANNED|INACTIVE
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
+
+ok_null
+simple_test_other unban -n 1
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.unban.003.sh b/ctdb/tests/UNIT/tool/ctdb.unban.003.sh
new file mode 100755
index 00000000000..8b94f3011ba
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.unban.003.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "node not banned"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok "Node 0 is not banned"
+simple_test
+
+ok <<EOF
+Number of nodes:3
+pnn:0 192.168.20.41 OK (THIS NODE)
+pnn:1 192.168.20.42 OK
+pnn:2 192.168.20.43 OK
+EOF
+simple_test_other nodestatus all
diff --git a/ctdb/tests/UNIT/tool/ctdb.uptime.001.sh b/ctdb/tests/UNIT/tool/ctdb.uptime.001.sh
new file mode 100755
index 00000000000..34fd1f4ebd7
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.uptime.001.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "simple ping"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+result_filter ()
+{
+ _weekday="[A-Z][a-z][a-z]"
+ _month="[A-Z][a-z][a-z]"
+ _date="[0-9][0-9]*"
+ _time="[0-9][0-9]:[0-9][0-9]:[0-9][0-9]"
+ _year="[0-9][0-9]*"
+ _date_time="${_weekday} ${_month} *${_date} ${_time} ${_year}"
+ _duration="(000 00:00:[0-9][0-9])"
+ sed -e "s|${_date_time}\$|DATE/TIME|" \
+ -e "s|[.0-9]* seconds|SEC seconds|" \
+ -e "s|${_duration}|(DURATION)|"
+}
+
+
+ok <<EOF
+Current time of node 0 : DATE/TIME
+Ctdbd start time : (DURATION) DATE/TIME
+Time of last recovery/failover: (DURATION) DATE/TIME
+Duration of last recovery/failover: SEC seconds
+EOF
+
+simple_test
diff --git a/ctdb/tests/UNIT/tool/ctdb.writekey.001.sh b/ctdb/tests/UNIT/tool/ctdb.writekey.001.sh
new file mode 100755
index 00000000000..7adee9fb98d
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/ctdb.writekey.001.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+define_test "volatile write"
+
+setup_ctdbd <<EOF
+NODEMAP
+0 192.168.20.41 0x0 CURRENT RECMASTER
+1 192.168.20.42 0x0
+2 192.168.20.43 0x0
+EOF
+
+ok_null
+simple_test_other attach "volatile.tdb"
+
+ok_null
+simple_test "volatile.tdb" "key1" "value1"
+
+ok <<EOF
+Data: size:6 ptr:[value1]
+EOF
+simple_test_other readkey "volatile.tdb" "key1"
+
+ok_null
+simple_test "volatile.tdb" "key1" "a new value"
+
+ok <<EOF
+Data: size:11 ptr:[a new value]
+EOF
+simple_test_other readkey "volatile.tdb" "key1"
diff --git a/ctdb/tests/UNIT/tool/scripts/local.sh b/ctdb/tests/UNIT/tool/scripts/local.sh
new file mode 100644
index 00000000000..61313504f11
--- /dev/null
+++ b/ctdb/tests/UNIT/tool/scripts/local.sh
@@ -0,0 +1,114 @@
+# Hey Emacs, this is a -*- shell-script -*- !!! :-)
+
+PATH="${PATH}:${CTDB_SCRIPTS_TOOLS_HELPER_DIR}"
+PATH="${PATH}:${CTDB_SCRIPTS_HELPER_BINDIR}"
+
+setup_ctdb_base "$CTDB_TEST_TMP_DIR" "ctdb-etc" \
+ functions
+
+if "$TEST_VERBOSE" ; then
+ debug () { echo "$@" ; }
+else
+ debug () { : ; }
+fi
+
+ctdbd_socket=$(ctdb-path socket "ctdbd")
+ctdbd_pidfile=$(ctdb-path pidfile "ctdbd")
+ctdbd_dbdir=$(ctdb-path vardir append "db")
+
+define_test ()
+{
+ _f=$(basename "$0" ".sh")
+
+ case "$_f" in
+ ctdb.*)
+ _cmd="${_f#ctdb.}"
+ _cmd="${_cmd%.*}" # Strip test number
+ export CTDB="ctdb"
+ export CTDB_DEBUGLEVEL=NOTICE
+ if [ -z "$FAKE_CTDBD_DEBUGLEVEL" ] ; then
+ FAKE_CTDBD_DEBUGLEVEL="ERR"
+ fi
+ export FAKE_CTDBD_DEBUGLEVEL
+ test_args="$_cmd"
+ ;;
+ *)
+ die "Unknown pattern for testcase \"$_f\""
+ esac
+
+ printf "%-28s - %s\n" "$_f" "$1"
+}
+
+cleanup_ctdbd ()
+{
+ debug "Cleaning up fake ctdbd"
+
+ pid=$(cat "$ctdbd_pidfile" 2>/dev/null || echo)
+ if [ -n "$pid" ] ; then
+ kill $pid || true
+ rm -f "$ctdbd_pidfile"
+ fi
+ rm -f "$ctdbd_socket"
+ rm -rf "$ctdbd_dbdir"
+}
+
+setup_ctdbd ()
+{
+ echo "Setting up fake ctdbd"
+
+ mkdir -p "$ctdbd_dbdir"
+ $VALGRIND fake_ctdbd -d "$FAKE_CTDBD_DEBUGLEVEL" \
+ -s "$ctdbd_socket" -p "$ctdbd_pidfile" \
+ -D "$ctdbd_dbdir"
+ # Wait till fake_ctdbd is running
+ wait_until 10 test -S "$ctdbd_socket" || \
+ die "fake_ctdbd failed to start"
+
+ test_cleanup cleanup_ctdbd
+}
+
+ctdbd_getpid ()
+{
+ cat "$ctdbd_pidfile"
+}
+
+setup_natgw ()
+{
+ debug "Setting up NAT gateway"
+
+ export CTDB_NATGW_HELPER="${CTDB_SCRIPTS_TOOLS_HELPER_DIR}/ctdb_natgw"
+ export CTDB_NATGW_NODES="${CTDB_BASE}/natgw_nodes"
+
+ cat >"$CTDB_NATGW_NODES"
+}
+
+setup_lvs ()
+{
+ debug "Setting up LVS"
+
+ export CTDB_LVS_HELPER="${CTDB_SCRIPTS_TOOLS_HELPER_DIR}/ctdb_lvs"
+ export CTDB_LVS_NODES="${CTDB_BASE}/lvs_nodes"
+
+ cat >"$CTDB_LVS_NODES"
+}
+
+setup_nodes ()
+{
+ _pnn="$1"
+
+ _f="${CTDB_BASE}/nodes${_pnn:+.}${_pnn}"
+
+ cat >"$_f"
+}
+
+simple_test_other ()
+{
+ (unit_test $CTDB -d $CTDB_DEBUGLEVEL "$@")
+ status=$?
+ [ $status -eq 0 ] || exit $status
+}
+
+simple_test ()
+{
+ simple_test_other $test_args "$@"
+}