]> git.proxmox.com Git - ovs.git/blobdiff - tests/ovsdb-server.at
System tests: Enable ALGs for userspace.
[ovs.git] / tests / ovsdb-server.at
index 800506bb319f5b578a3b301c2b58d1865c1da186..e72a65b4847b6b37791b88dcca2e7bcaa8959069 100644 (file)
@@ -1,9 +1,12 @@
 AT_BANNER([OVSDB -- ovsdb-server transactions (Unix sockets)])
 
-m4_define([OVSDB_SERVER_SHUTDOWN], 
-  [cp pid savepid
-   AT_CHECK([ovs-appctl -t $PWD/unixctl -e exit], [0], [ignore], [ignore])
-   OVS_WAIT_WHILE([kill -0 `cat savepid`], [kill `cat savepid`])])
+m4_define([OVSDB_SERVER_SHUTDOWN],
+  [OVS_APP_EXIT_AND_WAIT_BY_TARGET([ovsdb-server], [ovsdb-server.pid])])
+
+m4_define([OVSDB_SERVER_SHUTDOWN2],
+  [cp pid2 savepid2
+   AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 -e exit], [0], [ignore], [ignore])
+   OVS_WAIT_WHILE([kill -0 `cat savepid2`], [kill `cat savepid2`])])
 
 # OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
 #
@@ -22,82 +25,487 @@ m4_define([OVSDB_SERVER_SHUTDOWN],
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive unix $5])
-   AT_DATA([schema], [$2
-])
+   $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
-   AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --remote=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore])
+   AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db], [0], [ignore], [ignore])
    m4_foreach([txn], [$3], 
      [AT_CHECK([ovsdb-client transact unix:socket 'txn'], [0], [stdout], [ignore],
      [test ! -e pid || kill `cat pid`])
 cat stdout >> output
 ])
-   AT_CHECK([perl $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
             [test ! -e pid || kill `cat pid`])
    OVSDB_SERVER_SHUTDOWN
    AT_CLEANUP])
 
 EXECUTION_EXAMPLES
 \f
-AT_SETUP([database multiplexing implementation])
+AT_BANNER([ovsdb-server miscellaneous features])
+
+AT_SETUP([truncating corrupted database log])
+AT_KEYWORDS([ovsdb server positive unix])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+dnl Do one transaction and save the output.
+AT_DATA([txnfile], [[ovsdb-client transact unix:socket \
+'["ordinals",
+  {"op": "insert",
+   "table": "ordinals",
+   "row": {"number": 0, "name": "zero"}}]'
+]])
+AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [])
+cat stdout >> output
+dnl Add some crap to the database log and run another transaction, which should
+dnl ignore the crap and truncate it out of the log.
+echo 'xxx' >> db
+AT_DATA([txnfile], [[ovsdb-client transact unix:socket \
+'["ordinals",
+  {"op": "insert",
+   "table": "ordinals",
+   "row": {"number": 1, "name": "one"}}]'
+]])
+AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [stderr])
+AT_CHECK([grep 'syntax error: db: parse error.* in header line "xxx"' stderr],
+  [0], [ignore])
+cat stdout >> output
+dnl Run a final transaction to verify that both transactions succeeeded.
+dnl The crap that we added should have been truncated by the previous run,
+dnl so ovsdb-server shouldn't log a warning this time.
+AT_DATA([txnfile], [[ovsdb-client transact unix:socket \
+'["ordinals",
+  {"op": "select",
+   "table": "ordinals",
+   "where": [],
+   "sort": ["number"]}]'
+]])
+AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0],
+  [[[{"uuid":["uuid","<0>"]}]
+[{"uuid":["uuid","<1>"]}]
+[{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<2>"],"name":"zero","number":0},{"_uuid":["uuid","<1>"],"_version":["uuid","<3>"],"name":"one","number":1}]}]
+]], [],
+         [test ! -e pid || kill `cat pid`])
+AT_CLEANUP
+
+AT_SETUP([truncating database log with bad transaction])
+AT_KEYWORDS([ovsdb server positive unix])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+dnl Do one transaction and save the output.
+AT_DATA([txnfile], [[ovsdb-client transact unix:socket \
+'["ordinals",
+  {"op": "insert",
+   "table": "ordinals",
+   "row": {"number": 0, "name": "zero"}}]'
+]])
+AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [])
+cat stdout >> output
+dnl Add some crap to the database log and run another transaction, which should
+dnl ignore the crap and truncate it out of the log.
+echo 'OVSDB JSON 15 ffbcdae4b0386265f9ea3280dd7c8f0b72a20e56
+{"invalid":{}}' >> db
+AT_DATA([txnfile], [[ovsdb-client transact unix:socket \
+'["ordinals",
+  {"op": "insert",
+   "table": "ordinals",
+   "row": {"number": 1, "name": "one"}}]'
+]])
+AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [stderr])
+AT_CHECK([grep 'syntax "{"invalid":{}}": unknown table: No table named invalid.' stderr],
+  [0], [ignore])
+cat stdout >> output
+dnl Run a final transaction to verify that both transactions succeeeded.
+dnl The crap that we added should have been truncated by the previous run,
+dnl so ovsdb-server shouldn't log a warning this time.
+AT_DATA([txnfile], [[ovsdb-client transact unix:socket \
+'["ordinals",
+  {"op": "select",
+   "table": "ordinals",
+   "where": [],
+   "sort": ["number"]}]'
+]])
+AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0],
+  [[[{"uuid":["uuid","<0>"]}]
+[{"uuid":["uuid","<1>"]}]
+[{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<2>"],"name":"zero","number":0},{"_uuid":["uuid","<1>"],"_version":["uuid","<3>"],"name":"one","number":1}]}]
+]], [],
+         [test ! -e pid || kill `cat pid`])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-client get-schema-version])
 AT_KEYWORDS([ovsdb server positive])
