From ea9f1b905723716037d9f44b9afbcd05075e9b27 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 24 Jul 2023 16:37:10 +0900
Subject: [PATCH v4] Add TAP tests to worker_spi module

This commit adds TAP tests to check if worker_spi starts background
workers as expected.  sql/worker_spi.sql is gone, replaced by an
equivalent in TAP.

While here, this commit changes the names of bg workers to
distinguish static and dynamic bg workers.
---
 src/test/modules/worker_spi/Makefile          |  8 +-
 src/test/modules/worker_spi/dynamic.conf      |  2 -
 .../worker_spi/expected/worker_spi.out        | 50 -------------
 src/test/modules/worker_spi/meson.build       |  9 +--
 .../modules/worker_spi/sql/worker_spi.sql     | 35 ---------
 .../modules/worker_spi/t/001_worker_spi.pl    | 75 +++++++++++++++++++
 src/test/modules/worker_spi/worker_spi.c      |  8 +-
 7 files changed, 83 insertions(+), 104 deletions(-)
 delete mode 100644 src/test/modules/worker_spi/dynamic.conf
 delete mode 100644 src/test/modules/worker_spi/expected/worker_spi.out
 delete mode 100644 src/test/modules/worker_spi/sql/worker_spi.sql
 create mode 100644 src/test/modules/worker_spi/t/001_worker_spi.pl

diff --git a/src/test/modules/worker_spi/Makefile b/src/test/modules/worker_spi/Makefile
index cbf9b2e37f..024b34cdbb 100644
--- a/src/test/modules/worker_spi/Makefile
+++ b/src/test/modules/worker_spi/Makefile
@@ -6,13 +6,7 @@ EXTENSION = worker_spi
 DATA = worker_spi--1.0.sql
 PGFILEDESC = "worker_spi - background worker example"
 
-REGRESS = worker_spi
-
-# enable our module in shared_preload_libraries for dynamic bgworkers
-REGRESS_OPTS = --temp-config $(top_srcdir)/src/test/modules/worker_spi/dynamic.conf
-
-# Disable installcheck to ensure we cover dynamic bgworkers.
-NO_INSTALLCHECK = 1
+TAP_TESTS = 1
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
diff --git a/src/test/modules/worker_spi/dynamic.conf b/src/test/modules/worker_spi/dynamic.conf
deleted file mode 100644
index bfe015f664..0000000000
--- a/src/test/modules/worker_spi/dynamic.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-shared_preload_libraries = worker_spi
-worker_spi.database = contrib_regression
diff --git a/src/test/modules/worker_spi/expected/worker_spi.out b/src/test/modules/worker_spi/expected/worker_spi.out
deleted file mode 100644
index dc0a79bf75..0000000000
--- a/src/test/modules/worker_spi/expected/worker_spi.out
+++ /dev/null
@@ -1,50 +0,0 @@
-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)
-
diff --git a/src/test/modules/worker_spi/meson.build b/src/test/modules/worker_spi/meson.build
index a8cdfdeb36..68870324c9 100644
--- a/src/test/modules/worker_spi/meson.build
+++ b/src/test/modules/worker_spi/meson.build
@@ -25,12 +25,9 @@ tests += {
   'name': 'worker_spi',
   'sd': meson.current_source_dir(),
   'bd': meson.current_build_dir(),
-  'regress': {
-    'sql': [
-      'worker_spi',
+  'tap': {
+    'tests': [
+      't/001_worker_spi.pl',
     ],
-    'dbname': 'contrib_regression',
-    'regress_args': ['--temp-config', files('dynamic.conf')],
-    'runningcheck': false,
   },
 }
diff --git a/src/test/modules/worker_spi/sql/worker_spi.sql b/src/test/modules/worker_spi/sql/worker_spi.sql
deleted file mode 100644
index 4683523b29..0000000000
--- a/src/test/modules/worker_spi/sql/worker_spi.sql
+++ /dev/null
@@ -1,35 +0,0 @@
-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;
diff --git a/src/test/modules/worker_spi/t/001_worker_spi.pl b/src/test/modules/worker_spi/t/001_worker_spi.pl
new file mode 100644
index 0000000000..4f1943750e
--- /dev/null
+++ b/src/test/modules/worker_spi/t/001_worker_spi.pl
@@ -0,0 +1,75 @@
+# 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;
+
+$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.
+$node->safe_psql('postgres', 'SELECT worker_spi_launch(4) IS NOT NULL;');
+$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 we just inserted.
+$node->poll_query_until('postgres',
+	qq[SELECT count(*) FROM schema4.counted WHERE type = 'delta';], '0');
+my $result = $node->safe_psql('postgres', 'SELECT * FROM schema4.counted;');
+is($result, qq(total|1), 'dynamic worker correctly consumed tuple data');
+
+# 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 static bgworkers have been launched.
+ok( $node->poll_query_until(
+		'mydb',
+		qq[SELECT datname, count(datname) FROM pg_stat_activity
+            WHERE backend_type = 'worker_spi static worker' GROUP BY datname;],
+		'mydb|3'),
+	'static bgworkers all launched')
+  or die
+  "Timed out while waiting for static bgworkers to be launched";
+
+# Ask worker_spi to launch dynamic bgworkers, and check their presence.
+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 worker' 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();
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index ada0fb8ac7..5676073218 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -343,8 +343,8 @@ _PG_init(void)
 	 */
 	for (int i = 1; i <= worker_spi_total_workers; i++)
 	{
-		snprintf(worker.bgw_name, BGW_MAXLEN, "worker_spi worker %d", i);
-		snprintf(worker.bgw_type, BGW_MAXLEN, "worker_spi");
+		snprintf(worker.bgw_name, BGW_MAXLEN, "worker_spi static worker %d", i);
+		snprintf(worker.bgw_type, BGW_MAXLEN, "worker_spi static worker");
 		worker.bgw_main_arg = Int32GetDatum(i);
 
 		RegisterBackgroundWorker(&worker);
@@ -370,8 +370,8 @@ worker_spi_launch(PG_FUNCTION_ARGS)
 	worker.bgw_restart_time = BGW_NEVER_RESTART;
 	sprintf(worker.bgw_library_name, "worker_spi");
 	sprintf(worker.bgw_function_name, "worker_spi_main");
-	snprintf(worker.bgw_name, BGW_MAXLEN, "worker_spi worker %d", i);
-	snprintf(worker.bgw_type, BGW_MAXLEN, "worker_spi");
+	snprintf(worker.bgw_name, BGW_MAXLEN, "worker_spi dynamic worker %d", i);
+	snprintf(worker.bgw_type, BGW_MAXLEN, "worker_spi dynamic worker");
 	worker.bgw_main_arg = Int32GetDatum(i);
 	/* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup */
 	worker.bgw_notify_pid = MyProcPid;
-- 
2.40.1

