AT_BANNER([OVSDB -- interface description language (IDL)])

m4_divert_text([PREPARE_TESTS], [
# ovsdb_cluster_leader [REMOTES] [DATABASE]
#
# Returns the leader of the DATABASE cluster.
ovsdb_cluster_leader () {
   remotes=$(echo $1 | tr "," "\n")
   for remote in $remotes; do
      ovsdb-client dump $remote _Server Database name leader | grep $2 | grep -q true
      if [[ $? == 0 ]]; then
        port=$(echo $remote | cut -d':' -f 3)
        log=$(grep --include=s\*.log -rlnw -e "listening on port $port" ./)
        pid=$(echo $log | sed 's/\(.*\.\)log/\1pid/' )
        echo "${remote}|${pid}"
        return
      fi
   done
}])


# OVSDB_START_IDLTEST([REMOTE], [SCHEMA])
#
# Creates a database using SCHEMA (default: idltest.ovsschema) and
# starts a database server listening on punix:socket and REMOTE (if
# specified).
m4_define([OVSDB_START_IDLTEST],
[
  AT_CHECK([ovsdb-tool create db dnl
              m4_if([$2], [], [$abs_srcdir/idltest.ovsschema], [$2])])
  PKIDIR=$abs_top_builddir/tests
  AT_CHECK([ovsdb-server -vconsole:warn --log-file --detach --no-chdir dnl
              --pidfile --remote=punix:socket dnl
              m4_if(m4_substr($1, 0, 5), [pssl:],
                    [--private-key=$PKIDIR/testpki-privkey2.pem dnl
                     --certificate=$PKIDIR/testpki-cert2.pem dnl
                     --ca-cert=$PKIDIR/testpki-cacert.pem], []) dnl
              m4_if([$1], [], [], [--remote=$1]) db dnl
  ])
  on_exit 'kill `cat ovsdb-server.pid`'
])


# OVSDB_CLUSTER_START_IDLTEST([N], [REMOTE])
#
# Creates a clustered database using idltest.ovsschema and starts a database
# cluster of N servers listening on punix:socket and REMOTE (if specified).
m4_define([OVSDB_CLUSTER_START_IDLTEST],
  [n=$1
   AT_CHECK([ovsdb-tool create-cluster s1.db \
                        $abs_srcdir/idltest.ovsschema unix:s1.raft])
   cid=$(ovsdb-tool db-cid s1.db)
   schema_name=$(ovsdb-tool schema-name $abs_srcdir/idltest.ovsschema)
   for i in $(seq 2 $n); do
     AT_CHECK([ovsdb-tool join-cluster s$i.db \
                          $schema_name unix:s$i.raft unix:s1.raft])
   done
   on_exit 'kill $(cat s*.pid)'
   for i in $(seq $n); do
     AT_CHECK([ovsdb-server -vraft -vconsole:warn --detach --no-chdir \
                   --log-file=s$i.log --pidfile=s$i.pid --unixctl=s$i \
                   --remote=punix:s$i.ovsdb                           \
                   m4_if([$2], [], [], [--remote=$2]) s$i.db])
   done

   for i in $(seq $n); do
       OVS_WAIT_UNTIL([ovs-appctl -t $(pwd)/s$i cluster/status ${schema_name} \
                                           | grep -q 'Status: cluster member'])
   done
])


# OVSDB_CHECK_IDL_C(TITLE, [PRE-IDL-TXN], TRANSACTIONS, OUTPUT, [KEYWORDS],
#                   [FILTER])
#
# Creates a database with a schema derived from idltest.ovsidl, runs
# each PRE-IDL-TXN (if any), starts an ovsdb-server on that database,
# and runs "test-ovsdb idl" passing each of the TRANSACTIONS along.
#
# Checks that the overall output is OUTPUT.  Before comparison, the
# output is sorted (using "sort") and 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.  If FILTER is supplied then the output is also filtered
# through the specified program.
#
# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
m4_define([OVSDB_CHECK_IDL_C],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses OVSDB_IDL_WRITE_CHANGED_ONLY.
m4_define([OVSDB_CHECK_IDL_WRITE_CHANGED_ONLY_C],
  [AT_SETUP([$1 - write-changed-only - C])
   AT_KEYWORDS([ovsdb server idl positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 --write-changed-only idl unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses tcp.
m4_define([OVSDB_CHECK_IDL_TCP_C],
  [AT_SETUP([$1 - C - tcp])
   AT_KEYWORDS([ovsdb server idl positive tcp socket $5])
   OVSDB_START_IDLTEST(["ptcp:0:127.0.0.1"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])

   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl tcp:127.0.0.1:$TCP_PORT $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses tcp6.
m4_define([OVSDB_CHECK_IDL_TCP6_C],
  [AT_SETUP([$1 - C - tcp6])
   AT_SKIP_IF([test "$IS_WIN32" = "yes"])
   AT_SKIP_IF([test $HAVE_IPV6 = no])
   AT_KEYWORDS([ovsdb server idl positive tcp6 socket $5])
   OVSDB_START_IDLTEST(["ptcp:0:[[::1]]"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])

   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact tcp:[[::1]]:$TCP_PORT $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl tcp:[[::1]]:$TCP_PORT $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses the Python IDL implementation.
m4_define([OVSDB_CHECK_IDL_PY],
  [AT_SETUP([$1 - Python3])
   AT_KEYWORDS([ovsdb server idl positive Python $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_REGISTER_COLUMNS_PY],
  [AT_SETUP([$1 - Python3 - register_columns])
   AT_KEYWORDS([ovsdb server idl positive Python register_columns $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket ?simple:b,ba,i,ia,r,ra,s,sa,u,ua?simple3:name,uset,uref?simple4:name?simple6:name,weak_ref?link1:i,k,ka,l2?link2:i,l1?singleton:name $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with tcp
m4_define([OVSDB_CHECK_IDL_TCP_PY],
  [AT_SETUP([$1 - Python3 - tcp])
   AT_KEYWORDS([ovsdb server idl positive Python with tcp socket $5])
   OVSDB_START_IDLTEST(["ptcp:0:127.0.0.1"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])

   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema tcp:127.0.0.1:$TCP_PORT $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with tcp
# with multiple remotes with only one remote reachable
m4_define([OVSDB_CHECK_IDL_TCP_MULTIPLE_REMOTES_PY],
  [AT_SETUP([$1 - Python3 (multiple remotes) - tcp])
   AT_KEYWORDS([ovsdb server idl positive Python with tcp socket $5])
   OVSDB_START_IDLTEST(["ptcp:0:127.0.0.1"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
   WRONG_PORT_1=$((TCP_PORT + 101))
   WRONG_PORT_2=$((TCP_PORT + 102))
   remote=tcp:127.0.0.1:$WRONG_PORT_1,tcp:127.0.0.1:$TCP_PORT,tcp:127.0.0.1:$WRONG_PORT_2
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t20 idl $srcdir/idltest.ovsschema $remote $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with tcp6
m4_define([OVSDB_CHECK_IDL_TCP6_PY],
  [AT_SETUP([$1 - Python3 - tcp6])
   AT_SKIP_IF([test "$IS_WIN32" = "yes"])
   AT_SKIP_IF([test $HAVE_IPV6 = no])
   AT_KEYWORDS([ovsdb server idl positive Python with tcp6 socket $5])
   OVSDB_START_IDLTEST(["ptcp:0:[[::1]]"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
   echo "TCP_PORT=$TCP_PORT"

   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact "tcp:[[::1]]:$TCP_PORT" $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema tcp:[[::1]]:$TCP_PORT $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_TCP6_MULTIPLE_REMOTES_PY],
  [AT_SETUP([$1 - Python3 - tcp6])
   AT_SKIP_IF([test "$IS_WIN32" = "yes"])
   AT_SKIP_IF([test $HAVE_IPV6 = no])
   AT_KEYWORDS([ovsdb server idl positive Python with tcp6 socket $5])
   OVSDB_START_IDLTEST(["ptcp:0:[[::1]]"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
   WRONG_PORT_1=$((TCP_PORT + 101))
   WRONG_PORT_2=$((TCP_PORT + 102))
   remote="tcp:[[::1]]:$WRONG_PORT_1,tcp:[[::1]]:$TCP_PORT,tcp:[[::1]]:$WRONG_PORT_2"
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact "tcp:[[::1]]:$TCP_PORT" $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t20 idl $srcdir/idltest.ovsschema $remote $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with SSL
m4_define([OVSDB_CHECK_IDL_SSL_PY],
  [AT_SETUP([$1 - Python3 - SSL])
   AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
   $PYTHON3 -c "import ssl"
   SSL_PRESENT=$?
   AT_SKIP_IF([test $SSL_PRESENT != 0])
   AT_KEYWORDS([ovsdb server idl positive Python with ssl socket $5])
   AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
             [0], [stdout], [ignore])
   PKIDIR=$abs_top_builddir/tests
   AT_CHECK([ovsdb-server -vconsole:warn --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])
   on_exit 'kill `cat ovsdb-server.pid`'
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client \
                --private-key=$PKIDIR/testpki-privkey2.pem \
                --certificate=$PKIDIR/testpki-cert2.pem \
                --ca-cert=$PKIDIR/testpki-cacert.pem \
                transact "ssl:127.0.0.1:$TCP_PORT" $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema \
             ssl:127.0.0.1:$TCP_PORT $PKIDIR/testpki-privkey.pem \
             $PKIDIR/testpki-cert.pem $PKIDIR/testpki-cacert.pem $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN(["
     /unexpected SSL connection close/d
     /Protocol error/d
   "])
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL],
  [OVSDB_CHECK_IDL_C($@)
  OVSDB_CHECK_IDL_WRITE_CHANGED_ONLY_C($@)
   OVSDB_CHECK_IDL_TCP_C($@)
   OVSDB_CHECK_IDL_TCP6_C($@)
   OVSDB_CHECK_IDL_PY($@)
   OVSDB_CHECK_IDL_REGISTER_COLUMNS_PY($@)
   OVSDB_CHECK_IDL_TCP_PY($@)
   OVSDB_CHECK_IDL_TCP_MULTIPLE_REMOTES_PY($@)
   OVSDB_CHECK_IDL_TCP6_PY($@)
   OVSDB_CHECK_IDL_TCP6_MULTIPLE_REMOTES_PY($@)
   OVSDB_CHECK_IDL_SSL_PY($@)])

# This test uses the Python IDL implementation with passive tcp
m4_define([OVSDB_CHECK_IDL_PASSIVE_TCP_PY],
  [AT_SETUP([$1 - Python3 - ptcp])
   AT_KEYWORDS([ovsdb server idl positive Python with tcp socket $5])
   # find free TCP port
   OVSDB_START_IDLTEST(["ptcp:0:127.0.0.1"])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
   OVSDB_SERVER_SHUTDOWN
   rm -f db

   # start OVSDB server in passive mode
   OVSDB_START_IDLTEST(["tcp:127.0.0.1:$TCP_PORT"])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py -t10 idl_passive $srcdir/idltest.ovsschema ptcp:127.0.0.1:$TCP_PORT $3],
      [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP
   ])

OVSDB_CHECK_IDL_PASSIVE_TCP_PY([simple passive idl, initially empty, select empty],
  [],
  [['["idltest",{"op":"select","table":"link1","where":[]}]']],
  [[000: empty
001: {"error":null,"result":[{"rows":[]}]}
002: done
]])

OVSDB_CHECK_IDL([simple idl, initially empty, no ops],
  [],
  [],
  [000: empty
001: done
])

OVSDB_CHECK_IDL([simple idl, initially empty, various ops],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"b": true}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"r": 123.5}}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": -1,
               "r": 125,
               "b": false,
               "s": "",
               "ia": ["set", [1]],
               "ra": ["set", [1.5]],
               "ba": ["set", [false]],
               "sa": ["set", []],
               "ua": ["set", []]}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [["i", "<", 1]],
       "row": {"s": "newstring"}}]' \
    '["idltest",
      {"op": "delete",
       "table": "simple",
       "where": [["i", "==", 0]]}]' \
    'reconnect']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
002: table simple: i=0 r=0 b=false s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
002: table simple: i=1 r=2 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
003: {"error":null,"result":[{"count":2}]}
004: table simple: i=0 r=0 b=true s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: table simple: i=1 r=2 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
005: {"error":null,"result":[{"count":2}]}
006: table simple: i=0 r=123.5 b=true s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
006: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
007: {"error":null,"result":[{"uuid":["uuid","<6>"]}]}
008: table simple: i=-1 r=125 b=false s= u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
008: table simple: i=0 r=123.5 b=true s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
008: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
009: {"error":null,"result":[{"count":2}]}
010: table simple: i=-1 r=125 b=false s=newstring u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
010: table simple: i=0 r=123.5 b=true s=newstring u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
010: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
011: {"error":null,"result":[{"count":1}]}
012: table simple: i=-1 r=125 b=false s=newstring u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
012: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
013: reconnect
014: table simple: i=-1 r=125 b=false s=newstring u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
014: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
015: done
]])

OVSDB_CHECK_IDL([simple idl, initially populated],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"b": true}}]']],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
000: table simple: i=1 r=2 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<5>
001: {"error":null,"result":[{"count":2}]}
002: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
002: table simple: i=1 r=2 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<5>
003: done
]])

OVSDB_CHECK_IDL([simple idl, writing via IDL],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['verify 0 b, verify 1 r, set 0 b 1, set 1 r 3.5' \
    'insert 2, verify 2 i, verify 1 b, delete 1']],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
000: table simple: i=1 r=2 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<5>
001: commit, status=success
002: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
002: table simple: i=1 r=3.5 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<5>
003: commit, status=success
004: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: table simple: i=2 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<6>
005: done
]])

OVSDB_CHECK_IDL([simple idl, writing via IDL with unicode],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "(╯°□°）╯︵ ┻━┻"}}]']],
  [['set 0 b 1, insert 1, set 1 s "¯\_(ツ)_/¯"']],
  [[000: table simple: i=0 r=0 b=false s=(╯°□°）╯︵ ┻━┻ u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
001: commit, status=success
002: table simple: i=0 r=0 b=true s=(╯°□°）╯︵ ┻━┻ u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
002: table simple: i=1 r=0 b=false s="¯\_(ツ)_/¯" u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
003: done
]])

m4_define([OVSDB_CHECK_IDL_PY_WITH_EXPOUT],
  [AT_SETUP([$1 - Python3])
   AT_KEYWORDS([ovsdb server idl positive Python $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket $3],
            [0], [stdout], [ignore])
   echo "$4" > expout
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [expout])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

OVSDB_CHECK_IDL_PY_WITH_EXPOUT([simple idl, writing large data via IDL with unicode],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "'$(printf "测试超过四千零九十六个字节的中文字符串以使解码出现问题。%.0s" {1..50})'"}}]']],
  [['set 0 b 1, insert 1, set 1 s '$(printf "测试超过四千零九十六个字节的中文字符串以使解码出现问题。%.0s" {1..100})'']],
  [[000: table simple: i=0 r=0 b=false s=$(printf "测试超过四千零九十六个字节的中文字符串以使解码出现问题。%.0s" {1..50}) u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
001: commit, status=success
002: table simple: i=0 r=0 b=true s=$(printf "测试超过四千零九十六个字节的中文字符串以使解码出现问题。%.0s" {1..50}) u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
002: table simple: i=1 r=0 b=false s=$(printf "测试超过四千零九十六个字节的中文字符串以使解码出现问题。%.0s" {1..100}) u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
003: done]])

OVSDB_CHECK_IDL([simple idl, handling verification failure],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['set 0 b 1' \
    '+["idltest",
       {"op": "update",
        "table": "simple",
        "where": [["i", "==", 1]],
        "row": {"r": 5.0}}]' \
    '+verify 1 r, set 1 r 3' \
    'verify 1 r, set 1 r 3' \
    ]],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
000: table simple: i=1 r=2 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
001: commit, status=success
002: {"error":null,"result":[{"count":1}]}
003: commit, status=try again
004: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: table simple: i=1 r=5 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
005: commit, status=success
006: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
006: table simple: i=1 r=3 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
007: done
]])

OVSDB_CHECK_IDL([simple idl, increment operation],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['set 0 r 2.0, increment 0']],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
001: commit, status=success, increment=1
002: table simple: i=1 r=2 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
003: done
]])

OVSDB_CHECK_IDL([simple idl, aborting],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['set 0 r 2.0, abort' \
'+set 0 b 1']],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
001: commit, status=aborted
002: commit, status=success
003: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: done
]])

OVSDB_CHECK_IDL([simple idl, destroy without commit or abort],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['set 0 r 2.0, destroy' \
'+set 0 b 1']],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
001: destroy
002: commit, status=success
003: table simple: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: done
]])

