+++ /dev/null
-CREATE EXTENSION worker_spi;
-SELECT worker_spi_launch(4) IS NOT NULL;
- ?column?
-----------
- t
-(1 row)
-
--- wait until the worker completes its initialization
-DO $$
-DECLARE
- visible bool;
- loops int := 0;
-BEGIN
- LOOP
- visible := table_name IS NOT NULL
- FROM information_schema.tables
- WHERE table_schema = 'schema4' AND table_name = 'counted';
- IF visible OR loops > 120 * 10 THEN EXIT; END IF;
- PERFORM pg_sleep(0.1);
- loops := loops + 1;
- END LOOP;
-END
-$$;
-INSERT INTO schema4.counted VALUES ('total', 0), ('delta', 1);
-SELECT pg_reload_conf();
- pg_reload_conf
-----------------
- t
-(1 row)
-
--- wait until the worker has processed the tuple we just inserted
-DO $$
-DECLARE
- count int;
- loops int := 0;
-BEGIN
- LOOP
- count := count(*) FROM schema4.counted WHERE type = 'delta';
- IF count = 0 OR loops > 120 * 10 THEN EXIT; END IF;
- PERFORM pg_sleep(0.1);
- loops := loops + 1;
- END LOOP;
-END
-$$;
-SELECT * FROM schema4.counted;
- type | value
--------+-------
- total | 1
-(1 row)
-
+++ /dev/null
-CREATE EXTENSION worker_spi;
-SELECT worker_spi_launch(4) IS NOT NULL;
--- wait until the worker completes its initialization
-DO $$
-DECLARE
- visible bool;
- loops int := 0;
-BEGIN
- LOOP
- visible := table_name IS NOT NULL
- FROM information_schema.tables
- WHERE table_schema = 'schema4' AND table_name = 'counted';
- IF visible OR loops > 120 * 10 THEN EXIT; END IF;
- PERFORM pg_sleep(0.1);
- loops := loops + 1;
- END LOOP;
-END
-$$;
-INSERT INTO schema4.counted VALUES ('total', 0), ('delta', 1);
-SELECT pg_reload_conf();
--- wait until the worker has processed the tuple we just inserted
-DO $$
-DECLARE
- count int;
- loops int := 0;
-BEGIN
- LOOP
- count := count(*) FROM schema4.counted WHERE type = 'delta';
- IF count = 0 OR loops > 120 * 10 THEN EXIT; END IF;
- PERFORM pg_sleep(0.1);
- loops := loops + 1;
- END LOOP;
-END
-$$;
-SELECT * FROM schema4.counted;
--- /dev/null
+# Copyright (c) 2023, PostgreSQL Global Development Group
+
+# Test worker_spi module.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('mynode');
+$node->init;
+$node->start;
+
+note "testing dynamic bgworkers";
+
+$node->safe_psql('postgres', 'CREATE EXTENSION worker_spi;');
+
+# Launch one dynamic worker, then wait for its initialization to complete.
+# This consists in making sure that a table name "counted" is created
+# on a new schema whose name includes the index defined in input argument
+# of worker_spi_launch().
+# By default, dynamic bgworkers connect to the "postgres" database.
+my $result =
+ $node->safe_psql('postgres', 'SELECT worker_spi_launch(4) IS NOT NULL;');
+is($result, 't', "dynamic bgworker launched");
+$node->poll_query_until(
+ 'postgres',
+ qq[SELECT count(*) > 0 FROM information_schema.tables
+ WHERE table_schema = 'schema4' AND table_name = 'counted';]);
+$node->safe_psql('postgres',
+ "INSERT INTO schema4.counted VALUES ('total', 0), ('delta', 1);");
+# Issue a SIGHUP on the node to force the worker to loop once, accelerating
+# this test.
+$node->reload;
+# Wait until the worker has processed the tuple that has just been inserted.
+$node->poll_query_until('postgres',
+ qq[SELECT count(*) FROM schema4.counted WHERE type = 'delta';], '0');
+$result = $node->safe_psql('postgres', 'SELECT * FROM schema4.counted;');
+is($result, qq(total|1), 'dynamic bgworker correctly consumed tuple data');
+
+note "testing bgworkers loaded with shared_preload_libraries";
+
+# Create the database first so as the workers can connect to it when
+# the library is loaded.
+$node->safe_psql('postgres', q(CREATE DATABASE mydb;));
+$node->safe_psql('mydb', 'CREATE EXTENSION worker_spi;');
+
+# Now load the module as a shared library.
+$node->append_conf(
+ 'postgresql.conf', q{
+shared_preload_libraries = 'worker_spi'
+worker_spi.database = 'mydb'
+worker_spi.total_workers = 3
+});
+$node->restart;
+
+# Check that bgworkers have been registered and launched.
+ok( $node->poll_query_until(
+ 'mydb',
+ qq[SELECT datname, count(datname) FROM pg_stat_activity
+ WHERE backend_type = 'worker_spi' GROUP BY datname;],
+ 'mydb|3'),
+ 'bgworkers all launched'
+) or die "Timed out while waiting for bgworkers to be launched";
+
+# Ask worker_spi to launch dynamic bgworkers with the library loaded, then
+# check their existence.
+my $worker1_pid = $node->safe_psql('mydb', 'SELECT worker_spi_launch(1);');
+my $worker2_pid = $node->safe_psql('mydb', 'SELECT worker_spi_launch(2);');
+ok( $node->poll_query_until(
+ 'mydb',
+ qq[SELECT datname, count(datname) FROM pg_stat_activity
+ WHERE backend_type = 'worker_spi dynamic' AND
+ pid IN ($worker1_pid, $worker2_pid) GROUP BY datname;],
+ 'mydb|2'),
+ 'dynamic bgworkers all launched'
+) or die "Timed out while waiting for dynamic bgworkers to be launched";
+
+done_testing();