From 600fef1d835a512a34cb8118e0681832cbae5120 Mon Sep 17 00:00:00 2001 From: Joel Jacobson Date: Wed, 8 Oct 2025 09:30:54 +0200 Subject: [PATCH 1/2] Improve LISTEN/NOTIFY test coverage This adds isolation tests to cover previously untested code paths: * Check simple NOTIFY reparenting when parent has no action * Check LISTEN reparenting in subtransaction * Check LISTEN merge path when both outer and inner transactions have actions * Check LISTEN abort path (ROLLBACK TO SAVEPOINT discards pending actions) * Check notification_match function (triggered by hash table duplicate detection) This also adds a test to prepare for the next patch: * Check ChannelHashAddListener array growth --- src/test/isolation/expected/async-notify.out | 103 ++++++++++++++++++- src/test/isolation/specs/async-notify.spec | 52 ++++++++++ 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/test/isolation/expected/async-notify.out b/src/test/isolation/expected/async-notify.out index 556e1805893..9c19843d2d7 100644 --- a/src/test/isolation/expected/async-notify.out +++ b/src/test/isolation/expected/async-notify.out @@ -1,4 +1,4 @@ -Parsed test spec with 3 sessions +Parsed test spec with 5 sessions starting permutation: listenc notify1 notify2 notify3 notifyf step listenc: LISTEN c1; LISTEN c2; @@ -47,6 +47,105 @@ 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: listenc notifys_simple +step listenc: LISTEN c1; LISTEN c2; +step notifys_simple: + BEGIN; + SAVEPOINT s1; + NOTIFY c1, 'simple1'; + NOTIFY c2, 'simple2'; + RELEASE SAVEPOINT s1; + COMMIT; + +notifier: NOTIFY "c1" with payload "simple1" from notifier +notifier: NOTIFY "c2" with payload "simple2" from notifier + +starting permutation: lsbegin lssavepoint lslisten lsrelease lscommit lsnotify +step lsbegin: BEGIN; +step lssavepoint: SAVEPOINT s1; +step lslisten: LISTEN c1; LISTEN c2; +step lsrelease: RELEASE SAVEPOINT s1; +step lscommit: COMMIT; +step lsnotify: NOTIFY c1, 'subxact_test'; +listen_subxact: NOTIFY "c1" with payload "subxact_test" from listen_subxact + +starting permutation: lsbegin lslisten_outer lssavepoint lslisten lsrelease lscommit lsnotify +step lsbegin: BEGIN; +step lslisten_outer: LISTEN c3; +step lssavepoint: SAVEPOINT s1; +step lslisten: LISTEN c1; LISTEN c2; +step lsrelease: RELEASE SAVEPOINT s1; +step lscommit: COMMIT; +step lsnotify: NOTIFY c1, 'subxact_test'; +listen_subxact: NOTIFY "c1" with payload "subxact_test" from listen_subxact + +starting permutation: lsbegin lssavepoint lslisten lsrollback lscommit lsnotify_check +step lsbegin: BEGIN; +step lssavepoint: SAVEPOINT s1; +step lslisten: LISTEN c1; LISTEN c2; +step lsrollback: ROLLBACK TO SAVEPOINT s1; +step lscommit: COMMIT; +step lsnotify_check: NOTIFY c1, 'should_not_receive'; + +starting permutation: listenc notify_many_with_dup +step listenc: LISTEN c1; LISTEN c2; +step notify_many_with_dup: + BEGIN; + SELECT pg_notify('c1', 'msg' || s::text) FROM generate_series(1, 17) s; + SELECT pg_notify('c1', 'msg1'); + COMMIT; + +pg_notify +--------- + + + + + + + + + + + + + + + + + +(17 rows) + +pg_notify +--------- + +(1 row) + +notifier: NOTIFY "c1" with payload "msg1" from notifier +notifier: NOTIFY "c1" with payload "msg2" from notifier +notifier: NOTIFY "c1" with payload "msg3" from notifier +notifier: NOTIFY "c1" with payload "msg4" from notifier +notifier: NOTIFY "c1" with payload "msg5" from notifier +notifier: NOTIFY "c1" with payload "msg6" from notifier +notifier: NOTIFY "c1" with payload "msg7" from notifier +notifier: NOTIFY "c1" with payload "msg8" from notifier +notifier: NOTIFY "c1" with payload "msg9" from notifier +notifier: NOTIFY "c1" with payload "msg10" from notifier +notifier: NOTIFY "c1" with payload "msg11" from notifier +notifier: NOTIFY "c1" with payload "msg12" from notifier +notifier: NOTIFY "c1" with payload "msg13" from notifier +notifier: NOTIFY "c1" with payload "msg14" from notifier +notifier: NOTIFY "c1" with payload "msg15" from notifier +notifier: NOTIFY "c1" with payload "msg16" from notifier +notifier: NOTIFY "c1" with payload "msg17" from notifier + +starting permutation: listenc llisten l2listen l3listen lslisten +step listenc: LISTEN c1; LISTEN c2; +step llisten: LISTEN c1; LISTEN c2; +step l2listen: LISTEN c1; +step l3listen: LISTEN c1; +step lslisten: LISTEN c1; LISTEN c2; + starting permutation: llisten notify1 notify2 notify3 notifyf lcheck step llisten: LISTEN c1; LISTEN c2; step notify1: NOTIFY c1; @@ -95,6 +194,8 @@ listener: NOTIFY "c2" with payload "" from notifier starting permutation: l2listen l2begin notify1 lbegins llisten lcommit l2commit l2stop step l2listen: LISTEN c1; +listener2: NOTIFY "c1" with payload "" from notifier +listener2: NOTIFY "c1" with payload "" from notifier step l2begin: BEGIN; step notify1: NOTIFY c1; step lbegins: BEGIN ISOLATION LEVEL SERIALIZABLE; diff --git a/src/test/isolation/specs/async-notify.spec b/src/test/isolation/specs/async-notify.spec index 0b8cfd91083..942b09d5735 100644 --- a/src/test/isolation/specs/async-notify.spec +++ b/src/test/isolation/specs/async-notify.spec @@ -31,6 +31,20 @@ step notifys1 { ROLLBACK TO SAVEPOINT s2; COMMIT; } +step notifys_simple { + BEGIN; + SAVEPOINT s1; + NOTIFY c1, 'simple1'; + NOTIFY c2, 'simple2'; + RELEASE SAVEPOINT s1; + COMMIT; +} +step notify_many_with_dup { + BEGIN; + SELECT pg_notify('c1', 'msg' || s::text) FROM generate_series(1, 17) s; + SELECT pg_notify('c1', 'msg1'); + 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 *; } @@ -53,6 +67,26 @@ step l2begin { BEGIN; } step l2commit { COMMIT; } step l2stop { UNLISTEN *; } +# Third listener session for testing array growth. + +session listener3 +step l3listen { LISTEN c1; } +teardown { UNLISTEN *; } + +# Session for testing LISTEN in subtransaction with separate steps. + +session listen_subxact +step lsbegin { BEGIN; } +step lslisten_outer { LISTEN c3; } +step lssavepoint { SAVEPOINT s1; } +step lslisten { LISTEN c1; LISTEN c2; } +step lsrelease { RELEASE SAVEPOINT s1; } +step lsrollback { ROLLBACK TO SAVEPOINT s1; } +step lscommit { COMMIT; } +step lsnotify { NOTIFY c1, 'subxact_test'; } +step lsnotify_check { NOTIFY c1, 'should_not_receive'; } +teardown { UNLISTEN *; } + # Trivial cases. permutation listenc notify1 notify2 notify3 notifyf @@ -60,6 +94,24 @@ permutation listenc notify1 notify2 notify3 notifyf # Check simple and less-simple deduplication. permutation listenc notifyd1 notifyd2 notifys1 +# Check simple NOTIFY reparenting when parent has no action. +permutation listenc notifys_simple + +# Check LISTEN reparenting in subtransaction. +permutation lsbegin lssavepoint lslisten lsrelease lscommit lsnotify + +# Check LISTEN merge path when both outer and inner transactions have actions. +permutation lsbegin lslisten_outer lssavepoint lslisten lsrelease lscommit lsnotify + +# Check LISTEN abort path (ROLLBACK TO SAVEPOINT discards pending actions). +permutation lsbegin lssavepoint lslisten lsrollback lscommit lsnotify_check + +# Check notification_match function (triggered by hash table duplicate detection). +permutation listenc notify_many_with_dup + +# Check ChannelHashAddListener array growth. +permutation listenc llisten l2listen l3listen lslisten + # 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 -- 2.50.1