OVSDB_CHECK_IDL([simple idl, conditional, false condition],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}}]']],
  [['condition simple []' \
    'condition simple [true]']],
  [[000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: done
]])

OVSDB_CHECK_IDL([simple idl, conditional, true condition],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}}]']],
  [['condition simple []' \
    'condition simple [true]']],
  [[000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: done
]])

dnl This test ensures that the first explicitly set monitor condition
dnl is sent to the server.
OVSDB_CHECK_IDL([simple idl, conditional, wait for condition],
  [],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}}]' \
     'condition simple [true]' \
     '^["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 2,
               "r": 4.0,
               "b": true}}]']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
002: table simple: i=1 r=2 b=true s= u=<1> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
003: simple: conditions unchanged
004: {"error":null,"result":[{"uuid":["uuid","<2>"]}]}
005: table simple: i=1 r=2 b=true s= u=<1> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
005: table simple: i=2 r=4 b=true s= u=<1> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
006: done
]])

OVSDB_CHECK_IDL([simple idl, conditional, multiple clauses in condition],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}},
       {"op": "insert",
       "table": "simple",
       "row": {"i": 2,
               "r": 3.0,
               "b": true}}]']],
  [['condition simple []' \
    'condition simple [["i","==",1],["i","==",2]]']],
  [[000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
003: table simple: i=2 r=3 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
004: done
]])

OVSDB_CHECK_IDL([simple idl, conditional, modify as insert due to condition],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}}]']],
  [['condition simple []' \
    'condition simple [["i","==",1]]']],
  [[000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: done
]])

OVSDB_CHECK_IDL([simple idl, conditional, modify as delete due to condition],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}}]']],
  [['condition simple []' \
    'condition simple [["i","==",1],["i","==",2]]' \
    'condition simple [["i","==",2]]' \
    '["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 2,
               "r": 3.0,
               "b": true}}]']],
  [[000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: simple: change conditions
005: empty
006: {"error":null,"result":[{"uuid":["uuid","<2>"]}]}
007: table simple: i=2 r=3 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
008: done
]])

OVSDB_CHECK_IDL([simple idl, conditional, multiple tables],
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true}},
       {"op": "insert",
       "table": "link1",
       "row": {"i": 0, "k": ["named-uuid", "self"]},
       "uuid-name": "self"},
        {"op": "insert",
       "table": "link2",
       "row": {"i": 2},
       "uuid-name": "row0"}]']],
  [['condition simple [];link1 [];link2 []' \
    'condition simple [["i","==",1]]' \
    'condition link1 [["i","==",0]]' \
    'condition link2 [["i","==",3]]' \
    '+["idltest",
       {"op": "insert",
       "table": "link2",
       "row": {"i": 3},
        "uuid-name": "row0"}]']],
  [[000: link1: change conditions
000: link2: change conditions
000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: link1: change conditions
005: table link1: i=0 k=0 ka=[] l2= uuid=<2>
005: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
006: link2: change conditions
007: {"error":null,"result":[{"uuid":["uuid","<3>"]}]}
008: table link1: i=0 k=0 ka=[] l2= uuid=<2>
008: table link2: i=3 l1= uuid=<3>
008: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
009: done
]])

OVSDB_CHECK_IDL([self-linking idl, consistent ops],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link1",
       "row": {"i": 0, "k": ["named-uuid", "self"]},
       "uuid-name": "self"}]' \
    '["idltest",
      {"op": "insert",
       "table": "link1",
       "row": {"i": 1, "k": ["named-uuid", "row2"]},
       "uuid-name": "row1"},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 2, "k": ["named-uuid", "row1"]},
       "uuid-name": "row2"}]' \
    '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [["i", "==", 1]],
       "row": {"k": ["uuid", "#1#"]}}]' \
    '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [],
       "row": {"k": ["uuid", "#0#"]}}]']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
002: table link1: i=0 k=0 ka=[] l2= uuid=<0>
003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
004: table link1: i=0 k=0 ka=[] l2= uuid=<0>
004: table link1: i=1 k=2 ka=[] l2= uuid=<1>
004: table link1: i=2 k=1 ka=[] l2= uuid=<2>
005: {"error":null,"result":[{"count":1}]}
006: table link1: i=0 k=0 ka=[] l2= uuid=<0>
006: table link1: i=1 k=1 ka=[] l2= uuid=<1>
006: table link1: i=2 k=1 ka=[] l2= uuid=<2>
007: {"error":null,"result":[{"count":3}]}
008: table link1: i=0 k=0 ka=[] l2= uuid=<0>
008: table link1: i=1 k=0 ka=[] l2= uuid=<1>
008: table link1: i=2 k=0 ka=[] l2= uuid=<2>
009: done
]])

OVSDB_CHECK_IDL([self-linking idl, inconsistent ops],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link1",
       "row": {"i": 0, "k": ["uuid", "cf197cc5-c8c9-42f5-82d5-c71a9f2cb96b"]}}]' \
    '+["idltest",
      {"op": "insert",
       "table": "link1",
       "uuid-name": "one",
       "row": {"i": 1, "k": ["named-uuid", "one"]}},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 2, "k": ["named-uuid", "one"]}}]' \
     '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [],
       "row": {"k": ["uuid", "c2fca39a-e69a-42a4-9c56-5eca85839ce9"]}}]' \
     '+["idltest",
      {"op": "delete",
       "table": "link1",
       "where": [["_uuid", "==", ["uuid", "#1#"]]]}]' \
     '+["idltest",
      {"op": "delete",
       "table": "link1",
       "where": [["_uuid", "==", ["uuid", "#2#"]]]}]' \
     '["idltest",
      {"op": "delete",
       "table": "link1",
       "where": []}]' \
]],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"details":"Table link1 column k row <0> references nonexistent row <1> in table link1.","error":"referential integrity violation"}]}
002: {"error":null,"result":[{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
003: table link1: i=1 k=1 ka=[] l2= uuid=<2>
003: table link1: i=2 k=1 ka=[] l2= uuid=<3>
004: {"error":null,"result":[{"count":2},{"details":"Table link1 column k row <x> references nonexistent row <4> in table link1.","error":"referential integrity violation"}]}
005: {"error":null,"result":[{"count":1},{"details":"cannot delete link1 row <2> because of 1 remaining reference(s)","error":"referential integrity violation"}]}
006: {"error":null,"result":[{"count":1}]}
007: table link1: i=1 k=1 ka=[] l2= uuid=<2>
008: {"error":null,"result":[{"count":1}]}
009: empty
010: done
]],
  [],
  [[sed -e '/004:/s/row <[23]> references/row <x> references/']])

OVSDB_CHECK_IDL([self-linking idl, sets],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link1",
       "row": {"i": 0, "k": ["named-uuid", "i0"], "ka": ["set", [["named-uuid", "i0"]]]},
       "uuid-name": "i0"},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 1, "k": ["named-uuid", "i0"], "ka": ["set", [["named-uuid", "i1"]]]},
       "uuid-name": "i1"},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 2, "k": ["named-uuid", "i0"], "ka": ["set", [["named-uuid", "i2"]]]},
       "uuid-name": "i2"},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 3, "k": ["named-uuid", "i0"], "ka": ["set", [["named-uuid", "i3"]]]},
       "uuid-name": "i3"}]' \
    '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [],
       "row": {"ka": ["set", [["uuid", "#0#"], ["uuid", "#1#"], ["uuid", "#2#"], ["uuid", "#3#"]]]}}]' \
    '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [["i", "==", 2]],
       "row": {"ka": ["set", [["uuid", "#0#"], ["uuid", "88702e78-845b-4a6e-ad08-cf68922ae84a"], ["uuid", "#2#"]]]}}]' \
    '+["idltest",
      {"op": "delete",
       "table": "link1",
       "where": []}]']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
002: table link1: i=0 k=0 ka=[0] l2= uuid=<0>
002: table link1: i=1 k=0 ka=[1] l2= uuid=<1>
002: table link1: i=2 k=0 ka=[2] l2= uuid=<2>
002: table link1: i=3 k=0 ka=[3] l2= uuid=<3>
003: {"error":null,"result":[{"count":4}]}
004: table link1: i=0 k=0 ka=[0 1 2 3] l2= uuid=<0>
004: table link1: i=1 k=0 ka=[0 1 2 3] l2= uuid=<1>
004: table link1: i=2 k=0 ka=[0 1 2 3] l2= uuid=<2>
004: table link1: i=3 k=0 ka=[0 1 2 3] l2= uuid=<3>
005: {"error":null,"result":[{"count":1},{"details":"Table link1 column ka row <2> references nonexistent row <4> in table link1.","error":"referential integrity violation"}]}
006: {"error":null,"result":[{"count":4}]}
007: empty
008: done
]])

OVSDB_CHECK_IDL([external-linking idl, consistent ops],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link2",
       "row": {"i": 0},
       "uuid-name": "row0"},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 1, "k": ["named-uuid", "row1"], "l2": ["set", [["named-uuid", "row0"]]]},
       "uuid-name": "row1"}]']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
002: table link1: i=1 k=1 ka=[] l2=0 uuid=<1>
002: table link2: i=0 l1= uuid=<0>
003: done
]])

OVSDB_CHECK_IDL([singleton idl, constraints],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "singleton",
       "row": {"name": "foo"}}]' \
    '["idltest",
      {"op": "insert",
       "table": "singleton",
       "row": {"name": "bar"}}]' \
    '+["idltest",
      {"op": "delete",
       "table": "singleton",
       "where": [["_uuid", "==", ["uuid", "#0#"]]]},
      {"op": "insert",
       "table": "singleton",
       "row": {"name": "bar"}}]']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
002: table singleton: name=foo uuid=<0>
003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"details":"transaction causes \"singleton\" table to contain 2 rows, greater than the schema-defined limit of 1 row(s)","error":"constraint violation"}]}
004: {"error":null,"result":[{"count":1},{"uuid":["uuid","<2>"]}]}
005: table singleton: name=bar uuid=<2>
006: done
]])

dnl This test creates a database with references and checks that deleting both
dnl source and destination rows of a reference in a single update doesn't leak
dnl rows that got orphaned when processing the update.
OVSDB_CHECK_IDL([simple idl, references, multiple deletes],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"},
       "uuid-name": "weak_row0"},
      {"op": "insert",
       "table": "simple6",
       "row": {"name": "first_row",
               "weak_ref": ["set",
                             [["named-uuid", "weak_row0"]]
                           ]}}]']],
  [['["idltest",
      {"op": "delete",
       "table": "simple",
       "where": [["s", "==", "row0_s"]]},
      {"op": "delete",
       "table": "simple6",
       "where": [["name", "==", "first_row"]]}]']],
  [[000: table simple6: name=first_row weak_ref=[<0>] uuid=<1>
000: table simple: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
001: {"error":null,"result":[{"count":1},{"count":1}]}
002: empty
003: done
]])

OVSDB_CHECK_IDL_PY([external-linking idl, insert ops],
  [],
  [['linktest']],
  [[000: empty
001: commit, status=success
002: table link1: i=1 k=1 ka=[1] l2= uuid=<0>
002: table link1: i=2 k=1 ka=[1 2] l2= uuid=<1>
003: done
]])

OVSDB_CHECK_IDL_PY([getattr idl, insert ops],
  [],
  [['getattrtest']],
  [[000: empty
001: commit, status=success
002: table link1: i=2 k=2 ka=[] l2= uuid=<0>
003: done
]])

OVSDB_CHECK_IDL_PY([row-from-json idl, whats this],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['notifytest insert 2, notifytest set 1 b 1, notifytest delete 0']],
  [[000: table simple: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
000: table simple: i=1 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
001: commit, status=success, events=create|2|None, delete|0|None, update|1|b
002: table simple: i=1 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
002: table simple: i=2 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
003: done
]])

AT_SETUP([idl handling of missing tables and columns - C])
AT_KEYWORDS([ovsdb server idl positive])

# idltest2.ovsschema is the same as idltest.ovsschema, except that
# table link2 and column l2 have been deleted.  But the IDL still
# expects them to be there, so this test checks that it properly
# tolerates them being missing.
OVSDB_START_IDLTEST([], ["$abs_srcdir/idltest2.ovsschema"])
AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket ['["idltest",
      {"op": "insert",
       "table": "link1",
       "row": {"i": 0, "k": ["named-uuid", "self"]},
       "uuid-name": "self"}]' \
    '["idltest",
      {"op": "insert",
       "table": "link1",
       "row": {"i": 1, "k": ["named-uuid", "row2"]},
       "uuid-name": "row1"},
      {"op": "insert",
       "table": "link1",
       "row": {"i": 2, "k": ["named-uuid", "row1"]},
       "uuid-name": "row2"}]' \
    '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [["i", "==", 1]],
       "row": {"k": ["uuid", "#1#"]}}]' \
    '["idltest",
      {"op": "update",
       "table": "link1",
       "where": [],
       "row": {"k": ["uuid", "#0#"]}}]']],
         [0], [stdout], [stderr])
AT_CHECK([sort stdout | uuidfilt], [0],
    [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
002: table link1: i=0 k=0 ka=[] l2= uuid=<0>
003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
004: table link1: i=0 k=0 ka=[] l2= uuid=<0>
004: table link1: i=1 k=2 ka=[] l2= uuid=<1>
004: table link1: i=2 k=1 ka=[] l2= uuid=<2>
005: {"error":null,"result":[{"count":1}]}
006: table link1: i=0 k=0 ka=[] l2= uuid=<0>
006: table link1: i=1 k=1 ka=[] l2= uuid=<1>
006: table link1: i=2 k=1 ka=[] l2= uuid=<2>
007: {"error":null,"result":[{"count":3}]}
008: table link1: i=0 k=0 ka=[] l2= uuid=<0>
008: table link1: i=1 k=0 ka=[] l2= uuid=<1>
008: table link1: i=2 k=0 ka=[] l2= uuid=<2>
009: done
]])

# Check that ovsdb-idl figured out that table link2 and column l2 are missing.
AT_CHECK([grep ovsdb_idl stderr | sort], [0], [dnl
test-ovsdb|ovsdb_idl|idltest database lacks indexed table (database needs upgrade?)
test-ovsdb|ovsdb_idl|idltest database lacks link2 table (database needs upgrade?)
test-ovsdb|ovsdb_idl|idltest database lacks simple5 table (database needs upgrade?)
test-ovsdb|ovsdb_idl|idltest database lacks simple6 table (database needs upgrade?)
test-ovsdb|ovsdb_idl|idltest database lacks singleton table (database needs upgrade?)
test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column (database needs upgrade?)
test-ovsdb|ovsdb_idl|simple7 table in idltest database lacks id column (database needs upgrade?)
])

# Check that ovsdb-idl sent on "monitor" request and that it didn't
# mention that table or column, and (for paranoia) that it did mention another
# table and column.
AT_CHECK([grep -c '"monitor\|monitor_cond"' stderr], [0], [2
])
AT_CHECK([grep '"monitor\|monitor_cond"' stderr | grep link2], [1])
AT_CHECK([grep '"monitor\|monitor_cond"' stderr | grep l2], [1])
AT_CHECK([grep '"monitor\|monitor_cond"' stderr | grep -c '"link1"'], [0], [1
])
AT_CHECK([grep '"monitor\|monitor_cond"' stderr | grep -c '"ua"'], [0], [1
])
OVSDB_SERVER_SHUTDOWN
AT_CLEANUP

m4_define([OVSDB_CHECK_IDL_FETCH_COLUMNS_PY],
  [AT_SETUP([$1 - Python3 - fetch])
   AT_KEYWORDS([ovsdb server idl positive Python increment fetch $6])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket [$3] $4],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]),
            [0], [$5])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_FETCH_COLUMNS],
   [OVSDB_CHECK_IDL_FETCH_COLUMNS_PY($@)])

OVSDB_CHECK_IDL_FETCH_COLUMNS([simple idl, initially populated],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [?simple:i,r!],
  ['fetch 0 r'],
  [[000: table simple: i=0 uuid=<0>
000: table simple: i=1 uuid=<1>
001: commit, status=success
002: table simple: i=0 r=0 uuid=<0>
002: table simple: i=1 uuid=<1>
003: done
]])

m4_define([OVSDB_CHECK_IDL_WO_MONITOR_COND_PY],
  [AT_SETUP([$1 - Python3])
   AT_KEYWORDS([ovsdb server idl Python monitor $4])
   OVSDB_START_IDLTEST
   AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/disable-monitor-cond])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket $2],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$5],,, [[| $5]]),
            [0], [$3])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_WO_MONITOR_COND],
   [OVSDB_CHECK_IDL_WO_MONITOR_COND_PY($@)])


OVSDB_CHECK_IDL_WO_MONITOR_COND([simple idl disable monitor-cond],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"b": true}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"r": 123.5}}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": -1,
               "r": 125,
               "b": false,
               "s": "",
               "ia": ["set", [1]],
               "ra": ["set", [1.5]],
               "ba": ["set", [false]],
               "sa": ["set", []],
               "ua": ["set", []]}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [["i", "<", 1]],
       "row": {"s": "newstring"}}]' \
    '["idltest",
      {"op": "delete",
       "table": "simple",
       "where": [["i", "==", 0]]}]' \
    'reconnect']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