-AT_DATA([schema], [ORDINAL_SCHEMA
-])
+ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
-AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --unixctl=$PWD/unixctl --remote=punix:socket db], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client get-schema-version unix:socket ordinals], [0], [5.1.3
+])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
+
+AT_SETUP([database multiplexing implementation])
+AT_KEYWORDS([ovsdb server positive])
+ordinal_schema > schema1
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db1 db2], [0], [ignore], [ignore])
 AT_CHECK(
   [[ovsdb-client list-dbs unix:socket]], 
-  [0], [ordinals
+  [0], [constraints
+ordinals
 ], [ignore], [test ! -e pid || kill `cat pid`])
 AT_CHECK(
-  [[ovsdb-client get-schema unix:socket nonexistent]], 
-  [1], [], [[ovsdb-client: syntax "{"syntax":"[\"nonexistent\"]","details":"get_schema request specifies unknown database nonexistent","error":"unknown database"}": syntax error: Parsing database schema failed: Required 'name' member is missing.
-]], [test ! -e pid || kill `cat pid`])
+  [[ovstest test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0],
+  [[{"error":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"},"id":0,"result":null}
+]], [], [test ! -e pid || kill `cat pid`])
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
 
+AT_SETUP([ovsdb-server/add-db and remove-db])
+AT_KEYWORDS([ovsdb server positive])
+on_exit 'kill `cat ovsdb-server.pid`'
+ordinal_schema > schema1
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+
+# Start ovsdb-server with just a single database - db1.
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db1], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [ordinals
+])
+
+# Add the second database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [constraints
+ordinals
+])
+
+# The databases are responsive.
+AT_CHECK([ovsdb-client list-tables unix:socket constraints], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [0], [ignore], [ignore])
+
+# Add an already added database.
+if test $IS_WIN32 = "yes"; then
+  AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], 2, [],
+  [I/O error: db2: failed to lock lockfile (Resource deadlock avoided)
+ovs-appctl: ovsdb-server: server returned an error
+])
+else
+  AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], 2, [],
+  [db2: already open
+ovs-appctl: ovsdb-server: server returned an error
+])
+fi
+
+# Add a non-existing database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db3], 2, [], [stderr])
+AT_CHECK([sed 's/(.*)/(...)/' stderr], [0],
+  [I/O error: db3: open failed (...)
+ovs-appctl: ovsdb-server: server returned an error
+])
+
+# Add a remote through a db path in db1.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote db:ordinals,ordinals,name], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [db:ordinals,ordinals,name
+punix:socket
+])
+
+# Removing db1 has no effect on its remote.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db ordinals], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [constraints
+])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [db:ordinals,ordinals,name
+punix:socket
+])
+AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [1], [ignore], [ignore])
+
+# Remove db2.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db constraints], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [])
+AT_CHECK([ovsdb-client list-tables unix:socket constraints], [1], [ignore], [ignore])
+
+# Remove a non-existent database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db ordinals], [2],
+  [], [Failed to find the database.
+ovs-appctl: ovsdb-server: server returned an error
+])
+
+# Add a removed database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [constraints
+])
+AT_CHECK([ovsdb-client list-tables unix:socket constraints], [0], [ignore], [ignore])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/add-db with --monitor])
+AT_KEYWORDS([ovsdb server positive])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+# Start ovsdb-server, initially with one db.
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1])
+
+# Add the second database.
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [constraints
+ordinals
+])
+
+# Kill the daemon process, making it look like a segfault,
+# and wait for a new daemon process to get spawned.
+cp ovsdb-server.pid old.pid
+AT_CHECK([kill -SEGV `cat ovsdb-server.pid`])
+OVS_WAIT_WHILE([kill -0 `cat old.pid`])
+OVS_WAIT_UNTIL(
+  [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])
+OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [constraints
+ordinals
+])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/add-db and remove-db with --monitor])
+AT_KEYWORDS([ovsdb server positive])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+# Start ovsdb-server, initially with one db.
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1 db2])
+
+# Remove the second database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db constraints])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [ordinals
+])
+
+# Kill the daemon process, making it look like a segfault,
+# and wait for a new daemon process to get spawned.
+cp ovsdb-server.pid old.pid
+AT_CHECK([kill -SEGV `cat ovsdb-server.pid`])
+OVS_WAIT_WHILE([kill -0 `cat old.pid`])
+OVS_WAIT_UNTIL(
+  [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])
+OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [ordinals
+])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
 AT_SETUP([--remote=db: implementation])
 AT_KEYWORDS([ovsdb server positive])
 AT_DATA([schema],
   [[{"name": "mydb",
      "tables": {
+       "Root": {
+         "columns": {
+           "managers": {
+             "type": {
+               "key": "string",
+               "min": 0,
+               "max": "unlimited"}},
+           "manager_options": {
+             "type": {
+               "key": {"type": "uuid", "refTable": "Manager"},
+               "min": 0,
+               "max": "unlimited"}}}},
        "Manager": {
          "columns": {
-           "manager": {"type": "string"}}}}}
+           "target": {
+             "type": "string"},
+           "is_connected": {
+             "type": {
+               "key": "boolean",
+               "min": 0,
+               "max": 1}}}}}}
 ]])
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
 AT_CHECK(
   [[ovsdb-tool transact db \
      '["mydb",
+       {"op": "insert",
+        "table": "Root",
+        "row": {
+          "managers": "punix:socket1",
+          "manager_options": ["set", [["named-uuid", "x"]]]}},
        {"op": "insert",
         "table": "Manager",
-        "row": {"manager": "punix:socket"}}]']], [0], [ignore], [ignore])
-AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --remote=db:Manager,manager --unixctl=$PWD/unixctl db], [0], [ignore], [ignore])
+        "uuid-name": "x",
+        "row": {"target": "punix:socket2"}}]']], [0], [ignore], [ignore])
+on_exit 'kill `cat ovsdb-server.pid`'
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=db:mydb,Root,managers --remote=db:mydb,Root,manager_options --log-file db], [0], [ignore], [ignore])
+ovs-appctl -t ovsdb-server time/warp 6000 1000
 AT_CHECK(
-  [[ovsdb-client transact unix:socket \
+  [[ovsdb-client transact unix:socket1 \
      '["mydb",
+       {"op": "select",
+        "table": "Root",
+        "where": [],
+        "columns": ["managers"]},
        {"op": "select",
         "table": "Manager",
         "where": [],
-        "columns": ["manager"]}]']], 
-  [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`])
+        "columns": ["target", "is_connected"]}]']],
+  [0], [stdout], [ignore])
 AT_CHECK(
-  [perl $srcdir/uuidfilt.pl stdout], 
+  [${PERL} $srcdir/uuidfilt.pl stdout], 
   [0], 
-  [[[{"rows":[{"manager":"punix:socket"}]}]
+  [[[{"rows":[{"managers":"punix:socket1"}]},{"rows":[{"is_connected":false,"target":"punix:socket2"}]}]
 ]], 
-  [ignore], 
-  [test ! -e pid || kill `cat pid`])
-OVSDB_SERVER_SHUTDOWN
+  [ignore])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/add-remote and remove-remote])
+AT_KEYWORDS([ovsdb server positive])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile db])
+
+AT_CHECK([test ! -e socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote punix:socket1])
+if test "$IS_WIN32" = "yes"; then
+  OVS_WAIT_UNTIL([test -e socket1])
+else
+  OVS_WAIT_UNTIL([test -S socket1])
+fi
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [punix:socket1
+])
+
+AT_CHECK([test ! -e socket2])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote punix:socket2])
+if test "$IS_WIN32" = "yes"; then
+  OVS_WAIT_UNTIL([test -e socket2])
+else
+  OVS_WAIT_UNTIL([test -S socket2])
+fi
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [punix:socket1
+punix:socket2
+])
+
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote db:x,y,z], [2],
+  [], ["db:x,y,z": no database named x
+ovs-appctl: ovsdb-server: server returned an error
+])
+
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-remote punix:socket1])
+OVS_WAIT_UNTIL([test ! -e socket1])
+if test "$IS_WIN32" = "yes"; then
+  AT_CHECK([test -e socket2])
+else
+  AT_CHECK([test -S socket2])
+fi
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [punix:socket2
+])
+
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-remote punix:socket2])
+OVS_WAIT_UNTIL([test ! -e socket2])
+AT_CHECK([test ! -e socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/add-remote with --monitor])
+AT_KEYWORDS([ovsdb server positive])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+# Start ovsdb-server, initially with no remotes.
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db])
+
+# Add a remote.
+AT_CHECK([test ! -e socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote punix:socket1])
+OVS_WAIT_UNTIL([test -S socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [punix:socket1
+])
+
+# Kill the daemon process, making it look like a segfault,
+# and wait for a new daemon process to get spawned and for it to
+# start listening on 'socket1'.
+cp ovsdb-server.pid old.pid
+rm socket1
+AT_CHECK([kill -SEGV `cat ovsdb-server.pid`])
+OVS_WAIT_WHILE([kill -0 `cat old.pid`])
+OVS_WAIT_UNTIL(
+  [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])
+OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])
+OVS_WAIT_UNTIL([test -S socket1])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/add-remote and remove-remote with --monitor])
+AT_KEYWORDS([ovsdb server positive])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+# Start ovsdb-server, initially with no remotes.
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db])
+
+# Add a remote.
+AT_CHECK([test ! -e socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote punix:socket1])
+OVS_WAIT_UNTIL([test -S socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [punix:socket1
+])
+
+# Remove the remote.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-remote punix:socket1])
+OVS_WAIT_UNTIL([test ! -e socket1])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes])
+
+# Kill the daemon process, making it look like a segfault,
+# and wait for a new daemon process to get spawned and make sure that it
+# does not listen on 'socket1'.
+cp ovsdb-server.pid old.pid
+AT_CHECK([kill -SEGV `cat ovsdb-server.pid`])
+OVS_WAIT_WHILE([kill -0 `cat old.pid`])
+OVS_WAIT_UNTIL(
+  [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])
+OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])
+AT_CHECK([test ! -e socket1])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
 AT_CLEANUP
 
 AT_SETUP([SSL db: implementation])
 AT_KEYWORDS([ovsdb server positive ssl $5])
 AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
-AT_SKIP_IF([test "x$RANDOM" = x])
-SSL_PORT=`expr 32767 + \( $RANDOM % 32767 \)`
-PKIDIR=$abs_top_srcdir/tests
+# For this test, we pass PKIDIR through a ovsdb-tool transact and
+# msys on Windows does not convert the path style automatically.
+# So, do that forcefully with a 'pwd -W' (called through pwd() function).
+PKIDIR="$(cd $abs_top_builddir/tests && pwd)"
 AT_SKIP_IF([expr "$PKIDIR" : ".*[      '\"
-\r\\]"])
+\\]"])
 AT_DATA([schema],
   [[{"name": "mydb",
      "tables": {
@@ -105,9 +513,13 @@ AT_DATA([schema],
          "columns": {
            "private_key": {"type": "string"},
            "certificate": {"type": "string"},
-           "ca_cert": {"type": "string"}}}}}
+           "ca_cert": {"type": "string"},
+           "ssl_protocols" : {"type": "string"},
+           "ssl_ciphers" : {"type" : "string"}}}}}
 ]])
 AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+# The !ECDHE-ECDSA-AES256-GCM-SHA384 in the ssl_ciphers is so that
+# a cipher negotiation failure can be tested for later.
 AT_CHECK(
   [[ovsdb-tool transact db \
      '["mydb",
@@ -115,42 +527,111 @@ AT_CHECK(
         "table": "SSL",
         "row": {"private_key": "'"$PKIDIR/testpki-privkey2.pem"'",
                 "certificate": "'"$PKIDIR/testpki-cert2.pem"'",
-                "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'"}}]']],
+                "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'",
+                "ssl_protocols": "'"TLSv1.2,TLSv1.1"'",
+                "ssl_ciphers": "'"HIGH:!aNULL:!MD5:!ECDHE-ECDSA-AES256-GCM-SHA384"'"}}]']],
   [0], [ignore], [ignore])
 AT_CHECK(
-  [ovsdb-server --detach --pidfile=$PWD/pid \
-        --private-key=db:SSL,private_key \
-        --certificate=db:SSL,certificate \
-        --ca-cert=db:SSL,ca_cert \
-         --remote=pssl:$SSL_PORT:127.0.0.1 --unixctl=$PWD/unixctl db],
+  [ovsdb-server --log-file --detach --no-chdir --pidfile \
+        --private-key=db:mydb,SSL,private_key \
+        --certificate=db:mydb,SSL,certificate \
+        --ca-cert=db:mydb,SSL,ca_cert \
+        --ssl-protocols=db:mydb,SSL,ssl_protocols \
+        --ssl-ciphers=db:mydb,SSL,ssl_ciphers \
+        --remote=pssl:0:127.0.0.1 db],
   [0], [ignore], [ignore])
+PARSE_LISTENING_PORT([ovsdb-server.log], [SSL_PORT])
 AT_CHECK(
   [[ovsdb-client \
         --private-key=$PKIDIR/testpki-privkey.pem \
         --certificate=$PKIDIR/testpki-cert.pem \
         --ca-cert=$PKIDIR/testpki-cacert.pem \
+        --ssl-protocols=TLSv1.2,TLSv1.1 \
+        --ssl-ciphers=HIGH:!aNULL:!MD5 \
         transact ssl:127.0.0.1:$SSL_PORT \
         '["mydb",
           {"op": "select",
            "table": "SSL",
            "where": [],
-           "columns": ["private_key"]}]']], 
+           "columns": ["private_key"]}]']],
   [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`])
 cat stdout >> output
 AT_CHECK_UNQUOTED(
-  [perl $srcdir/uuidfilt.pl output], [0], 
-  [[[{"rows":[{"private_key":"$PKIDIR/testpki-privkey2.pem"}]}]
+  [cat output], [0],
+  [[@<:@{"rows":@<:@{"private_key":"$PKIDIR/testpki-privkey2.pem"}@:>@}@:>@
 ]], [ignore], [test ! -e pid || kill `cat pid`])
+# Check that when the server has TLSv1.1+ and the client has
+# TLSv1 that the connection fails.
+AT_CHECK(
+  [[ovsdb-client \
+        --private-key=$PKIDIR/testpki-privkey.pem \
+        --certificate=$PKIDIR/testpki-cert.pem \
+        --ca-cert=$PKIDIR/testpki-cacert.pem \
+        --ssl-protocols=TLSv1 \
+        --ssl-ciphers=HIGH:!aNULL:!MD5 \
+        transact ssl:127.0.0.1:$SSL_PORT \
+        '["mydb",
+          {"op": "select",
+           "table": "SSL",
+           "where": [],
+           "columns": ["private_key"]}]']], 
+  [1], [stdout], 
+  [stderr], 
+  [test ! -e pid || kill `cat pid`])
+cat stderr > output
+AT_CHECK_UNQUOTED(
+  [grep "failed to connect" output], [0],
+  [ovsdb-client: failed to connect to "ssl:127.0.0.1:$SSL_PORT" (Protocol error)
+], 
+  [ignore], [test ! -e pid || kill `cat pid`])
+# Check that when ciphers are not compatible, that a negotiation
+# failure occurs.
+AT_CHECK(
+  [[ovsdb-client \
+        --private-key=$PKIDIR/testpki-privkey.pem \
+        --certificate=$PKIDIR/testpki-cert.pem \
+        --ca-cert=$PKIDIR/testpki-cacert.pem \
+        --ssl-protocols=TLSv1.2,TLSv1.1 \
+        --ssl-ciphers=ECDHE-ECDSA-AES256-GCM-SHA384 \
+        transact ssl:127.0.0.1:$SSL_PORT \
+        '["mydb",
+          {"op": "select",
+           "table": "SSL",
+           "where": [],
+           "columns": ["private_key"]}]']], 
+  [1], [stdout], 
+  [stderr], 
+  [test ! -e pid || kill `cat pid`])
+cat stderr > output
+AT_CHECK_UNQUOTED(
+  [grep "failed to connect" output], [0],
+  [ovsdb-client: failed to connect to "ssl:127.0.0.1:$SSL_PORT" (Protocol error)
+], 
+  [ignore], [test ! -e pid || kill `cat pid`])
+# The error message for being unable to negotiate a shared ciphersuite
+# is 'sslv3 alert handshake failure'. This is not the clearest message.
+AT_CHECK_UNQUOTED(
+  [grep "sslv3 alert handshake failure" output], [0],
+  [stdout],
+  [ignore], [test ! -e pid || kill `cat pid`])
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
 
 AT_SETUP([compacting online])
 AT_KEYWORDS([ovsdb server compact])
-AT_DATA([schema], [ORDINAL_SCHEMA
-])
-touch .db.~lock~
+ordinal_schema > schema
+dnl Make sure that "ovsdb-tool create" works with a dangling symlink for
+dnl the database and the lockfile, creating the target of each symlink rather
+dnl than replacing the symlinks with regular files.
+mkdir dir
+if test "$IS_WIN32" = "no"; then
+    ln -s dir/db db
+    ln -s dir/.db.~lock~ .db.~lock~
+    AT_SKIP_IF([test ! -h db || test ! -h .db.~lock~])
+fi
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
-AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --unixctl=$PWD/unixctl --remote=punix:socket --log-file=$PWD/ovsdb-server.log db], [0], [ignore], [ignore])
+dnl Start ovsdb-server.
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket --log-file="`pwd`"/ovsdb-server.log db], [0], [ignore], [ignore])
 AT_CAPTURE_FILE([ovsdb-server.log])
 dnl Do a bunch of random transactions that put crap in the database log.
 AT_CHECK(
@@ -180,32 +661,33 @@ AT_CHECK(
     done]],
   [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`])
 dnl Check that all the crap is in fact in the database log.
-AT_CHECK([[perl $srcdir/uuidfilt.pl db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/']], [0],
-  [[{"name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}}}}}
-{"ordinals":{"<0>":{"name":"zero"}},"_comment":"add row for zero 0","_date":0}
-{"ordinals":{"<0>":null},"_comment":"delete row for 0","_date":0}
-{"ordinals":{"<1>":{"name":"zero"}},"_comment":"add back row for zero 0","_date":0}
-{"ordinals":{"<2>":{"number":1,"name":"one"}},"_comment":"add row for one 1","_date":0}
-{"ordinals":{"<2>":null},"_comment":"delete row for 1","_date":0}
-{"ordinals":{"<3>":{"number":1,"name":"one"}},"_comment":"add back row for one 1","_date":0}
-{"ordinals":{"<4>":{"number":2,"name":"two"}},"_comment":"add row for two 2","_date":0}
-{"ordinals":{"<4>":null},"_comment":"delete row for 2","_date":0}
-{"ordinals":{"<5>":{"number":2,"name":"two"}},"_comment":"add back row for two 2","_date":0}
-{"ordinals":{"<6>":{"number":3,"name":"three"}},"_comment":"add row for three 3","_date":0}
-{"ordinals":{"<6>":null},"_comment":"delete row for 3","_date":0}
-{"ordinals":{"<7>":{"number":3,"name":"three"}},"_comment":"add back row for three 3","_date":0}
-{"ordinals":{"<8>":{"number":4,"name":"four"}},"_comment":"add row for four 4","_date":0}
-{"ordinals":{"<8>":null},"_comment":"delete row for 4","_date":0}
-{"ordinals":{"<9>":{"number":4,"name":"four"}},"_comment":"add back row for four 4","_date":0}
-{"ordinals":{"<10>":{"number":5,"name":"five"}},"_comment":"add row for five 5","_date":0}
-{"ordinals":{"<10>":null},"_comment":"delete row for 5","_date":0}
-{"ordinals":{"<11>":{"number":5,"name":"five"}},"_comment":"add back row for five 5","_date":0}
+AT_CHECK([[${PERL} $srcdir/uuidfilt.pl db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/' | ovstest test-json --multiple -]], [0],
+  [[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"]]}},"version":"5.1.3"}
+{"_comment":"add row for zero 0","_date":0,"ordinals":{"<0>":{"name":"zero"}}}
+{"_comment":"delete row for 0","_date":0,"ordinals":{"<0>":null}}
+{"_comment":"add back row for zero 0","_date":0,"ordinals":{"<1>":{"name":"zero"}}}
+{"_comment":"add row for one 1","_date":0,"ordinals":{"<2>":{"name":"one","number":1}}}
+{"_comment":"delete row for 1","_date":0,"ordinals":{"<2>":null}}
+{"_comment":"add back row for one 1","_date":0,"ordinals":{"<3>":{"name":"one","number":1}}}
+{"_comment":"add row for two 2","_date":0,"ordinals":{"<4>":{"name":"two","number":2}}}
+{"_comment":"delete row for 2","_date":0,"ordinals":{"<4>":null}}
+{"_comment":"add back row for two 2","_date":0,"ordinals":{"<5>":{"name":"two","number":2}}}
+{"_comment":"add row for three 3","_date":0,"ordinals":{"<6>":{"name":"three","number":3}}}
+{"_comment":"delete row for 3","_date":0,"ordinals":{"<6>":null}}
+{"_comment":"add back row for three 3","_date":0,"ordinals":{"<7>":{"name":"three","number":3}}}
+{"_comment":"add row for four 4","_date":0,"ordinals":{"<8>":{"name":"four","number":4}}}
+{"_comment":"delete row for 4","_date":0,"ordinals":{"<8>":null}}
+{"_comment":"add back row for four 4","_date":0,"ordinals":{"<9>":{"name":"four","number":4}}}
+{"_comment":"add row for five 5","_date":0,"ordinals":{"<10>":{"name":"five","number":5}}}
+{"_comment":"delete row for 5","_date":0,"ordinals":{"<10>":null}}
+{"_comment":"add back row for five 5","_date":0,"ordinals":{"<11>":{"name":"five","number":5}}}
 ]], [], [test ! -e pid || kill `cat pid`])
 dnl Dump out and check the actual database contents.
 AT_CHECK([[ovsdb-client dump unix:socket ordinals]],
   [0], [stdout], [ignore])
-AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0],
-  [_uuid                                name  number
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl stdout], [0], [dnl
+ordinals table
+_uuid                                name  number
 ------------------------------------ ----- ------
 <0> five  5     @&t@
 <1> four  4     @&t@
@@ -215,19 +697,28 @@ AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0],
 <5> zero  0     @&t@
 ], [], [test ! -e pid || kill `cat pid`])
 dnl Now compact the database in-place.
-AT_CHECK([[ovs-appctl -t $PWD/unixctl ovsdb-server/compact]],
+AT_CHECK([[ovs-appctl -t ovsdb-server ovsdb-server/compact]],
   [0], [], [ignore], [test ! -e pid || kill `cat pid`])
+dnl Make sure that "db" is still a symlink to dir/db instead of getting
+dnl replaced by a regular file, ditto for .db.~lock~.
+if test "$IS_WIN32" = "no"; then
+    AT_CHECK([test -h db])
+    AT_CHECK([test -h .db.~lock~])
+    AT_CHECK([test -f dir/db])
+    AT_CHECK([test -f dir/.db.~lock~])
+fi
 dnl We can't fully re-check the contents of the database log, because the
 dnl order of the records is not predictable, but there should only be 4 lines
 dnl in it now.
 AT_CAPTURE_FILE([db])
-AT_CHECK([wc -l < db], [0], [4
-], [], [test ! -e pid || kill `cat pid`])
+AT_CHECK([test `wc -l < db` -eq 4], [0], [], [],
+  [test ! -e pid || kill `cat pid`])
 dnl And check that the dumped data is the same too:
 AT_CHECK([ovsdb-client dump unix:socket ordinals], [0], [stdout], [ignore],
   [test ! -e pid || kill `cat pid`])
-AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0],
-  [_uuid                                name  number
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl stdout], [0], [dnl
+ordinals table
+_uuid                                name  number
 ------------------------------------ ----- ------
 <0> five  5     @&t@
 <1> four  4     @&t@
@@ -246,13 +737,18 @@ AT_CHECK(
   [0], [[[{"count":3}]
 ]], [ignore], [test ! -e pid || kill `cat pid`])
 dnl There should be 6 lines in the log now.
-AT_CHECK([wc -l < db], [0], [6
-], [], [test ! -e pid || kill `cat pid`])
-dnl Then check that the dumped data is correct.
+AT_CHECK([test `wc -l < db` -eq 6], [0], [], [],
+  [test ! -e pid || kill `cat pid`])
+dnl Then check that the dumped data is correct.  This time first kill
+dnl and restart the database server to ensure that the data is correct on
+dnl disk as well as in memory.
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket --log-file="`pwd`"/ovsdb-server.log db], [0], [ignore], [ignore])
 AT_CHECK([ovsdb-client dump unix:socket ordinals], [0], [stdout], [ignore],
   [test ! -e pid || kill `cat pid`])
-AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0],
-  [_uuid                                name  number
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl stdout], [0], [dnl
+ordinals table
+_uuid                                name  number
 ------------------------------------ ----- ------
 <0> five  5     @&t@
 <1> four  4     @&t@
@@ -260,8 +756,106 @@ AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0],
 ], [], [test ! -e pid || kill `cat pid`])
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
+
+AT_SETUP([ovsdb-server combines updates on backlogged connections])
+on_exit 'kill `cat *.pid`'
+
+# The maximum socket receive buffer size is important for this test, which
+# tests behavior when the receive buffer overflows.
+if test -e /proc/sys/net/core/rmem_max; then
+    # Linux
+    rmem_max=`cat /proc/sys/net/core/rmem_max`
+elif rmem_max=`sysctl -n net.inet.tcp.recvbuf_max 2>/dev/null`; then
+    : # FreeBSD, NetBSD
+else
+    # Don't know how to get maximum socket receive buffer on this OS
+    AT_SKIP_IF([:])
+fi
+
+# Calculate the number of iterations we need to queue.  Each of the
+# iterations we execute, by itself, yields a monitor update of about
+# 25 kB, so fill up that much space plus a few for luck.
+n_iterations=`expr $rmem_max / 25000 + 5`
+echo rmem_max=$rmem_max n_iterations=$n_iterations
+
+# If there's too much queuing skip the test to avoid timing out.
+AT_SKIP_IF([test $rmem_max -gt 1048576])
+
+# Calculate the exact number of monitor updates expected for $n_iterations,
+# assuming no updates are combined.  The "extra" update is for the initial
+# contents of the database.
+n_updates=`expr $n_iterations \* 3 + 1`
+
+# Start an ovsdb-server with the vswitchd schema.
+OVSDB_INIT([db])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:db.sock db],
+  [0], [ignore], [ignore])
+
+# Executes a set of transactions that add a bridge with 100 ports, and
+# then deletes that bridge.  This yields three monitor updates that
+# add up to about 25 kB in size.
+#
+# The update also increments a counter held in the database so that we can
+# verify that the overall effect of the transactions took effect (e.g.
+# monitor updates at the end weren't just dropped).  We add an arbitrary
+# string to the counter to make grepping for it more reliable.
+counter=0
+trigger_big_update () {
+    counter=`expr $counter + 1`
+    ovs-vsctl --no-wait -- set open_vswitch . system_version=xyzzy$counter
+    ovs-vsctl --no-wait -- add-br br0 $add
+    ovs-vsctl --no-wait -- del-br br0
+}
+add_ports () {
+    for j in `seq 1 100`; do
+        printf " -- add-port br0 p%d" $j
+    done
+}
+add=`add_ports`
+
+AT_CAPTURE_FILE([ovsdb-client.err])
+AT_CAPTURE_FILE([ovsdb-client-nonblock.err])
+
+
+# Start an ovsdb-client monitoring all changes to the database,
+# By default, it is non-blocking, and will get update message
+# for each ovsdb-server transaactions.
+AT_CHECK([ovsdb-client --detach --no-chdir --pidfile=nonblock.pid monitor ALL >ovsdb-client-nonblock.out 2>ovsdb-client-nonblock.err])
+
+# Start an ovsdb-client monitoring all changes to the database,
+# make it block to force the buffers to fill up, and then execute
+# enough iterations that ovsdb-server starts combining updates.
+AT_CHECK([ovsdb-client --detach --no-chdir --pidfile monitor ALL >ovsdb-client.out 2>ovsdb-client.err])
+AT_CHECK([ovs-appctl -t ovsdb-client ovsdb-client/block])
+for i in `seq 1 $n_iterations`; do
+    echo "blocked update ($i of $n_iterations)"
+    trigger_big_update $i
+done
+AT_CHECK([ovs-appctl -t ovsdb-client ovsdb-client/unblock])
+OVS_WAIT_UNTIL([grep "\"xyzzy$counter\"" ovsdb-client.out])
+OVS_WAIT_UNTIL([grep "\"xyzzy$counter\"" ovsdb-client-nonblock.out])
+OVS_APP_EXIT_AND_WAIT([ovsdb-client])
+AT_CHECK([kill `cat nonblock.pid`])
+
+# Count the number of updates in the ovsdb-client output, by counting
+# the number of changes to the Open_vSwitch table.  (All of our
+# transactions modify the Open_vSwitch table.)  It should be less than
+# $n_updates updates.
+#
+# Check that the counter is what we expect.
+logged_updates=`grep -c '^Open_vSwitch' ovsdb-client.out`
+logged_nonblock_updates=`grep -c '^Open_vSwitch' ovsdb-client-nonblock.out`
+echo "logged_nonblock_updates=$logged_nonblock_updates (expected less or equal to $n_updates)"
+echo "logged_updates=$logged_updates (expected less than $logged_nonblock_updates)"
+AT_CHECK([test $logged_nonblock_updates -le $n_updates])
+AT_CHECK([test $logged_updates -lt $logged_nonblock_updates])
+AT_CHECK_UNQUOTED([ovs-vsctl get open_vswitch . system_version], [0],
+  ["xyzzy$counter"
+])
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
 \f
-AT_BANNER([OVSDB -- ovsdb-server transactions (SSL sockets)])
+AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv4 sockets)])
 
 # OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
 #
@@ -281,24 +875,144 @@ m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive ssl $5])
    AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
-   AT_SKIP_IF([test "x$RANDOM" = x])
-   AT_DATA([schema], [$2
-])
-   SSL_PORT=`expr 32767 + \( $RANDOM % 32767 \)`
-   PKIDIR=$abs_top_srcdir/tests
+   $2 > schema
+   PKIDIR=$abs_top_builddir/tests
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
-   AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --private-key=$PKIDIR/testpki-privkey2.pem --certificate=$PKIDIR/testpki-cert2.pem --ca-cert=$PKIDIR/testpki-cacert.pem --remote=pssl:$SSL_PORT:127.0.0.1 --unixctl=$PWD/unixctl db], [0], [ignore], [ignore])
+   AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile --private-key=$PKIDIR/testpki-privkey2.pem --certificate=$PKIDIR/testpki-cert2.pem --ca-cert=$PKIDIR/testpki-cacert.pem --remote=pssl:0:127.0.0.1 db], [0], [ignore], [ignore])
+   PARSE_LISTENING_PORT([ovsdb-server.log], [SSL_PORT])
    m4_foreach([txn], [$3], 
      [AT_CHECK([ovsdb-client --private-key=$PKIDIR/testpki-privkey.pem --certificate=$PKIDIR/testpki-cert.pem --ca-cert=$PKIDIR/testpki-cacert.pem transact ssl:127.0.0.1:$SSL_PORT 'txn'], [0], [stdout], [ignore],
      [test ! -e pid || kill `cat pid`])
 cat stdout >> output
 ])
-   AT_CHECK([perl $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+            [test ! -e pid || kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+EXECUTION_EXAMPLES
+
+AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv6 sockets)])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number.  The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server positive ssl6 $5])
+   AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+   AT_SKIP_IF([test $HAVE_IPV6 = no])
+   $2 > schema
+   PKIDIR=$abs_top_builddir/tests
+   AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile --private-key=$PKIDIR/testpki-privkey2.pem --certificate=$PKIDIR/testpki-cert2.pem --ca-cert=$PKIDIR/testpki-cacert.pem --remote=pssl:0:[[::1]] db], [0], [ignore], [ignore])
+   PARSE_LISTENING_PORT([ovsdb-server.log], [SSL_PORT])
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client --private-key=$PKIDIR/testpki-privkey.pem --certificate=$PKIDIR/testpki-cert.pem --ca-cert=$PKIDIR/testpki-cacert.pem transact ssl:[[::1]]:$SSL_PORT 'txn'], [0], [stdout], [ignore],
+     [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+            [test ! -e pid || kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+ONE_EXECUTION_EXAMPLE
+
+AT_BANNER([OVSDB -- ovsdb-server transactions (TCP IPv4 sockets)])
+
+AT_SETUP([ovsdb-client get-schema-version - tcp socket])
+AT_KEYWORDS([ovsdb server positive tcp])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile --remote=ptcp:0:127.0.0.1 db], [0], [ignore], [ignore])
+PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
+AT_CHECK([ovsdb-client get-schema-version tcp:127.0.0.1:$TCP_PORT ordinals], [0], [5.1.3
+])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number.  The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server positive tcp $5])
+   $2 > schema
+   PKIDIR=$abs_top_builddir/tests
+   AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile --remote=ptcp:0:127.0.0.1 db], [0], [ignore], [ignore])
+   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT 'txn'], [0], [stdout], [ignore],
+     [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
             [test ! -e pid || kill `cat pid`])
    OVSDB_SERVER_SHUTDOWN
    AT_CLEANUP])
 
 EXECUTION_EXAMPLES
+
+AT_BANNER([OVSDB -- ovsdb-server transactions (TCP IPv6 sockets)])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number.  The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server positive tcp6 $5])
+   AT_SKIP_IF([test $HAVE_IPV6 = no])
+   $2 > schema
+   PKIDIR=$abs_top_builddir/tests
+   AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile --remote=ptcp:0:[[::1]] db], [0], [ignore], [ignore])
+   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client transact tcp:[[::1]]:$TCP_PORT 'txn'], [0], [stdout], [ignore],
+     [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+            [test ! -e pid || kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+ONE_EXECUTION_EXAMPLE
 \f
 AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
 
@@ -321,17 +1035,506 @@ AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
 # TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
+   AT_SKIP_IF([test "$IS_WIN32" = "yes"])
    AT_KEYWORDS([ovsdb server positive transient $5])
-   AT_DATA([schema], [$2
-])
+   $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
    m4_foreach([txn], [$3], 
      [AT_DATA([txnfile], [ovsdb-client transact unix:socket 'txn'
 ])
-      AT_CHECK([ovsdb-server --remote=punix:socket --unixctl=$PWD/unixctl db --run="sh txnfile"], [0], [stdout], [ignore])
+      AT_CHECK([ovsdb-server --remote=punix:socket db --run="sh txnfile"], [0], [stdout], [ignore])
       cat stdout >> output
 ])
-   AT_CHECK([perl $srcdir/uuidfilt.pl output], [0], [$4], [ignore])
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore])
+   AT_CLEANUP])
+
+EXECUTION_EXAMPLES
+\f
+AT_BANNER([OVSDB -- ovsdb-server replication])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates two databases with the given SCHEMA, and starts an ovsdb-server on
+# each database.
+# Runs each of the TRANSACTIONS (which should be a quoted list of
+# quoted strings) against one of the servers with ovsdb-client one at a
+# time. The server replicates its database to the other ovsdb-server.
+#
+# Checks that the dump of both databases are the same.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server tcp replication $5])
+   $2 > schema
+   AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+   AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore])
+   i
+   on_exit 'test ! -e pid || kill `cat pid`'
+
+   AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=pid2 --remote=punix:db2.sock --unixctl=unixctl2 --sync-from=unix:db.sock db2], [0], [ignore], [ignore])
+   on_exit 'test ! -e pid2 || kill `cat pid2`'
+
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client transact 'txn'], [0], [stdout], [ignore])
+   ])
+
+   AT_CHECK([ovsdb-client dump], [0], [stdout], [ignore])
+   OVS_WAIT_UNTIL([ ovsdb-client dump unix:db2.sock > dump2; diff stdout dump2])
+
+   OVSDB_SERVER_SHUTDOWN
+   OVSDB_SERVER_SHUTDOWN2
    AT_CLEANUP])
 
 EXECUTION_EXAMPLES
+
+AT_BANNER([OVSDB -- ovsdb-server replication table-exclusion])
+
+# OVSDB_CHECK_REPLICATION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates two databases with the given SCHEMA, and starts an
+# ovsdb-server on each database.
+# Runs each of the TRANSACTIONS (which should be a quoted list of
+# quoted strings) against one of the servers with ovsdb-client one at a
+# time. The server replicates its database to the other ovsdb-server.
+#
+# Checks that the difference between the dump of the databases is
+# OUTPUT, but UUIDs in the output are replaced by markers of the form
+# <N> where N is a number.  The first unique UUID is replaced by <0>,
+# the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_REPLICATION],
+   [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server tcp replication table-exclusion])
+   $2 > schema
+   AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+   AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore])
+   on_exit 'test ! -e pid || kill `cat pid`'
+
+   AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=pid2 --remote=punix:db2.sock --unixctl=unixctl2 --sync-from=unix:db.sock --sync-exclude-tables=mydb:b db2], [0], [ignore], [ignore])
+   on_exit 'test ! -e pid2 || kill `cat pid2`'
+
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ ovsdb-client transact 'txn' ], [0], [stdout], [ignore])
+   ])
+
+   AT_CHECK([ovsdb-client dump], [0], [stdout], [ignore])
+   cat stdout > dump1
+
+   OVS_WAIT_UNTIL([ ovsdb-client dump unix:db2.sock | grep one ])
+   AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout], [ignore])
+   cat stdout > dump2
+
+   AT_CHECK([diff dump1 dump2], [1], [stdout], [ignore])
+   cat stdout > output
+
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore])
+
+   OVSDB_SERVER_SHUTDOWN
+   OVSDB_SERVER_SHUTDOWN2
+   AT_CLEANUP])
+
+REPLICATION_EXAMPLES
+
+AT_BANNER([OVSDB -- ovsdb-server replication runtime management commands])
+
+#ovsdb-server/get-active-ovsdb-server command
+AT_SETUP([ovsdb-server/get-active-ovsdb-server])
+AT_KEYWORDS([ovsdb server replication get-active])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --sync-from=tcp:127.0.0.1:9999 db])
+
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/get-active-ovsdb-server],
+  [0], [tcp:127.0.0.1:9999
+])
+AT_CLEANUP
+
+#*ovsdb-server/set-active-ovsdb-server command
+AT_SETUP([ovsdb-server/set-active-ovsdb-server])
+AT_KEYWORDS([ovsdb server replication set-active])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile db])
+
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/set-active-ovsdb-server tcp:127.0.0.1:9999])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/get-active-ovsdb-server],
+  [0], [tcp:127.0.0.1:9999
+])
+AT_CLEANUP
+
+#ovsdb-server/get-sync-exclude-tables command
+AT_SETUP([ovsdb-server/get-sync-exclude-tables])
+AT_KEYWORDS([ovsdb server replication get-exclude-tables])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+on_exit 'kill `cat *.pid`'
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --sync-exclude-tables=mydb:db1,mydb:db2 db])
+
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/get-sync-exclude-tables],
+  [0], [mydb:db1,mydb:db2
+])
+AT_CLEANUP
+
+#ovsdb-server/set-sync-exclude-tables command
+AT_SETUP([ovsdb-server/set-sync-exclude-tables])
+AT_KEYWORDS([ovsdb server replication set-exclude-tables])
+replication_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore])
+on_exit 'test ! -e pid || kill `cat pid`'
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=pid2 --remote=punix:db2.sock --unixctl=unixctl2 --sync-from=unix:db.sock db2], [0], [ignore], [ignore])
+on_exit 'test ! -e pid2 || kill `cat pid2`'
+
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/set-sync-exclude-tables mydb:b], [0], [ignore], [ignore], [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+
+AT_CHECK([ovsdb-client transact unix:db.sock \
+ '[["mydb",
+    {"op": "insert",
+      "table": "a",
+      "row": {"number": 0, "name": "zero"}},
+    {"op": "insert",
+      "table": "b",
+      "row": {"number": 1, "name": "one"}}]]'], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+
+AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+cat stdout > dump1
+OVS_WAIT_UNTIL([ ovsdb-client dump unix:db2.sock | grep zero ])
+AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout], [ignore])
+cat stdout > dump2
+
+AT_CHECK([diff dump1 dump2], [1], [stdout], [ignore])
+cat stdout > output
+
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [7,9c7,8
+< _uuid                                name number
+< ------------------------------------ ---- ------
+< <0> one  1     @&t@
+---
+> _uuid name number
+> ----- ---- ------
+])
+
+OVSDB_SERVER_SHUTDOWN
+OVSDB_SERVER_SHUTDOWN2
+AT_CLEANUP
+
+#ovsdb-server/connect-active-ovsdb-server
+AT_SETUP([ovsdb-server/connect-active-server])
+AT_KEYWORDS([ovsdb server replication connect-active-server])
+replication_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore])
+on_exit 'test ! -e pid || kill `cat pid`'
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=pid2 --remote=punix:db2.sock --unixctl=unixctl2 db2], [0], [ignore], [ignore])
+on_exit 'test ! -e pid2 || kill `cat pid2`'
+
+dnl Try to connect without specifying the active server.
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/connect-active-ovsdb-server], [0],
+[Unable to connect: active server is not specified.
+], [ignore])
+
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/set-active-ovsdb-server unix:db.sock], [0], [stdout], [ignore])
+
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/connect-active-ovsdb-server], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-client transact unix:db.sock \
+ '[["mydb",
+  {"op": "insert",
+   "table": "a",
+   "row": {"number": 0, "name": "zero"}}]]'], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout], [ignore])
+cat stdout > dump1
+OVS_WAIT_UNTIL([ ovsdb-client dump unix:db2.sock | grep zero ])
+AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout], [ignore])
+cat stdout > dump2
+
+AT_CHECK([diff dump1 dump2], [0], [], [ignore])
+OVSDB_SERVER_SHUTDOWN
+OVSDB_SERVER_SHUTDOWN2
+AT_CLEANUP
+
+#ovsdb-server/disconnect-active-server command
+AT_SETUP([ovsdb-server/disconnect-active-server])
+AT_KEYWORDS([ovsdb server replication disconnect-active-server])
+replication_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore])
+on_exit 'test ! -e pid || kill `cat pid`'
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=pid2 --remote=punix:db2.sock --unixctl=unixctl2 --sync-from=unix:db.sock db2], [0], [ignore], [ignore])
+on_exit 'test ! -e pid2 || kill `cat pid2`'
+
+AT_CHECK([ovsdb-client transact unix:db.sock \
+'[["mydb",
+  {"op": "insert",
+   "table": "a",
+   "row": {"number": 0, "name": "zero"}}]]'], [0], [stdout], [ignore])
+
+dnl Make sure the transaction shows up in db2. This also tests the back up server
+dnl can be read.
+OVS_WAIT_UNTIL([ovsdb-client dump unix:db2.sock | grep zero])
+
+dnl The backup server does not accept any write transaction
+AT_CHECK([ovsdb-client transact unix:db2.sock \
+'[["mydb",
+  {"op": "insert",
+   "table": "b",
+   "row": {"number": 1, "name": "one"}}]]'], [0],
+   [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+])
+
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/disconnect-active-ovsdb-server], [0], [ignore], [ignore])
+
+AT_CHECK([ovsdb-client transact unix:db.sock \
+'[["mydb",
+  {"op": "insert",
+   "table": "b",
+   "row": {"number": 1, "name": "one"}}]]'], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout], [ignore])
+cat stdout > dump1
+
+sleep 1
+AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout], [ignore])
+cat stdout > dump2
+
+AT_CHECK([diff dump1 dump2], [1], [stdout], [ignore])
+cat stdout > output
+
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [7,9c7,8
+< _uuid                                name number
+< ------------------------------------ ---- ------
+< <0> one  1     @&t@
+---
+> _uuid name number
+> ----- ---- ------
+], [ignore], [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+
+dnl The backup server now become active, and can accept write transactions.
+AT_CHECK([ovsdb-client transact unix:db2.sock \
+'[["mydb",
+  {"op": "insert",
+   "table": "b",
+   "row": {"number": 1, "name": "one"}}]]'], [0], [stdout], [ignore])
+
+AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout])
+cat stdout > output
+
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [a table
+_uuid                                name number
+------------------------------------ ---- ------
+<0> zero 0     @&t@
+
+b table
+_uuid                                name number
+------------------------------------ ---- ------
+<1> one  1     @&t@
+])
+
+OVSDB_SERVER_SHUTDOWN
+OVSDB_SERVER_SHUTDOWN2
+AT_CLEANUP
+
+#ovsdb-server/active-backup-role-switching
+AT_SETUP([ovsdb-server/active-backup-role-switching])
+AT_KEYWORDS([ovsdb server replication active-backup-switching])
+replication_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+dnl Add some data to both DBs
+AT_CHECK([ovsdb-tool transact db1 \
+'[["mydb",
+  {"op": "insert",
+   "table": "a",
+   "row": {"number": 9, "name": "nine"}}]]'], [0], [ignore], [ignore])
+
+AT_CHECK([ovsdb-tool transact db2 \
+'[["mydb",
+  {"op": "insert",
+   "table": "a",
+   "row": {"number": 9, "name": "nine"}}]]'], [0], [ignore], [ignore])
+
+dnl Start both 'db1' and 'db2' in backup mode. Let them backup from each
+dnl other. This is not an supported operation state, but to simulate a start
+dnl up condition where an HA manger can select which one to be an active
+dnl server soon after.
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile="`pwd`"/pid --remote=punix:db.sock --unixctl="`pwd`"/unixctl db1 --sync-from=unix:db2.sock --active ], [0], [ignore], [ignore])
+on_exit 'test ! -e pid || kill `cat pid`'
+
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/connect-active-ovsdb-server])
+
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile="`pwd`"/pid2 --remote=punix:db2.sock --unixctl="`pwd`"/unixctl2 --sync-from=unix:db.sock db2], [0], [ignore], [ignore])
+on_exit 'test ! -e pid2 || kill `cat pid2`'
+
+dnl
+dnl make sure both servers reached the replication state
+OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status |grep replicating])
+OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/sync-status |grep replicating])
+
+dnl Switch the 'db1' to active
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/disconnect-active-ovsdb-server])
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status], [0], [state: active
+])
+
+dnl Issue a transaction to 'db1'
+AT_CHECK([ovsdb-client transact unix:db.sock \
+'[["mydb",
+  {"op": "insert",
+   "table": "a",
+   "row": {"number": 0, "name": "zero"}}]]'], [0], [ignore])
+
+dnl It should be replicated to 'db2'
+OVS_WAIT_UNTIL([ovsdb-client dump unix:db2.sock | grep zero])
+
+dnl Flip the role of 'db1' and 'db2'.  'db1' becomes backup, and db2 becomes active
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/disconnect-active-ovsdb-server])
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/connect-active-ovsdb-server])
+
+dnl Verify the change happend
+OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status |grep replicating])
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/sync-status], [0], [state: active
+])
+
+dnl Issue an transaction to 'db2' which is now active.
+AT_CHECK([ovsdb-client transact unix:db2.sock \
+'[["mydb",
+  {"op": "insert",
+   "table": "b",
+   "row": {"number": 1, "name": "one"}}]]'], [0], [ignore])
+
+dnl The transaction should be replicated to 'db1'
+OVS_WAIT_UNTIL([ovsdb-client dump unix:db.sock | grep one])
+
+dnl Both servers should have the same content.
+AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout])
+cat stdout > dump1
+
+AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout])
+cat stdout > dump2
+
+AT_CHECK([diff dump1 dump2])
+
+dnl OVSDB_SERVER_SHUTDOWN
+dnl OVSDB_SERVER_SHUTDOWN2
+AT_CLEANUP
+
+#ovsdb-server prevent self replicating
+AT_SETUP([ovsdb-server prevent self replicating])
+AT_KEYWORDS([ovsdb server replication])
+replication_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+
+dnl Add some data to both DBs
+AT_CHECK([ovsdb-tool transact db \
+'[["mydb",
+  {"op": "insert",
+   "table": "a",
+   "row": {"number": 9, "name": "nine"}}]]'], [0], [ignore], [ignore])
+
+dnl Start 'db', then try to be a back up server of itself.
+AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server.log --pidfile="`pwd`"/pid --remote=punix:db.sock --unixctl="`pwd`"/unixctl db --sync-from=unix:db.sock --active ], [0], [ignore], [ignore])
+on_exit 'test ! -e pid || kill `cat pid`'
+
+dnl Save the current content
+AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout])
+cp stdout dump1
+
+AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/connect-active-ovsdb-server])
+dnl Check that self replicating is blocked.
+AT_CHECK([grep "Self replicating is not allowed" ovsdb-server.log], [0], [stdout])
+
+dnl Check current DB content is preserved.
+AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout])
+cat stdout > dump2
+
+AT_CHECK([diff dump1 dump2])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/read-only db:ptcp connection])
+AT_KEYWORDS([ovsdb server read-only])
+AT_DATA([schema],
+  [[{"name": "mydb",
+     "tables": {
+       "Root": {
+         "columns": {
+           "managers": {
+             "type": {
+               "key": {"type": "uuid", "refTable": "Manager"},
+               "min": 0,
+               "max": "unlimited"}}}},
+       "Manager": {
+         "columns": {
+           "target": {
+             "type": "string"},
+           "read_only": {
+             "type": {
+               "key": "boolean",
+               "min": 0,
+               "max": 1}},
+           "is_connected": {
+             "type": {
+               "key": "boolean",
+               "min": 0,
+               "max": 1}}}},
+       "ordinals": {
+         "columns": {
+           "number": {"type": "integer"},
+           "name": {"type": "string"}},
+         "indexes": [["number"]]}
+    },
+     "version": "5.1.3",
+     "cksum": "12345678 9"
+}
+]])
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK(
+  [[ovsdb-tool transact db \
+     '["mydb",
+       {"op": "insert",
+        "table": "Root",
+        "row": {
+          "managers": ["set", [["named-uuid", "x"]]]}},
+       {"op": "insert",
+        "table": "Manager",
+        "uuid-name": "x",
+        "row": {"target": "ptcp:0:127.0.0.1",
+               "read_only": true}}]']], [0], [ignore], [ignore])
+
+AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile --remote=db:mydb,Root,managers db], [0], [ignore], [ignore])
+PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
+AT_CHECK([ovsdb-client get-schema-version tcp:127.0.0.1:$TCP_PORT mydb], [0], [5.1.3
+])
+
+AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT \
+        ['["mydb",
+         {"op": "insert",
+          "table": "ordinals",
+          "row": {"name": "two", "number": '2'}}
+         ]']], [0], [stdout], [ignore])
+cat stdout >> output
+AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]]
+], [ignore])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP