@@ -2014,3 +2014,152 @@ six 6
])
AT_CLEANUP
+
+AT_BANNER([OVSDB -- ovsdb-server stream record/replay])
+
+AT_SETUP([ovsdb-server record/replay])
+AT_KEYWORDS([ovsdb server record replay])
+on_exit 'kill `cat *.pid`'
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+
+dnl Create a directory for replay files.
+AT_CHECK([mkdir replay_dir])
+
+dnl Make a copy of a database for later replay.
+AT_CHECK([cp db ./replay_dir/db.copy])
+
+dnl Starting a dummy server only to reserve some tcp port.
+AT_CHECK([cp db db.tmp])
+AT_CHECK([ovsdb-server -vfile -vvlog:off --log-file=listener.log dnl
+ --detach --no-chdir dnl
+ --pidfile=pid2 --unixctl=unixctl2 dnl
+ --remote=ptcp:0:127.0.0.1 dnl
+ db.tmp], [0], [stdout], [stderr])
+PARSE_LISTENING_PORT([listener.log], [BAD_TCP_PORT])
+
+dnl Start ovsdb-server with recording enabled.
+dnl Trying to start a tcp session on already used port to record the error.
+AT_CHECK([ovsdb-server --replay-record=./replay_dir dnl
+ -vfile -vvlog:off -vjsonrpc:file:dbg --log-file=1.log dnl
+ --detach --no-chdir --pidfile dnl
+ --remote=punix:db.sock dnl
+ --remote=ptcp:$BAD_TCP_PORT:127.0.0.1 dnl
+ --remote=ptcp:0:127.0.0.1 dnl
+ db], [0], [stdout], [stderr])
+CHECK_DBS([ordinals
+])
+PARSE_LISTENING_PORT([1.log], [TCP_PORT])
+
+dnl Start a monitor on the 'ordinals' db to check recording of this kind
+dnl of messages.
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --no-chdir dnl
+ --pidfile=monitor.pid --log-file=monitor.log dnl
+ --db-change-aware --no-headings dnl
+ monitor tcp:127.0.0.1:$TCP_PORT dnl
+ ordinals ordinals number name dnl
+ > monitor.stdout 2> monitor.stderr])
+OVS_WAIT_UNTIL([test -e monitor.pid])
+
+dnl Do a bunch of random transactions.
+AT_CHECK(
+ [[for pair in 'zero 0' 'one 1' 'two 2' 'three 3' 'four 4' 'five 5'; do
+ set -- $pair
+ if test "$2" -eq "5"; then
+ # killing the monitor to check if this correctly recorded.
+ kill -9 $(cat monitor.pid)
+ fi
+ ovsdb-client --db-change-aware transact unix:db.sock '
+ ["ordinals",
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"name": "'$1'", "number": '$2'}},
+ {"op": "comment",
+ "comment": "add row for '"$pair"'"}]'
+ ovsdb-client transact unix:db.sock '
+ ["ordinals",
+ {"op": "delete",
+ "table": "ordinals",
+ "where": [["number", "==", '$2']]},
+ {"op": "comment",
+ "comment": "delete row for '"$2"'"}]'
+ ovsdb-client transact unix:db.sock '
+ ["ordinals",
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"name": "'$1'", "number": '$2'}},
+ {"op": "comment",
+ "comment": "add back row for '"$pair"'"}]'
+ done]],
+ [0], [stdout])
+
+AT_CHECK([ovsdb-client dump unix:db.sock ordinals | uuidfilt], 0, [dnl
+ordinals table
+_uuid name number
+------------------------------------ ----- ------
+<0> five 5
+<1> four 4
+<2> one 1
+<3> three 3
+<4> two 2
+<5> zero 0
+])
+
+AT_CHECK([uuidfilt monitor.stdout | sed '/^$/d'], [0], [dnl
+<0> insert 0 zero
+<0> delete 0 zero
+<1> insert 0 zero
+<2> insert 1 one
+<2> delete 1 one
+<3> insert 1 one
+<4> insert 2 two
+<4> delete 2 two
+<5> insert 2 two
+<6> insert 3 three
+<6> delete 3 three
+<7> insert 3 three
+<8> insert 4 four
+<8> delete 4 four
+<9> insert 4 four
+])
+OVSDB_SERVER_SHUTDOWN
+OVSDB_SERVER_SHUTDOWN2
+
+dnl Starting a replay.
+AT_CHECK([ovsdb-server --replay=./replay_dir dnl
+ -vfile -vvlog:off -vjsonrpc:file:dbg --log-file=2.log dnl
+ --detach --no-chdir --pidfile dnl
+ --remote=punix:db.sock dnl
+ --remote=ptcp:$BAD_TCP_PORT:127.0.0.1 dnl
+ --remote=ptcp:0:127.0.0.1 dnl
+ ./replay_dir/db.copy], [0], [stdout], [stderr])
+
+dnl Waiting for process termination. Process should exit after correct
+dnl processing of the 'exit' unixctl command from the recorded session.
+OVS_WAIT_WHILE([test -e ovsdb-server.pid])
+
+dnl Stripping out timestamps from database files. Also clearing record
+dnl hashes in database files, since dates inside are different.
+m4_define([CLEAN_DB_FILE],
+ [sed 's/\(OVSDB JSON [[0-9]]*\).*$/\1/g' $1 | dnl
+ sed 's/"_date":[[0-9]]*/"_date":<clared>/g' > $2])
+
+CLEAN_DB_FILE([db], [db.clear])
+CLEAN_DB_FILE([./replay_dir/db.copy], [./replay_dir/db.copy.clear])
+
+dnl Stripping out timestamps, PIDs and poll_loop warnings from the log.
+dnl Also stripping socket_util errors as sockets are not used in replay.
+m4_define([CLEAN_LOG_FILE],
+ [sed 's/[[0-9\-]]*T[[0-9:\.]]*Z|[[0-9]]*\(|.*$\)/\1/g' $1 | dnl
+ sed '/|poll_loop|/d' | dnl
+ sed '/|socket_util|/d' | dnl
+ sed 's/[[0-9]]*\.ctl/<cleared>\.ctl/g'> $2])
+
+CLEAN_LOG_FILE([1.log], [1.log.clear])
+CLEAN_LOG_FILE([2.log], [2.log.clear])
+
+dnl Checking that databases and logs are equal.
+AT_CHECK([diff db.clear ./replay_dir/db.copy.clear])
+AT_CHECK([diff 1.log.clear 2.log.clear])
+
+AT_CLEANUP
Signed-off-by: Ilya Maximets <i.maximets@ovn.org> --- tests/ovsdb-server.at | 149 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+)