002: table simple: i=0 r=0 b=false s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
002: table simple: i=1 r=2 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
003: {"error":null,"result":[{"count":2}]}
004: table simple: i=0 r=0 b=true s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: table simple: i=1 r=2 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
005: {"error":null,"result":[{"count":2}]}
006: table simple: i=0 r=123.5 b=true s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
006: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
007: {"error":null,"result":[{"uuid":["uuid","<6>"]}]}
008: table simple: i=-1 r=125 b=false s= u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
008: table simple: i=0 r=123.5 b=true s= u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
008: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
009: {"error":null,"result":[{"count":2}]}
010: table simple: i=-1 r=125 b=false s=newstring u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
010: table simple: i=0 r=123.5 b=true s=newstring u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
010: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
011: {"error":null,"result":[{"count":1}]}
012: table simple: i=-1 r=125 b=false s=newstring u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
012: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
013: reconnect
014: table simple: i=-1 r=125 b=false s=newstring u=<2> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
014: table simple: i=1 r=123.5 b=true s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
015: done
]])

m4_define([OVSDB_CHECK_IDL_TRACK_C],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl tracking positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_TRACK_WRITE_CHANGED_ONLY_C],
  [AT_SETUP([$1 - write-changed-only - C])
   AT_KEYWORDS([ovsdb server idl tracking positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c --write-changed-only idl unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_TRACK],
  [OVSDB_CHECK_IDL_TRACK_C($@)
   OVSDB_CHECK_IDL_TRACK_WRITE_CHANGED_ONLY_C($@)])

OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]']],
  [['["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"b": true}}]']],
  [[000: table simple: inserted row: i=1 r=2 b=true s=mystring u=<0> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<1> <2>] uuid=<3>
000: table simple: updated columns: b ba i ia r ra s sa u ua
001: {"error":null,"result":[{"count":2}]}
002: table simple: i=0 r=0 b=true s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<5>
002: table simple: i=1 r=2 b=true s=mystring u=<0> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<1> <2>] uuid=<3>
002: table simple: updated columns: b
003: done
]])

dnl This test creates database with weak references and checks that orphan
dnl rows created for weak references are not available for iteration via
dnl list of tracked changes.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, orphan weak references],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"},
       "uuid-name": "weak_row0"},
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row1_s"},
       "uuid-name": "weak_row1"},
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row2_s"},
       "uuid-name": "weak_row2"},
      {"op": "insert",
       "table": "simple6",
       "row": {"name": "first_row",
               "weak_ref": ["set",
                             [["named-uuid", "weak_row0"],
                              ["named-uuid", "weak_row1"],
                              ["named-uuid", "weak_row2"]]
                           ]}}]']],
  [['condition simple []' \
    'condition simple [["s","==","row1_s"]]' \
    '["idltest",
      {"op": "update",
      "table": "simple6",
      "where": [],
      "row": {"name": "new_name"}}]' \
    '["idltest",
      {"op": "delete",
      "table": "simple6",
      "where": []}]']],
  [[000: simple: change conditions
001: table simple6: inserted row: name=first_row weak_ref=[] uuid=<0>
001: table simple6: updated columns: name weak_ref
002: simple: change conditions
003: table simple6: name=first_row weak_ref=[<1>] uuid=<0>
003: table simple: inserted row: i=0 r=0 b=false s=row1_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
003: table simple: updated columns: s
004: {"error":null,"result":[{"count":1}]}
005: table simple6: name=new_name weak_ref=[<1>] uuid=<0>
005: table simple6: updated columns: name
006: {"error":null,"result":[{"count":1}]}
007: table simple: i=0 r=0 b=false s=row1_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
008: done
]])

dnl This test creates database with weak references and checks that the
dnl content of orphaned rows created for weak references after monitor
dnl condition change are not leaked when the row is reinserted and deleted.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, orphan rows, conditional],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"},
       "uuid-name": "weak_row0"},
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row1_s"},
       "uuid-name": "weak_row1"},
      {"op": "insert",
       "table": "simple6",
       "row": {"name": "first_row",
               "weak_ref": ["set",
                             [["named-uuid", "weak_row0"]]
                           ]}}]']],
  [['condition simple []' \
    'condition simple [["s","==","row0_s"]]' \
    'condition simple [["s","==","row1_s"]]' \
    'condition simple [["s","==","row0_s"]]' \
    '["idltest",
      {"op": "delete",
      "table": "simple6",
      "where": []}]']],
  [[000: simple: change conditions
001: table simple6: inserted row: name=first_row weak_ref=[] uuid=<0>
001: table simple6: updated columns: name weak_ref
002: simple: change conditions
003: table simple6: name=first_row weak_ref=[<1>] uuid=<0>
003: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
003: table simple: updated columns: s
004: simple: change conditions
005: table simple6: name=first_row weak_ref=[] uuid=<0>
005: table simple: deleted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
005: table simple: inserted row: i=0 r=0 b=false s=row1_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
005: table simple: updated columns: s
006: simple: change conditions
007: table simple6: name=first_row weak_ref=[<1>] uuid=<0>
007: table simple: deleted row: i=0 r=0 b=false s=row1_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
007: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
007: table simple: updated columns: s
008: {"error":null,"result":[{"count":1}]}
009: table simple: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
010: done
]])

dnl This test checks that deleting the destination of a weak reference
dnl without deleting the source, through monitor condition change, updates
dnl the source tracked record.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, references, conditional delete],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s", "i": 0},
       "uuid-name": "weak_row0"},
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row1_s", "i": 1},
       "uuid-name": "weak_row1"},
      {"op": "insert",
       "table": "simple6",
       "row": {"name": "first_row",
               "weak_ref": ["set",
                             [["named-uuid", "weak_row0"],
                              ["named-uuid", "weak_row1"]]
                           ]}}]']],
  [['condition simple []' \
    'condition simple [["s","==","row0_s"]]' \
    'condition simple [["s","==","row1_s"]]' \
    '["idltest",
      {"op": "update",
      "table": "simple6",
      "where": [],
      "row": {"name": "new_name"}}]' \
    '["idltest",
      {"op": "delete",
      "table": "simple6",
      "where": []}]']],
  [[000: simple: change conditions
001: table simple6: inserted row: name=first_row weak_ref=[] uuid=<0>
001: table simple6: updated columns: name weak_ref
002: simple: change conditions
003: table simple6: name=first_row weak_ref=[<1>] uuid=<0>
003: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
003: table simple: updated columns: s
004: simple: change conditions
005: table simple6: name=first_row weak_ref=[<3>] uuid=<0>
005: table simple: deleted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
005: table simple: inserted row: i=1 r=0 b=false s=row1_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
005: table simple: updated columns: i s
006: {"error":null,"result":[{"count":1}]}
007: table simple6: name=new_name weak_ref=[<3>] uuid=<0>
007: table simple6: updated columns: name
008: {"error":null,"result":[{"count":1}]}
009: table simple: i=1 r=0 b=false s=row1_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
010: done
]])

dnl This test checks that deleting the destination of a reference updates the
dnl source tracked record.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, references, single delete],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"},
       "uuid-name": "uuid_row0_s"},
      {"op": "insert",
       "table": "simple6",
       "row": {"name": "row0_s6",
               "weak_ref": ["set",
                             [["named-uuid", "uuid_row0_s"]]
                           ]}}]']],
  [['condition simple [true];simple6 [true]' \
    '["idltest",
      {"op": "delete",
       "table": "simple",
       "where": []}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"}}]']],
  [[000: simple6: conditions unchanged
000: simple: conditions unchanged
001: table simple6: inserted row: name=row0_s6 weak_ref=[<0>] uuid=<1>
001: table simple6: updated columns: name weak_ref
001: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
001: table simple: updated columns: s
002: {"error":null,"result":[{"count":1}]}
003: table simple6: name=row0_s6 weak_ref=[] uuid=<1>
003: table simple6: updated columns: weak_ref
003: table simple: deleted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
004: {"error":null,"result":[{"uuid":["uuid","<3>"]}]}
005: table simple6: name=row0_s6 weak_ref=[] uuid=<1>
005: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
005: table simple: updated columns: s
006: done
]])

dnl This test checks that deleting both the destination and source of the
dnl reference doesn't remove the reference in the source tracked record.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, weak references, multiple deletes],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"},
       "uuid-name": "uuid_row0_s"},
      {"op": "insert",
       "table": "simple6",
       "row": {"name": "row0_s6",
               "weak_ref": ["set",
                             [["named-uuid", "uuid_row0_s"]]
                           ]}}]']],
  [['condition simple [true];simple6 [true]' \
    '["idltest",
      {"op": "delete",
       "table": "simple",
       "where": []},
      {"op": "delete",
       "table": "simple6",
       "where": []}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"}}]']],
  [[000: simple6: conditions unchanged
000: simple: conditions unchanged
001: table simple6: inserted row: name=row0_s6 weak_ref=[<0>] uuid=<1>
001: table simple6: updated columns: name weak_ref
001: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
001: table simple: updated columns: s
002: {"error":null,"result":[{"count":1},{"count":1}]}
003: table simple6: deleted row: name=row0_s6 weak_ref=[<0>] uuid=<1>
003: table simple: deleted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<0>
004: {"error":null,"result":[{"uuid":["uuid","<3>"]}]}
005: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<2> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
005: table simple: updated columns: s
006: done
]])

dnl This test checks that deleting both the destination and source of the
dnl reference doesn't remove the reference in the source tracked record.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, strong references, multiple deletes],
  [['["idltest",
      {"op": "insert",
       "table": "simple4",
       "row": {"name": "row0_s4"},
       "uuid-name": "uuid_row0_s4"},
      {"op": "insert",
       "table": "simple3",
       "row": {"name": "row0_s3",
               "uref": ["set",
                         [["named-uuid", "uuid_row0_s4"]]
                       ]}}]']],
  [['condition simple [true];simple3 [true];simple4 [true]' \
    '["idltest",
      {"op": "delete",
       "table": "simple3",
       "where": []},
      {"op": "delete",
       "table": "simple4",
       "where": []}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"}}]']],
  [[000: simple3: conditions unchanged
000: simple4: conditions unchanged
000: simple: conditions unchanged
001: table simple3: inserted row: name=row0_s3 uset=[] uref=[<0>] uuid=<1>
001: table simple3: updated columns: name uref
001: table simple4: inserted row: name=row0_s4 uuid=<0>
001: table simple4: updated columns: name
002: {"error":null,"result":[{"count":1},{"count":1}]}
003: table simple3: deleted row: name=row0_s3 uset=[] uref=[<0>] uuid=<1>
003: table simple4: deleted row: name=row0_s4 uuid=<0>
004: {"error":null,"result":[{"uuid":["uuid","<2>"]}]}
005: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<3> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
005: table simple: updated columns: s
006: done
]])

dnl This test checks that changing conditions to not include the target of
dnl a strong reference also updates the source row when change tracking is
dnl enabled.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated, strong references, conditional],
  [['["idltest",
      {"op": "insert",
       "table": "simple4",
       "row": {"name": "row0_s4"},
       "uuid-name": "uuid_row0_s4"},
      {"op": "insert",
       "table": "simple3",
       "row": {"name": "row0_s3",
               "uref": ["set",
                         [["named-uuid", "uuid_row0_s4"]]
                       ]}}]']],
  [['condition simple [true];simple3 [true];simple4 [true]' \
    'condition simple4 []' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"}}]']],
  [[000: simple3: conditions unchanged
000: simple4: conditions unchanged
000: simple: conditions unchanged
001: table simple3: inserted row: name=row0_s3 uset=[] uref=[<0>] uuid=<1>
001: table simple3: updated columns: name uref
001: table simple4: inserted row: name=row0_s4 uuid=<0>
001: table simple4: updated columns: name
002: simple4: change conditions
003: table simple3: name=row0_s3 uset=[] uref=[] uuid=<1>
003: table simple4: deleted row: name=row0_s4 uuid=<0>
004: {"error":null,"result":[{"uuid":["uuid","<2>"]}]}
005: table simple3: name=row0_s3 uset=[] uref=[] uuid=<1>
005: table simple: inserted row: i=0 r=0 b=false s=row0_s u=<3> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
005: table simple: updated columns: s
006: done
]])

dnl This test checks that changing conditions to not include the target of
dnl a strong reference also updates the source row when change tracking is
dnl disabled.
OVSDB_CHECK_IDL([simple idl, initially populated, strong references, conditional],
  [['["idltest",
      {"op": "insert",
       "table": "simple4",
       "row": {"name": "row0_s4"},
       "uuid-name": "uuid_row0_s4"},
      {"op": "insert",
       "table": "simple3",
       "row": {"name": "row0_s3",
               "uref": ["set",
                         [["named-uuid", "uuid_row0_s4"]]
                       ]}}]']],
  [['condition simple [true];simple3 [true];simple4 [true]' \
    'condition simple4 []' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"s": "row0_s"}}]']],
  [[000: simple3: conditions unchanged
000: simple4: conditions unchanged
000: simple: conditions unchanged
001: table simple3: name=row0_s3 uset=[] uref=[<0>] uuid=<1>
001: table simple4: name=row0_s4 uuid=<0>
002: simple4: change conditions
003: table simple3: name=row0_s3 uset=[] uref=[] uuid=<1>
004: {"error":null,"result":[{"uuid":["uuid","<2>"]}]}
005: table simple3: name=row0_s3 uset=[] uref=[] uuid=<1>
005: table simple: i=0 r=0 b=false s=row0_s u=<3> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
006: done
]])

dnl This test checks that deleting a row that refers to a row that was inserted
dnl in the current IDL run works properly.
OVSDB_CHECK_IDL_TRACK([track, simple idl, initially empty, strong references, insert and delete],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link1",
       "uuid-name": "uuid_l1",
       "row": {"i": 1, "k": ["named-uuid", "uuid_l1"]}},
      {"op": "insert",
       "table": "link2",
       "row": {"i": 2, "l1": ["set", [["named-uuid", "uuid_l1"]]]}}
      ]' \
    '+["idltest",
      {"op": "delete",
       "table": "link2",
       "where": [["i", "==", 2]]}]'
  ]],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
002: {"error":null,"result":[{"count":1}]}
003: table link1: inserted row: i=1 k=1 ka=[] l2= uuid=<0>
003: table link1: updated columns: i k
004: done
]])

