mirror of https://github.com/postgres/postgres
We had no actual end-to-end test of NOTIFY message delivery. In the core async.sql regression test, testing this is problematic because psql traditionally prints the PID of the sending backend, making the output unstable. We also have an isolation test script, but it likewise failed to prove that delivery worked, because isolationtester.c had no provisions for detecting/reporting NOTIFY messages. Hence, add such provisions to isolationtester.c, and extend async-notify.spec to include direct tests of basic NOTIFY functionality. I also added tests showing that NOTIFY de-duplicates messages normally, but not across subtransaction boundaries. (That's the historical behavior since we introduced subtransactions, though perhaps we ought to change it.) Patch by me, with suggestions/review by Andres Freund. Discussion: https://postgr.es/m/31304.1564246011@sss.pgh.pa.uspull/47/head
parent
44460d7017
commit
b10f40bf0e
@ -1,17 +1,102 @@ |
||||
Parsed test spec with 2 sessions |
||||
|
||||
starting permutation: listen begin check notify check |
||||
step listen: LISTEN a; |
||||
step begin: BEGIN; |
||||
step check: SELECT pg_notification_queue_usage() > 0 AS nonzero; |
||||
starting permutation: listenc notify1 notify2 notify3 notifyf |
||||
step listenc: LISTEN c1; LISTEN c2; |
||||
step notify1: NOTIFY c1; |
||||
notifier: NOTIFY "c1" with payload "" from notifier |
||||
step notify2: NOTIFY c2, 'payload'; |
||||
notifier: NOTIFY "c2" with payload "payload" from notifier |
||||
step notify3: NOTIFY c3, 'payload3'; |
||||
step notifyf: SELECT pg_notify('c2', NULL); |
||||
pg_notify |
||||
|
||||
|
||||
notifier: NOTIFY "c2" with payload "" from notifier |
||||
|
||||
starting permutation: listenc notifyd1 notifyd2 notifys1 |
||||
step listenc: LISTEN c1; LISTEN c2; |
||||
step notifyd1: NOTIFY c2, 'payload'; NOTIFY c1; NOTIFY "c2", 'payload'; |
||||
notifier: NOTIFY "c2" with payload "payload" from notifier |
||||
notifier: NOTIFY "c1" with payload "" from notifier |
||||
step notifyd2: NOTIFY c1; NOTIFY c1; NOTIFY c1, 'p1'; NOTIFY c1, 'p2'; |
||||
notifier: NOTIFY "c1" with payload "" from notifier |
||||
notifier: NOTIFY "c1" with payload "p1" from notifier |
||||
notifier: NOTIFY "c1" with payload "p2" from notifier |
||||
step notifys1: |
||||
BEGIN; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
SAVEPOINT s1; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
NOTIFY c1, 'payloads'; NOTIFY "c2", 'payloads'; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
NOTIFY c1, 'payloads'; NOTIFY "c2", 'payloads'; |
||||
RELEASE SAVEPOINT s1; |
||||
SAVEPOINT s2; |
||||
NOTIFY c1, 'rpayload'; NOTIFY "c2", 'rpayload'; |
||||
NOTIFY c1, 'rpayloads'; NOTIFY "c2", 'rpayloads'; |
||||
NOTIFY c1, 'rpayload'; NOTIFY "c2", 'rpayload'; |
||||
NOTIFY c1, 'rpayloads'; NOTIFY "c2", 'rpayloads'; |
||||
ROLLBACK TO SAVEPOINT s2; |
||||
COMMIT; |
||||
|
||||
notifier: NOTIFY "c1" with payload "payload" from notifier |
||||
notifier: NOTIFY "c2" with payload "payload" from notifier |
||||
notifier: NOTIFY "c1" with payload "payload" from notifier |
||||
notifier: NOTIFY "c2" with payload "payload" from notifier |
||||
notifier: NOTIFY "c1" with payload "payloads" from notifier |
||||
notifier: NOTIFY "c2" with payload "payloads" from notifier |
||||
|
||||
starting permutation: llisten notify1 notify2 notify3 notifyf lcheck |
||||
step llisten: LISTEN c1; LISTEN c2; |
||||
step notify1: NOTIFY c1; |
||||
step notify2: NOTIFY c2, 'payload'; |
||||
step notify3: NOTIFY c3, 'payload3'; |
||||
step notifyf: SELECT pg_notify('c2', NULL); |
||||
pg_notify |
||||
|
||||
|
||||
step lcheck: SELECT 1 AS x; |
||||
x |
||||
|
||||
1 |
||||
listener: NOTIFY "c1" with payload "" from notifier |
||||
listener: NOTIFY "c2" with payload "payload" from notifier |
||||
listener: NOTIFY "c2" with payload "" from notifier |
||||
|
||||
starting permutation: listenc llisten notify1 notify2 notify3 notifyf lcheck |
||||
step listenc: LISTEN c1; LISTEN c2; |
||||
step llisten: LISTEN c1; LISTEN c2; |
||||
step notify1: NOTIFY c1; |
||||
notifier: NOTIFY "c1" with payload "" from notifier |
||||
step notify2: NOTIFY c2, 'payload'; |
||||
notifier: NOTIFY "c2" with payload "payload" from notifier |
||||
step notify3: NOTIFY c3, 'payload3'; |
||||
step notifyf: SELECT pg_notify('c2', NULL); |
||||
pg_notify |
||||
|
||||
|
||||
notifier: NOTIFY "c2" with payload "" from notifier |
||||
step lcheck: SELECT 1 AS x; |
||||
x |
||||
|
||||
1 |
||||
listener: NOTIFY "c1" with payload "" from notifier |
||||
listener: NOTIFY "c2" with payload "payload" from notifier |
||||
listener: NOTIFY "c2" with payload "" from notifier |
||||
|
||||
starting permutation: llisten lbegin usage bignotify usage |
||||
step llisten: LISTEN c1; LISTEN c2; |
||||
step lbegin: BEGIN; |
||||
step usage: SELECT pg_notification_queue_usage() > 0 AS nonzero; |
||||
nonzero |
||||
|
||||
f |
||||
step notify: SELECT count(pg_notify('a', s::text)) FROM generate_series(1, 1000) s; |
||||
step bignotify: SELECT count(pg_notify('c1', s::text)) FROM generate_series(1, 1000) s; |
||||
count |
||||
|
||||
1000 |
||||
step check: SELECT pg_notification_queue_usage() > 0 AS nonzero; |
||||
step usage: SELECT pg_notification_queue_usage() > 0 AS nonzero; |
||||
nonzero |
||||
|
||||
t |
||||
|
@ -1,14 +1,70 @@ |
||||
# Verify that pg_notification_queue_usage correctly reports a non-zero result, |
||||
# after submitting notifications while another connection is listening for |
||||
# those notifications and waiting inside an active transaction. |
||||
# Tests for LISTEN/NOTIFY |
||||
|
||||
session "listener" |
||||
step "listen" { LISTEN a; } |
||||
step "begin" { BEGIN; } |
||||
teardown { ROLLBACK; UNLISTEN *; } |
||||
# Most of these tests use only the "notifier" session and hence exercise only |
||||
# self-notifies, which are convenient because they minimize timing concerns. |
||||
# Note we assume that each step is delivered to the backend as a single Query |
||||
# message so it will run as one transaction. |
||||
|
||||
session "notifier" |
||||
step "check" { SELECT pg_notification_queue_usage() > 0 AS nonzero; } |
||||
step "notify" { SELECT count(pg_notify('a', s::text)) FROM generate_series(1, 1000) s; } |
||||
step "listenc" { LISTEN c1; LISTEN c2; } |
||||
step "notify1" { NOTIFY c1; } |
||||
step "notify2" { NOTIFY c2, 'payload'; } |
||||
step "notify3" { NOTIFY c3, 'payload3'; } # not listening to c3 |
||||
step "notifyf" { SELECT pg_notify('c2', NULL); } |
||||
step "notifyd1" { NOTIFY c2, 'payload'; NOTIFY c1; NOTIFY "c2", 'payload'; } |
||||
step "notifyd2" { NOTIFY c1; NOTIFY c1; NOTIFY c1, 'p1'; NOTIFY c1, 'p2'; } |
||||
step "notifys1" { |
||||
BEGIN; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
SAVEPOINT s1; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
NOTIFY c1, 'payloads'; NOTIFY "c2", 'payloads'; |
||||
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload'; |
||||
NOTIFY c1, 'payloads'; NOTIFY "c2", 'payloads'; |
||||
RELEASE SAVEPOINT s1; |
||||
SAVEPOINT s2; |
||||
NOTIFY c1, 'rpayload'; NOTIFY "c2", 'rpayload'; |
||||
NOTIFY c1, 'rpayloads'; NOTIFY "c2", 'rpayloads'; |
||||
NOTIFY c1, 'rpayload'; NOTIFY "c2", 'rpayload'; |
||||
NOTIFY c1, 'rpayloads'; NOTIFY "c2", 'rpayloads'; |
||||
ROLLBACK TO SAVEPOINT s2; |
||||
COMMIT; |
||||
} |
||||
step "usage" { SELECT pg_notification_queue_usage() > 0 AS nonzero; } |
||||
step "bignotify" { SELECT count(pg_notify('c1', s::text)) FROM generate_series(1, 1000) s; } |
||||
teardown { UNLISTEN *; } |
||||
|
||||
# The listener session is used for cross-backend notify checks. |
||||
|
||||
session "listener" |
||||
step "llisten" { LISTEN c1; LISTEN c2; } |
||||
step "lcheck" { SELECT 1 AS x; } |
||||
step "lbegin" { BEGIN; } |
||||
teardown { UNLISTEN *; } |
||||
|
||||
|
||||
# Trivial cases. |
||||
permutation "listenc" "notify1" "notify2" "notify3" "notifyf" |
||||
|
||||
# Check simple and less-simple deduplication. |
||||
permutation "listenc" "notifyd1" "notifyd2" "notifys1" |
||||
|
||||
# Cross-backend notification delivery. We use a "select 1" to force the |
||||
# listener session to check for notifies. In principle we could just wait |
||||
# for delivery, but that would require extra support in isolationtester |
||||
# and might have portability-of-timing issues. |
||||
permutation "llisten" "notify1" "notify2" "notify3" "notifyf" "lcheck" |
||||
|
||||
# Again, with local delivery too. |
||||
permutation "listenc" "llisten" "notify1" "notify2" "notify3" "notifyf" "lcheck" |
||||
|
||||
# Verify that pg_notification_queue_usage correctly reports a non-zero result, |
||||
# after submitting notifications while another connection is listening for |
||||
# those notifications and waiting inside an active transaction. We have to |
||||
# fill a page of the notify SLRU to make this happen, which is a good deal |
||||
# of traffic. To not bloat the expected output, we intentionally don't |
||||
# commit the listener's transaction, so that it never reports these events. |
||||
# Hence, this should be the last test in this script. |
||||
|
||||
permutation "listen" "begin" "check" "notify" "check" |
||||
permutation "llisten" "lbegin" "usage" "bignotify" "usage" |
||||
|
Loading…
Reference in new issue