OVSDB_CHECK_IDL_TRACK([track, simple idl, initially empty, various ops],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"b": true}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"r": 123.5}}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": -1,
               "r": 125,
               "b": false,
               "s": "",
               "ia": ["set", [1]],
               "ra": ["set", [1.5]],
               "ba": ["set", [false]],
               "sa": ["set", []],
               "ua": ["set", []]}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [["i", "<", 1]],
       "row": {"s": "newstring"}}]' \
    '["idltest",
      {"op": "delete",
       "table": "simple",
       "where": [["i", "==", 0]]}]' \
    'reconnect']],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
002: table simple: inserted row: i=1 r=2 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0>
002: table simple: updated columns: b ba i ia r ra s sa u ua
003: {"error":null,"result":[{"count":2}]}
004: table simple: i=0 r=0 b=true s= u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: table simple: updated columns: b
005: {"error":null,"result":[{"count":2}]}
006: table simple: i=0 r=123.5 b=true s= u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
006: table simple: i=1 r=123.5 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0>
006: table simple: updated columns: r
006: table simple: updated columns: r
007: {"error":null,"result":[{"uuid":["uuid","<6>"]}]}
008: table simple: inserted row: i=-1 r=125 b=false s= u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
008: table simple: updated columns: ba i ia r ra
009: {"error":null,"result":[{"count":2}]}
010: table simple: i=-1 r=125 b=false s=newstring u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
010: table simple: i=0 r=123.5 b=true s=newstring u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
010: table simple: updated columns: s
010: table simple: updated columns: s
011: {"error":null,"result":[{"count":1}]}
012: table simple: deleted row: i=0 r=123.5 b=true s=newstring u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
013: reconnect
014: table simple: inserted row: i=-1 r=125 b=false s=newstring u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6>
014: table simple: inserted row: i=1 r=123.5 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0>
014: table simple: updated columns: b ba i ia r ra s sa u ua
014: table simple: updated columns: ba i ia r ra s
015: done
]])

m4_define([OVSDB_CHECK_IDL_PARTIAL_UPDATE_MAP_COLUMN],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl partial update map column positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-partial-update-map-column unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

OVSDB_CHECK_IDL_PARTIAL_UPDATE_MAP_COLUMN([map, simple2 idl-partial-update-map-column, initially populated],
[['["idltest", {"op":"insert", "table":"simple2",
                "row":{"name":"myString1","smap":["map",[["key1","value1"],["key2","value2"]]]} }]']
],
[],
[[000: Getting records
001: name=myString1 smap=[[key1 : value1],[key2 : value2]] imap=[]
002: After insert element
003: name=String2 smap=[[key1 : myList1],[key2 : value2]] imap=[[3 : myids2]]
004: After insert duplicated element
005: name=String2 smap=[[key1 : myList1],[key2 : value2]] imap=[[3 : myids2]]
006: After delete element
007: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]]
008: After trying to delete a deleted element
009: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]]
010: End test
]])

OVSDB_CHECK_IDL_PY([partial-map idl],
[['["idltest", {"op":"insert", "table":"simple2",
                "row":{"name":"myString1","smap":["map",[["key1","value1"],["key2","value2"]]]} }]']
],
  [?simple2:name,smap,imap 'partialmapinsertelement' 'partialmapinsertmultipleelements' 'partialmapdelelements' 'partialmapmutatenew'],
[[000: table simple2: name=myString1 smap=[(key1 value1) (key2 value2)] imap=[] uuid=<0>
001: commit, status=success
002: table simple2: name=String2 smap=[(key1 myList1) (key2 value2)] imap=[(3 myids2)] uuid=<0>
003: commit, status=success
004: table simple2: name=String2 smap=[(key1 myList1) (key2 myList2) (key3 myList3) (key4 myList4)] imap=[(3 myids2)] uuid=<0>
005: commit, status=success
006: table simple2: name=String2 smap=[(key2 myList2)] imap=[(3 myids2)] uuid=<0>
007: commit, status=success
008: table simple2: name=String2 smap=[(key2 myList2)] imap=[(3 myids2)] uuid=<0>
008: table simple2: name=String2New smap=[(key1 newList1) (key2 newList2)] imap=[] uuid=<1>
009: done
]])

OVSDB_CHECK_IDL_PY([partial-map update set refmap idl],
[['["idltest", {"op":"insert", "table":"simple3", "row":{"name":"myString1"}},
               {"op":"insert", "table":"simple5", "row":{"name":"myString2"}}]']],
['partialmapmutateirefmap'],
[[000: table simple3: name=myString1 uset=[] uref=[] uuid=<0>
000: table simple5: name=myString2 irefmap=[] uuid=<1>
001: commit, status=success
002: table simple3: name=myString1 uset=[] uref=[] uuid=<0>
002: table simple5: name=myString2 irefmap=[(1 <0>)] uuid=<1>
003: done
]])

m4_define([OVSDB_CHECK_IDL_PARTIAL_UPDATE_SET_COLUMN],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl partial update set column positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-partial-update-set-column unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

OVSDB_CHECK_IDL_PARTIAL_UPDATE_SET_COLUMN([set, simple3 idl-partial-update-set-column, initially populated],
[['["idltest", {"op":"insert", "table":"simple3",
                "row":{"name":"mySet1","uset":["set", [[ "uuid", "0005b872-f9e5-43be-ae02-3184b9680e75" ], [ "uuid", "000d2f6a-76af-412f-b59d-e7bcd3e84eff" ]]]} }]']
],
[],
[[000: Getting records
001: table simple3: name=mySet1 uset=[<0>,<1>] uref=[] uuid=<2>
002: After rename+add new value
003: table simple3: name=String2 uset=[<0>,<1>,<3>] uref=[] uuid=<2>
004: After add new value
005: table simple3: name=String2 uset=[<0>,<1>,<3>,<4>] uref=[] uuid=<2>
006: After delete value
007: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[] uuid=<2>
008: After trying to delete a deleted value
009: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[] uuid=<2>
010: After add to other table + set of strong ref
011: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[<5>] uuid=<2>
012: End test
]])

OVSDB_CHECK_IDL_PY([partial-set idl],
[['["idltest", {"op":"insert", "table":"simple3", "uuid-name":"newrow",
                    "row":{"name":"mySet1","uset":["set", [[ "uuid", "0005b872-f9e5-43be-ae02-3184b9680e75" ]]]} },
               {"op":"insert", "table":"simple4", "row":{"name":"seed"}},
               {"op":"mutate", "table":"simple3", "where":[["_uuid", "==", ["named-uuid", "newrow"]]],
                    "mutations": [["uset", "insert", ["set", [["uuid", "000d2f6a-76af-412f-b59d-e7bcd3e84eff"]]]]]}]']
],
  ['partialrenamesetadd' 'partialduplicateadd' 'partialsetdel' 'partialsetref' 'partialsetoverrideops' 'partialsetadddelete' 'partialsetmutatenew'],
[[000: table simple3: name=mySet1 uset=[<0> <1>] uref=[] uuid=<2>
001: commit, status=success
002: table simple3: name=String2 uset=[<0> <1> <3>] uref=[] uuid=<2>
003: commit, status=success
004: table simple3: name=String2 uset=[<0> <1> <3> <4>] uref=[] uuid=<2>
005: commit, status=success
006: table simple3: name=String2 uset=[<0> <1> <4>] uref=[] uuid=<2>
007: commit, status=success
008: table simple3: name=String2 uset=[<0> <1> <4>] uref=[<5>] uuid=<2>
008: table simple4: name=test uuid=<5>
009: commit, status=success
010: table simple3: name=String2 uset=[<4>] uref=[<5>] uuid=<2>
010: table simple4: name=test uuid=<5>
011: commit, status=success
012: table simple3: name=String2 uset=[<6> <7>] uref=[<5>] uuid=<2>
012: table simple4: name=test uuid=<5>
013: commit, status=success
014: table simple3: name=String2 uset=[<6> <7>] uref=[<5>] uuid=<2>
014: table simple3: name=String3 uset=[<8>] uref=[] uuid=<9>
014: table simple4: name=test uuid=<5>
015: done
]])

m4_define([OVSDB_CHECK_IDL_NOTIFY],
   [OVSDB_CHECK_IDL_PY([$1], [], [$2], [$3], [notify $4], [$5])
    OVSDB_CHECK_IDL_SSL_PY([$1], [], [$2], [$3], [notify $4], [$5])])

OVSDB_CHECK_IDL_NOTIFY([simple link idl verify notify],
  [['track-notify' \
    '["idltest",
       {"op": "insert",
       "table": "link1",
       "row": {"i": 1, "k": ["named-uuid", "l1row"], "l2": ["set", [["named-uuid", "l2row"]]]},
       "uuid-name": "l1row"},
      {"op": "insert",
       "table": "link2",
       "uuid-name": "l2row",
       "row": {"i": 2, "l1": ["set", [["named-uuid", "l1row"]]]}}]']],
[[000: empty
000: event:create, row={}, uuid=<0>, updates=None
000: event:create, row={}, uuid=<1>, updates=None
001: {"error":null,"result":[{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
002: event:create, row={i=1 l2=[<3>]}, uuid=<2>, updates=None
002: event:create, row={i=2 l1=[<2>]}, uuid=<3>, updates=None
002: table link1: i=1 k=1 ka=[] l2=2 uuid=<2>
002: table link2: i=2 l1=1 uuid=<3>
003: done
]])

OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
  [['track-notify' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 2.0,
               "b": true,
               "s": "mystring",
               "u": ["uuid", "84f5c8f5-ac76-4dbc-a24f-8860eb407fc1"],
               "ia": ["set", [1, 2, 3]],
               "ra": ["set", [-0.5]],
               "ba": ["set", [true]],
               "sa": ["set", ["abc", "def"]],
               "ua": ["set", [["uuid", "69443985-7806-45e2-b35f-574a04e720f9"],
                              ["uuid", "aad11ef0-816a-4b01-93e6-03b8b4256b98"]]]}},
      {"op": "insert",
       "table": "simple",
       "row": {}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"b": false}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [],
       "row": {"r": 123.5}}]' \
    '["idltest",
      {"op": "insert",
       "table": "simple",
       "row": {"i": -1,
               "r": 125,
               "b": false,
               "s": "",
               "ia": ["set", [1]],
               "ra": ["set", [1.5]],
               "ba": ["set", [false]],
               "sa": ["set", []],
               "ua": ["set", []]}}]' \
    '["idltest",
      {"op": "update",
       "table": "simple",
       "where": [["i", "<", 1]],
       "row": {"s": "newstring"}}]' \
    '["idltest",
      {"op": "delete",
       "table": "simple",
       "where": [["i", "==", 0]]}]' \
    'reconnect']],
  [[000: empty
000: event:create, row={}, uuid=<0>, updates=None
000: event:create, row={}, uuid=<1>, updates=None
001: {"error":null,"result":[{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
002: event:create, row={i=0 r=0 b=false s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[]}, uuid=<3>, updates=None
002: event:create, row={i=1 r=2 b=true s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>]}, uuid=<2>, updates=None
002: table simple: i=0 r=0 b=false s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
002: table simple: i=1 r=2 b=true s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
003: {"error":null,"result":[{"count":2}]}
004: event:update, row={i=1 r=2 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>]}, uuid=<2>, updates={b=true}
004: table simple: i=0 r=0 b=false s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
004: table simple: i=1 r=2 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
005: {"error":null,"result":[{"count":2}]}
006: event:update, row={i=0 r=123.5 b=false s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[]}, uuid=<3>, updates={r=0}
006: event:update, row={i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>]}, uuid=<2>, updates={r=2}
006: table simple: i=0 r=123.5 b=false s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
006: table simple: i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
007: {"error":null,"result":[{"uuid":["uuid","<8>"]}]}
008: event:create, row={i=-1 r=125 b=false s= u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[]}, uuid=<8>, updates=None
008: table simple: i=-1 r=125 b=false s= u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<8>
008: table simple: i=0 r=123.5 b=false s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
008: table simple: i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
009: {"error":null,"result":[{"count":2}]}
010: event:update, row={i=-1 r=125 b=false s=newstring u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[]}, uuid=<8>, updates={s=}
010: event:update, row={i=0 r=123.5 b=false s=newstring u=<4> ia=[] ra=[] ba=[] sa=[] ua=[]}, uuid=<3>, updates={s=}
010: table simple: i=-1 r=125 b=false s=newstring u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<8>
010: table simple: i=0 r=123.5 b=false s=newstring u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<3>
010: table simple: i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
011: {"error":null,"result":[{"count":1}]}
012: event:delete, row={i=0 r=123.5 b=false s=newstring u=<4> ia=[] ra=[] ba=[] sa=[] ua=[]}, uuid=<3>, updates=None
012: table simple: i=-1 r=125 b=false s=newstring u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<8>
012: table simple: i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
013: reconnect
014: event:create, row={i=-1 r=125 b=false s=newstring u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[]}, uuid=<8>, updates=None
014: event:create, row={i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>]}, uuid=<2>, updates=None
014: event:create, row={}, uuid=<0>, updates=None
014: event:create, row={}, uuid=<1>, updates=None
014: table simple: i=-1 r=125 b=false s=newstring u=<4> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<8>
014: table simple: i=1 r=123.5 b=false s=mystring u=<5> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<6> <7>] uuid=<2>
015: done
]])

# Tests to verify the functionality of the one column compound index.
# It tests index for one column string and integer indexes.
# The run of test-ovsdb generates the output of the display of data using the different indexes defined in
# the program.
# Then, some at_checks are used to verify the correctness of the corresponding index as well as the existence
# of all the rows involved in the test.
m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl compound_index_single_column compound_index positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
# Generate the data to be tested.
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index unix:socket $3],
            [0], [stdout], [ignore])
# Filter the rows of data that corresponds to the string index eliminating the extra columns of data.
# This is done to verifiy that the output data is in the correct and expected order.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sed -e 's/ i=.*//g']],
            [0], [$4])
# Here, the data is filtered and sorted in order to have all the rows in the index and be
# able to determined that all the involved rows are present.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
            [0], [$5])
# Filter the rows of data that corresponds to the integer index eliminating the extra columns of data.
# This is done to verifiy that the output data is in the correct and expected order.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sed -e 's/ s=.*//g']],
            [0], [$6])
# Here again, the data is filtered and sorted in order to have all the rows in the index and be
# able to determined that all the involved rows are present.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
            [0], [$7])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C([Compound_index, single column test ],
    [['["idltest",
      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 1, "b":true, "r":101.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 2, "b":false, "r":102.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 10, "b":true, "r":110.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 1, "b":false, "r":110.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":120.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":122.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 4, "b":true, "r":130.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List005", "i": 5, "b":true, "r":130.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 20, "b":true, "r":220.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 19, "b":true, "r":219.0}}
      ]']],
    [idl_compound_index_single_column],
    [001: s=List000
001: s=List000
001: s=List000
001: s=List001
001: s=List001
001: s=List001
001: s=List001
001: s=List005
001: s=List020
001: s=List020
003: s=List001
003: s=List001
003: s=List001
003: s=List001
],
[001: s=List000 i=1 b=True r=101.000000
001: s=List000 i=10 b=True r=110.000000
001: s=List000 i=2 b=False r=102.000000
001: s=List001 i=1 b=False r=110.000000
001: s=List001 i=2 b=True r=120.000000
001: s=List001 i=2 b=True r=122.000000
001: s=List001 i=4 b=True r=130.000000
001: s=List005 i=5 b=True r=130.000000
001: s=List020 i=19 b=True r=219.000000
001: s=List020 i=20 b=True r=220.000000
003: s=List001 i=1 b=False r=110.000000
003: s=List001 i=2 b=True r=120.000000
003: s=List001 i=2 b=True r=122.000000
003: s=List001 i=4 b=True r=130.000000
],
[002: i=1
002: i=1
002: i=2
002: i=2
002: i=2
002: i=4
002: i=5
002: i=10
002: i=19
002: i=20
004: i=5
005: i=4
005: i=5
006: i=5
006: i=10
006: i=19
006: i=20
006: i=54
007: i=5
007: i=19
007: i=20
007: i=30
007: i=54
008: i=1
008: i=1
008: i=2
008: i=2
008: i=2
008: i=5
008: i=19
008: i=20
008: i=30
008: i=54
],
[002: i=1 s=List000 b=True r=101.000000
002: i=1 s=List001 b=False r=110.000000
002: i=10 s=List000 b=True r=110.000000
002: i=19 s=List020 b=True r=219.000000
002: i=2 s=List000 b=False r=102.000000
002: i=2 s=List001 b=True r=120.000000
002: i=2 s=List001 b=True r=122.000000
002: i=20 s=List020 b=True r=220.000000
002: i=4 s=List001 b=True r=130.000000
002: i=5 s=List005 b=True r=130.000000
004: i=5 s=List005 b=True r=130.000000
005: i=4 s=List001 b=True r=130.000000
005: i=5 s=List005 b=True r=130.000000
006: i=10 s=List000 b=True r=110.000000
006: i=19 s=List020 b=True r=219.000000
006: i=20 s=List020 b=True r=220.000000
006: i=5 s=List005 b=True r=130.000000
006: i=54 s=Lista054 b=False r=0.000000
007: i=19 s=List020 b=True r=219.000000
007: i=20 s=List020 b=True r=220.000000
007: i=30 s=List000 b=True r=110.000000
007: i=5 s=List005 b=True r=130.000000
007: i=54 s=Lista054 b=False r=0.000000
008: i=1 s=List000 b=True r=101.000000
008: i=1 s=List001 b=False r=110.000000
008: i=19 s=List020 b=True r=219.000000
008: i=2 s=List000 b=False r=102.000000
008: i=2 s=List001 b=True r=120.000000
008: i=2 s=List001 b=True r=122.000000
008: i=20 s=List020 b=True r=220.000000
008: i=30 s=List000 b=True r=110.000000
008: i=5 s=List005 b=True r=130.000000
008: i=54 s=Lista054 b=False r=0.000000
])

# Tests to verify the functionality of two column compound index.
# It tests index for two columns using string and integer fields.
# The run of test-ovsdb generates the output of the display of data using the different indexes defined in
# the program.
# Then, some at_checks are used to verify the correctness of the corresponding index as well as the existence
# of all the rows involved in the test.
m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl compound_index_double_column compound_index positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
# Generate the data to be tested.
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index unix:socket $3],
            [0], [stdout], [ignore])
# Filter the rows of data that corresponds to the string-integer index eliminating the extra columns of data.
# This is done to verifiy that the output data is in the correct and expected order.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sed -e 's/ b=.*//g']],
            [0], [$4])
# Here, the data is filtered and sorted in order to have all the rows in the index and be
# able to determined that all the involved rows are present.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
            [0], [$5])
# Filter the rows of data that corresponds to the integer index eliminating the extra columns of data.
# This is done to verifiy that the output data is in the correct and expected order.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sed -e 's/ b=.*//g']],
            [0], [$6])
# Here again, the data is filtered and sorted in order to have all the rows in the index and be
# able to determined that all the involved rows are present.
   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
            [0], [$7])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C([Compound_index, double column test ],
    [['["idltest",
      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 1, "b":true, "r":101.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 2, "b":false, "r":102.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 10, "b":true, "r":110.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 1, "b":false, "r":110.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":120.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":122.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 4, "b":true, "r":130.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List005", "i": 5, "b":true, "r":130.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 20, "b":true, "r":220.0}},
      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 19, "b":true, "r":219.0}}
      ]']],
    [idl_compound_index_double_column],
    [001: s=List000 i=1
001: s=List000 i=2
001: s=List000 i=10
001: s=List001 i=1
001: s=List001 i=2
001: s=List001 i=2
001: s=List001 i=4
001: s=List005 i=5
001: s=List020 i=19
001: s=List020 i=20
002: s=List000 i=10
002: s=List000 i=2
002: s=List000 i=1
002: s=List001 i=4
002: s=List001 i=2
002: s=List001 i=2
002: s=List001 i=1
002: s=List005 i=5
002: s=List020 i=20
002: s=List020 i=19
003: s=List000 i=10
004: s=List001 i=1
004: s=List001 i=2
004: s=List001 i=2
004: s=List001 i=4
004: s=List005 i=5
],
    [001: s=List000 i=1 b=True r=101.000000
001: s=List000 i=10 b=True r=110.000000
001: s=List000 i=2 b=False r=102.000000
001: s=List001 i=1 b=False r=110.000000
001: s=List001 i=2 b=True r=120.000000
001: s=List001 i=2 b=True r=122.000000
001: s=List001 i=4 b=True r=130.000000
001: s=List005 i=5 b=True r=130.000000
001: s=List020 i=19 b=True r=219.000000
001: s=List020 i=20 b=True r=220.000000
002: s=List000 i=1 b=True r=101.000000
002: s=List000 i=10 b=True r=110.000000
002: s=List000 i=2 b=False r=102.000000
002: s=List001 i=1 b=False r=110.000000
002: s=List001 i=2 b=True r=120.000000
002: s=List001 i=2 b=True r=122.000000
002: s=List001 i=4 b=True r=130.000000
002: s=List005 i=5 b=True r=130.000000
002: s=List020 i=19 b=True r=219.000000
002: s=List020 i=20 b=True r=220.000000
003: s=List000 i=10 b=True r=110.000000
004: s=List001 i=1 b=False r=110.000000
004: s=List001 i=2 b=True r=120.000000
004: s=List001 i=2 b=True r=122.000000
004: s=List001 i=4 b=True r=130.000000
004: s=List005 i=5 b=True r=130.000000
],
    [005: i=1 s=List000
005: i=1 s=List001
005: i=2 s=List000
005: i=2 s=List001
005: i=2 s=List001
005: i=4 s=List001
005: i=5 s=List005
005: i=10 s=List000
005: i=19 s=List020
005: i=20 s=List020
006: i=20 s=List020
006: i=19 s=List020
006: i=10 s=List000
006: i=5 s=List005
006: i=4 s=List001
006: i=2 s=List000
006: i=2 s=List001
006: i=2 s=List001
006: i=1 s=List000
006: i=1 s=List001
],
    [005: i=1 s=List000 b=True r=101.000000
005: i=1 s=List001 b=False r=110.000000
005: i=10 s=List000 b=True r=110.000000
005: i=19 s=List020 b=True r=219.000000
005: i=2 s=List000 b=False r=102.000000
005: i=2 s=List001 b=True r=120.000000
005: i=2 s=List001 b=True r=122.000000
005: i=20 s=List020 b=True r=220.000000
005: i=4 s=List001 b=True r=130.000000
005: i=5 s=List005 b=True r=130.000000
006: i=1 s=List000 b=True r=101.000000
006: i=1 s=List001 b=False r=110.000000
006: i=10 s=List000 b=True r=110.000000
006: i=19 s=List020 b=True r=219.000000
006: i=2 s=List000 b=False r=102.000000
006: i=2 s=List001 b=True r=120.000000
006: i=2 s=List001 b=True r=122.000000
006: i=20 s=List020 b=True r=220.000000
006: i=4 s=List001 b=True r=130.000000
006: i=5 s=List005 b=True r=130.000000
])

m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_WITH_REF],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([ovsdb server idl compound_index compound_index_with_ref positive $5])
   OVSDB_START_IDLTEST
   m4_if([$2], [], [],
     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index-with-ref unix:socket $3],
            [0], [stdout], [ignore])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
            [0], [$4])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

OVSDB_CHECK_IDL_COMPOUND_INDEX_WITH_REF([set, simple3 idl-compound-index-with-ref, initially populated],
[],
[],
[[000: After add to other table + set of strong ref
001: table simple3: name= uset=[] uref=[<0>] uuid=<1>
002: check simple4: not empty
003: Query using index with reference
004: table simple3: name= uset=[] uref=[<0>] uuid=<1>
005: After delete
007: check simple4: empty
008: End test
]])

m4_define([CHECK_STREAM_OPEN_BLOCK],
  [AT_SETUP([Check stream open block - $1 - $3])
   AT_SKIP_IF([test "$3" = "tcp6" && test "$IS_WIN32" = "yes"])
   AT_SKIP_IF([test "$3" = "tcp6" && test "$HAVE_IPV6" = "no"])
   AT_SKIP_IF([test "$3" = "ssl6" && test "$IS_WIN32" = "yes"])
   AT_SKIP_IF([test "$3" = "ssl6" && test "$HAVE_IPV6" = "no"])
   AT_SKIP_IF([test "$3" = "ssl" && test "$HAVE_OPENSSL" = "no"])
   $PYTHON3 -c "import ssl"
   SSL_PRESENT=$?
   AT_SKIP_IF([test "$3" = "ssl" && test $SSL_PRESENT != 0])
   AT_SKIP_IF([test "$3" = "ssl6" && test "$HAVE_OPENSSL" = "no"])
   AT_SKIP_IF([test "$3" = "ssl6" && test $SSL_PRESENT != 0])
   AT_KEYWORDS([ovsdb server stream open_block $3])
   PKIDIR=$abs_top_builddir/tests
   m4_define([PROTOCOL], [m4_substr([$3], [0], [3])])
   OVSDB_START_IDLTEST([m4_join([], [p], PROTOCOL, [:0:], $4)])
   PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
   WRONG_PORT=$(($TCP_PORT + 101))
   SSL_KEY_ARGS="$PKIDIR/testpki-privkey.pem $PKIDIR/testpki-cert.pem $PKIDIR/testpki-cacert.pem"
   AT_CHECK([$2 PROTOCOL:$4:$TCP_PORT $SSL_KEY_ARGS], [0], [ignore])
   AT_CHECK([$2 PROTOCOL:$4:$WRONG_PORT $SSL_KEY_ARGS], [1], [ignore],
            [ignore])
   OVSDB_SERVER_SHUTDOWN(["
     /unexpected SSL connection close/d
     /Protocol error/d
   "])
   AT_CHECK([$2 PROTOCOL:$4:$TCP_PORT $SSL_KEY_ARGS], [1], [ignore], [ignore])
   AT_CLEANUP])

CHECK_STREAM_OPEN_BLOCK([C], [test-stream], [tcp], [127.0.0.1])
CHECK_STREAM_OPEN_BLOCK([C], [test-stream], [tcp6], [[[::1]]])
CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
                        [tcp], [127.0.0.1])
CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
                        [tcp6], [[[::1]]])
CHECK_STREAM_OPEN_BLOCK([C], [test-stream], [ssl], [127.0.0.1])
CHECK_STREAM_OPEN_BLOCK([C], [test-stream], [ssl6], [[[::1]]])
CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
                        [ssl], [127.0.0.1])
CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
                        [ssl6], [[[::1]]])

dnl OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS(LOG)
dnl
dnl Looks up transaction IDs in the log of OVSDB client application.
dnl All-zero UUID should not be sent within a monitor request more than once,
dnl unless some database requests were lost (not replied).
m4_define([OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS],
[
   requests=$(grep -c 'send request' $1)
   replies=$(grep -c 'received reply' $1)

   if test "$requests" -eq "$replies"; then
     AT_CHECK([grep 'monitor_cond_since' $1 \
                | grep -c "00000000-0000-0000-0000-000000000000" | tr -d '\n'],
              [0], [1])
   fi
])

# same as OVSDB_CHECK_IDL but uses Python IDL implementation with tcp
# with multiple remotes to assert the idl connects to the leader of the Raft cluster
m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY],
  [AT_SETUP([$1 - Python3 (leader only)])
   AT_SKIP_IF([test "$IS_ARM64" = "yes"])
   AT_KEYWORDS([ovsdb server idl Python leader_only with tcp socket])
   m4_define([LPBK],[127.0.0.1])
   OVSDB_CLUSTER_START_IDLTEST([$2], ["ptcp:0:"LPBK])
   PARSE_LISTENING_PORT([s2.log], [TCP_PORT_1])
   PARSE_LISTENING_PORT([s3.log], [TCP_PORT_2])
   PARSE_LISTENING_PORT([s1.log], [TCP_PORT_3])
   remotes=tcp:LPBK:$TCP_PORT_1,tcp:LPBK:$TCP_PORT_2,tcp:LPBK:$TCP_PORT_3
   pids=$(cat s2.pid s3.pid s1.pid | tr '\n' ',')
   echo $pids
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t30 idl-cluster $srcdir/idltest.ovsschema $remotes $pids $3],
        [0], [stdout], [stderr])
   remote=$(ovsdb_cluster_leader $remotes "idltest")
   leader=$(echo $remote | cut -d'|' -f 1)
   AT_CHECK([grep -F -- "${leader}" stdout], [0], [ignore])
   OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS([stderr])
   AT_CLEANUP])

OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote'])
OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL reconnects to leader], 3, ['remote' '+remotestop' 'remote'])

# OVSDB_CHECK_CLUSTER_IDL_C(TITLE, N_SERVERS, [PRE-IDL-TXN], TRANSACTIONS,
#                           OUTPUT, [KEYWORDS], [FILTER], [LOG_FILTER])
#
# Creates a clustered database with a schema derived from idltest.ovsidl, runs
# each PRE-IDL-TXN (if any), starts N_SERVERS ovsdb-server instances in RAFT,
# on that database, and runs "test-ovsdb idl" passing each of the TRANSACTIONS
# along.
#
# Checks that the overall output is OUTPUT.  Before comparison, the
# output is sorted (using "sort") and 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.  If FILTER is supplied then the output is also filtered
# through the specified program.
#
# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
#
# If LOG_FILTER is provided, checks that the contents of LOG_FILTER
# are not matched by grep in the test-ovsdb logs.
m4_define([OVSDB_CHECK_CLUSTER_IDL_C],
  [AT_SETUP([$1 - C - tcp])
   AT_KEYWORDS([ovsdb server idl tcp $6])
   m4_define([LPBK],[127.0.0.1])
   OVSDB_CLUSTER_START_IDLTEST([$2], ["ptcp:0:"LPBK])
   PARSE_LISTENING_PORT([s1.log], [TCP_PORT_1])
   PARSE_LISTENING_PORT([s2.log], [TCP_PORT_2])
   PARSE_LISTENING_PORT([s3.log], [TCP_PORT_3])
   remotes=tcp:LPBK:$TCP_PORT_1,tcp:LPBK:$TCP_PORT_2,tcp:LPBK:$TCP_PORT_3

   m4_if([$3], [], [],
     [AT_CHECK([ovsdb-client transact $remotes $3], [0], [ignore], [ignore])])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl tcp:LPBK:$TCP_PORT_1 $4],
            [0], [stdout], [stderr])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]),
            [0], [$5])
   m4_ifval([$8], [AT_CHECK([grep '$8' stderr], [1])], [], [])
   OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS([stderr])
   AT_CLEANUP])

# Same as OVSDB_CHECK_CLUSTER_IDL_C but uses the Python IDL implementation.
m4_define([OVSDB_CHECK_CLUSTER_IDL_PY],
  [AT_SETUP([$1 - Python3 - tcp])
   AT_KEYWORDS([ovsdb server idl tcp $6])
   m4_define([LPBK],[127.0.0.1])
   OVSDB_CLUSTER_START_IDLTEST([$2], ["ptcp:0:"LPBK])
   PARSE_LISTENING_PORT([s1.log], [TCP_PORT_1])
   PARSE_LISTENING_PORT([s2.log], [TCP_PORT_2])
   PARSE_LISTENING_PORT([s3.log], [TCP_PORT_3])
   remotes=tcp:LPBK:$TCP_PORT_1,tcp:LPBK:$TCP_PORT_2,tcp:LPBK:$TCP_PORT_3

   m4_if([$3], [], [],
     [AT_CHECK([ovsdb-client transact $remotes $3], [0], [ignore], [ignore])])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py -t10 idl $srcdir/idltest.ovsschema tcp:LPBK:$TCP_PORT_1 $4],
            [0], [stdout], [stderr])
   AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]),
            [0], [$5])
   m4_if([$8], [AT_CHECK([grep '$8' stderr], [1])], [], [])
   OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS([stderr])
   AT_CLEANUP])

m4_define([OVSDB_CHECK_CLUSTER_IDL],
  [OVSDB_CHECK_CLUSTER_IDL_C($@)
   OVSDB_CHECK_CLUSTER_IDL_PY($@)])

# Checks that monitor_cond_since works fine when disconnects happen
# with cond_change requests in flight (i.e., IDL is properly updated).
OVSDB_CHECK_CLUSTER_IDL([simple idl, monitor_cond_since, cluster disconnect],
  3,
  [['["idltest",
       {"op": "insert",
       "table": "simple",
       "row": {"i": 1,
               "r": 1.0,
               "b": true}},
       {"op": "insert",
       "table": "simple",
       "row": {"i": 2,
               "r": 1.0,
               "b": true}}]']],
  [['condition simple []' \
    'condition simple [["i","==",2]]' \
    'condition simple [["i","==",1]]' \
    '+reconnect' \
    '?["idltest",
      {"op": "update",
       "table": "simple",
       "where": [["i", "==", 1]],
       "row": {"r": 2.0 }}]']],
  [[000: simple: change conditions
001: empty
002: simple: change conditions
003: table simple: i=2 r=1 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
004: simple: change conditions
005: reconnect
006: table simple
007: {"error":null,"result":[{"count":1}]}
008: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
009: done
]])

dnl This test checks that IDL keeps the existing connection to the server if
dnl it's still on a list of remotes after update.
OVSDB_CHECK_IDL_C([simple idl, initially empty, set remotes],
  [],
  [['set-remote unix:socket' \
    '+set-remote unix:bad_socket,unix:socket' \
    '+set-remote unix:bad_socket' \
    '+set-remote unix:socket' \
    'set-remote unix:bad_socket,unix:socket' \
    '+set-remote unix:socket' \
    '+reconnect']],
  [[000: empty
001: new remotes: unix:socket, is connected: true
002: new remotes: unix:bad_socket,unix:socket, is connected: true
003: new remotes: unix:bad_socket, is connected: false
004: new remotes: unix:socket, is connected: false
005: empty
006: new remotes: unix:bad_socket,unix:socket, is connected: true
007: new remotes: unix:socket, is connected: true
008: reconnect
009: empty
010: done
]])

dnl This test checks that forceful reconnects triggered by the IDL
dnl happen immediately (they should not use backoff).
OVSDB_CHECK_CLUSTER_IDL([simple idl, initially empty, force reconnect],
  3,
  [],
  [['+reconnect' \
    'reconnect' \
    'reconnect' \
    'reconnect']],
  [[000: reconnect
001: empty
002: reconnect
003: empty
004: reconnect
005: empty
006: reconnect
007: empty
008: done
]],
[],
[],
reconnect.*waiting .* seconds before reconnect)

AT_SETUP([idl table and column presence check])
AT_KEYWORDS([ovsdb server idl table column check])
OVSDB_START_IDLTEST([], ["$abs_srcdir/idltest2.ovsschema"])

AT_CHECK(ovsdb-tool create db2 $abs_srcdir/idltest.ovsschema)
AT_CHECK(ovsdb-server -vconsole:warn --log-file=ovsdb-server2.log --detach dnl
           --no-chdir --pidfile=ovsdb-server2.pid --remote=punix:socket2 db2)
on_exit 'kill `cat ovsdb-server2.pid`'

dnl In this test, test-ovsdb first connects to the server with schema
dnl idltest2.ovsschema and outputs the presence of tables and columns.
dnl And then it connectes to the server with the schema idltest.ovsschema
dnl and does the same.
AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 dnl
                 idl-table-column-check unix:socket unix:socket2], [0], [dnl
unix:socket remote has table simple
unix:socket remote has table link1
unix:socket remote doesn't have table link2
unix:socket remote doesn't have table simple5
unix:socket remote doesn't have col irefmap in table simple5
unix:socket remote doesn't have col l2 in table link1
unix:socket remote has col i in table link1
unix:socket remote doesn't have col id in table simple7
--- remote unix:socket done ---
unix:socket2 remote has table simple
unix:socket2 remote has table link1
unix:socket2 remote has table link2
unix:socket2 remote has table simple5
unix:socket2 remote has col irefmap in table simple5
unix:socket2 remote has col l2 in table link1
unix:socket2 remote has col i in table link1
unix:socket2 remote has col id in table simple7
--- remote unix:socket2 done ---
], [stderr])

OVSDB_SERVER_SHUTDOWN
AT_CLEANUP

dnl This test checks that inserting and deleting the source of a reference
dnl doesn't remove the reference in the (deleted) source tracked record.
OVSDB_CHECK_IDL_TRACK([track, insert and delete, refs to link1],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link2",
       "uuid-name": "l2row0",
       "row": {"i": 1, "l1": ["set", [["named-uuid", "l1row0"]]]}
      },
      {"op": "insert",
       "table": "link1",
       "uuid-name": "l1row0",
       "row": {"i": 1, "k": ["named-uuid", "l1row0"]}
      },
      {"op": "insert",
       "table": "link2",
       "uuid-name": "l2row1",
       "row": {"i": 2, "l1": ["set", [["named-uuid", "l1row0"]]]}
      }
    ]' \
    '+["idltest",
      {"op": "delete",
       "table": "link2",
       "where": [["i", "==", 2]]}
       ]' \
    '["idltest",
      {"op": "delete",
       "table": "link2",
       "where": [["i", "==", 1]]}
       ]'
  ]],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
002: {"error":null,"result":[{"count":1}]}
003: table link1: inserted row: i=1 k=1 ka=[] l2= uuid=<1>
003: table link1: updated columns: i k
003: table link2: inserted row: i=1 l1=1 uuid=<0>
003: table link2: inserted/deleted row: i=2 l1=1 uuid=<2>
003: table link2: updated columns: i l1
003: table link2: updated columns: i l1
004: {"error":null,"result":[{"count":1}]}
005: table link1: i=1 k=1 ka=[] l2= uuid=<1>
006: done
]])
OVSDB_CHECK_IDL_TRACK([track, insert and delete, refs to link2],
  [],
  [['["idltest",
      {"op": "insert",
       "table": "link1",
       "uuid-name": "l1row0",
       "row": {"i": 1, "k": ["named-uuid", "l1row0"], "l2": ["set", [["named-uuid", "l2row0"]]]}
      },
      {"op": "insert",
       "table": "link2",
       "uuid-name": "l2row0",
       "row": {"i": 1}
      },
      {"op": "insert",
       "table": "link1",
       "uuid-name": "l1row1",
       "row": {"i": 2, "k": ["named-uuid", "l1row0"], "l2": ["set", [["named-uuid", "l2row0"]]]}
      }
    ]' \
    '+["idltest",
      {"op": "delete",
       "table": "link1",
       "where": [["i", "==", 2]]}
       ]' \
    '["idltest",
      {"op": "delete",
       "table": "link1",
       "where": [["i", "==", 1]]}
       ]'
  ]],
  [[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
002: {"error":null,"result":[{"count":1}]}
003: table link1: inserted row: i=1 k=1 ka=[] l2=1 uuid=<0>
003: table link1: inserted/deleted row: i=2 k=1 ka=[] l2=1 uuid=<2>
003: table link1: updated columns: i k l2
003: table link1: updated columns: i k l2
003: table link2: inserted row: i=1 l1= uuid=<1>
003: table link2: updated columns: i
004: {"error":null,"result":[{"count":1}]}
005: table link2: i=1 l1= uuid=<1>
006: done
]])

m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT_C],
  [AT_SETUP([$1 - C])
   AT_KEYWORDS([idl persistent uuid insert])
   OVSDB_START_IDLTEST([], ["$abs_srcdir/idltest.ovsschema"])
   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket $2],
            [0], [stdout], [stderr])
   AT_CHECK([sort stdout],
            [0], [$3])
   AT_CHECK([grep $4 stderr], [0], [ignore])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])

m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT_PY],
  [AT_SETUP([$1 - Python3])
   AT_KEYWORDS([idl persistent uuid insert])
   OVSDB_START_IDLTEST([], ["$abs_srcdir/idltest.ovsschema"])
   AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket $2],
            [0], [stdout], [stderr])
   AT_CHECK([sort stdout],
            [0], [$3])
   AT_CHECK([grep $4 stderr], [0], [ignore])
   OVSDB_SERVER_SHUTDOWN
   AT_CLEANUP])


m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT],
  [OVSDB_CHECK_IDL_PERS_UUID_INSERT_C($@)
   OVSDB_CHECK_IDL_PERS_UUID_INSERT_PY($@)])

OVSDB_CHECK_IDL_PERS_UUID_INSERT([simple idl, persistent uuid insert],
  [['insert_uuid c5cc12f8-eaa1-43a7-8a73-bccd18df2222 2, insert_uuid c5cc12f8-eaa1-43a7-8a73-bccd18df3333 3' \
    'insert_uuid c5cc12f8-eaa1-43a7-8a73-bccd18df4444 4, insert_uuid c5cc12f8-eaa1-43a7-8a73-bccd18df2222 5' \
    'insert_uuid c5cc12f8-eaa1-43a7-8a73-bccd18df4444 4' \
    'delete 2' \
    'insert_uuid c5cc12f8-eaa1-43a7-8a73-bccd18df2222 5'
    ]],
  [[000: empty
001: commit, status=success
002: table simple: i=2 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df2222
002: table simple: i=3 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df3333
003: commit, status=error
004: table simple: i=2 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df2222
004: table simple: i=3 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df3333
005: commit, status=success
006: table simple: i=2 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df2222
006: table simple: i=3 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df3333
006: table simple: i=4 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df4444
007: commit, status=success
008: table simple: i=3 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df3333
008: table simple: i=4 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df4444
009: commit, status=success
010: table simple: i=3 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df3333
010: table simple: i=4 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df4444
010: table simple: i=5 r=0 b=false s= u=00000000-0000-0000-0000-000000000000 ia=[] ra=[] ba=[] sa=[] ua=[] uuid=c5cc12f8-eaa1-43a7-8a73-bccd18df2222
011: done
]],
  [['This UUID would duplicate a UUID already present within the table or deleted within the same transaction']])
