diff --git a/test/runner.sh b/test/runner.sh
index edbb6295f..80a415f4e 100755
--- a/test/runner.sh
+++ b/test/runner.sh
@@ -99,7 +99,12 @@ cd ${EXE_DIR}/sql
 # create database and install timescaledb
 ${PSQL} "$@" -U $TEST_ROLE_SUPERUSER -d postgres -v ECHO=none -c "CREATE DATABASE \"${TEST_DBNAME}\";"
 ${PSQL} "$@" -U $TEST_ROLE_SUPERUSER -d ${TEST_DBNAME} -v ECHO=none -c "SET client_min_messages=error; CREATE EXTENSION timescaledb;"
-${PSQL} "$@" -U $TEST_ROLE_SUPERUSER -d ${TEST_DBNAME} -v ECHO=none -v MODULE_PATHNAME="'timescaledb-${EXT_VERSION}'" -v TSL_MODULE_PATHNAME="'timescaledb-tsl-${EXT_VERSION}'" < ${TEST_SUPPORT_FILE} >/dev/null 2>&1
+${PSQL} "$@" -U $TEST_ROLE_SUPERUSER -d ${TEST_DBNAME} \
+    -v ECHO=none \
+    -v MODULE_PATHNAME="'timescaledb-${EXT_VERSION}'" \
+    -v TSL_MODULE_PATHNAME="'timescaledb-tsl-${EXT_VERSION}'" \
+    -v TEST_SPINWAIT_ITERS=${TEST_SPINWAIT_ITERS} \
+    -f ${TEST_SUPPORT_FILE} >/dev/null 2>&1
 export TEST_DBNAME
 
 # we strip out any output between <exclude_from_test></exclude_from_test>
diff --git a/test/sql/utils/testsupport.sql b/test/sql/utils/testsupport.sql
index 1613fb1da..8a6b95e06 100644
--- a/test/sql/utils/testsupport.sql
+++ b/test/sql/utils/testsupport.sql
@@ -309,3 +309,29 @@ BEGIN
     RETURN dirPath;
 END;
 $BODY$;
+
+-- Wait for job to execute with success or failure
+CREATE OR REPLACE FUNCTION test.wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS)
+RETURNS BOOLEAN LANGUAGE PLPGSQL AS
+$BODY$
+DECLARE
+    r RECORD;
+BEGIN
+    FOR i in 1..spins
+    LOOP
+        SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
+        IF (r.total_failures > 0) THEN
+            RAISE INFO 'wait_for_job_to_run: job execution failed';
+            RETURN false;
+        ELSEIF (r.total_successes = expected_runs) THEN
+            RETURN true;
+        ELSEIF (r.total_successes > expected_runs) THEN
+            RAISE 'num_runs > expected';
+        ELSE
+            PERFORM pg_sleep(0.1);
+        END IF;
+    END LOOP;
+    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
+    RETURN false;
+END
+$BODY$;
diff --git a/tsl/test/expected/bgw_custom-13.out b/tsl/test/expected/bgw_custom-13.out
index 13076e04a..cc90865ec 100644
--- a/tsl/test/expected/bgw_custom-13.out
+++ b/tsl/test/expected/bgw_custom-13.out
@@ -274,29 +274,6 @@ SELECT delete_job(:job_id_1);
 (1 row)
 
 -- tests for #3545
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
 TRUNCATE custom_log;
 -- Nested procedure call
 CREATE OR REPLACE PROCEDURE custom_proc_nested(job_id int, args jsonb) LANGUAGE PLPGSQL AS
@@ -351,13 +328,13 @@ SELECT _timescaledb_functions.start_background_workers();
 (1 row)
 
 -- Wait for jobs
-SELECT wait_for_job_to_run(:job_id_1, 1);
+SELECT test.wait_for_job_to_run(:job_id_1, 1);
  wait_for_job_to_run 
 ---------------------
  t
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_2, 1);
+SELECT test.wait_for_job_to_run(:job_id_2, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -389,7 +366,7 @@ SELECT delete_job(:job_id_2);
 TRUNCATE custom_log;
 -- Forced Exception
 SELECT add_job('custom_proc4', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_3 \gset
-SELECT wait_for_job_to_run(:job_id_3, 1);
+SELECT test.wait_for_job_to_run(:job_id_3, 1);
 INFO:  wait_for_job_to_run: job execution failed
  wait_for_job_to_run 
 ---------------------
@@ -443,7 +420,7 @@ SELECT * FROM _timescaledb_internal.compressed_chunk_stats ORDER BY chunk_name;
 
 -- Compression policy
 SELECT add_compression_policy('conditions', interval '1 day') AS job_id_4 \gset
-SELECT wait_for_job_to_run(:job_id_4, 1);
+SELECT test.wait_for_job_to_run(:job_id_4, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -479,7 +456,7 @@ select t.schedule_interval FROM alter_job(:job_id_4, next_start=> now() ) t;
  @ 12 hours
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_4, 2);
+SELECT test.wait_for_job_to_run(:job_id_4, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -525,7 +502,7 @@ GROUP BY location, bucket
 WITH NO DATA;
 -- Refresh Continous Aggregate by Job
 SELECT add_job('custom_proc5', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_5 \gset
-SELECT wait_for_job_to_run(:job_id_5, 1);
+SELECT test.wait_for_job_to_run(:job_id_5, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -840,7 +817,7 @@ END
 $$;
 select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
 -- wait for enough time
-SELECT wait_for_job_to_run(:last_job_id, 1);
+SELECT test.wait_for_job_to_run(:last_job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/bgw_custom-14.out b/tsl/test/expected/bgw_custom-14.out
index c13889328..bd880c3b3 100644
--- a/tsl/test/expected/bgw_custom-14.out
+++ b/tsl/test/expected/bgw_custom-14.out
@@ -274,29 +274,6 @@ SELECT delete_job(:job_id_1);
 (1 row)
 
 -- tests for #3545
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
 TRUNCATE custom_log;
 -- Nested procedure call
 CREATE OR REPLACE PROCEDURE custom_proc_nested(job_id int, args jsonb) LANGUAGE PLPGSQL AS
@@ -351,13 +328,13 @@ SELECT _timescaledb_functions.start_background_workers();
 (1 row)
 
 -- Wait for jobs
-SELECT wait_for_job_to_run(:job_id_1, 1);
+SELECT test.wait_for_job_to_run(:job_id_1, 1);
  wait_for_job_to_run 
 ---------------------
  t
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_2, 1);
+SELECT test.wait_for_job_to_run(:job_id_2, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -389,7 +366,7 @@ SELECT delete_job(:job_id_2);
 TRUNCATE custom_log;
 -- Forced Exception
 SELECT add_job('custom_proc4', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_3 \gset
-SELECT wait_for_job_to_run(:job_id_3, 1);
+SELECT test.wait_for_job_to_run(:job_id_3, 1);
 INFO:  wait_for_job_to_run: job execution failed
  wait_for_job_to_run 
 ---------------------
@@ -443,7 +420,7 @@ SELECT * FROM _timescaledb_internal.compressed_chunk_stats ORDER BY chunk_name;
 
 -- Compression policy
 SELECT add_compression_policy('conditions', interval '1 day') AS job_id_4 \gset
-SELECT wait_for_job_to_run(:job_id_4, 1);
+SELECT test.wait_for_job_to_run(:job_id_4, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -479,7 +456,7 @@ select t.schedule_interval FROM alter_job(:job_id_4, next_start=> now() ) t;
  @ 12 hours
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_4, 2);
+SELECT test.wait_for_job_to_run(:job_id_4, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -525,7 +502,7 @@ GROUP BY location, bucket
 WITH NO DATA;
 -- Refresh Continous Aggregate by Job
 SELECT add_job('custom_proc5', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_5 \gset
-SELECT wait_for_job_to_run(:job_id_5, 1);
+SELECT test.wait_for_job_to_run(:job_id_5, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -840,7 +817,7 @@ END
 $$;
 select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
 -- wait for enough time
-SELECT wait_for_job_to_run(:last_job_id, 1);
+SELECT test.wait_for_job_to_run(:last_job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/bgw_custom-15.out b/tsl/test/expected/bgw_custom-15.out
index c13889328..bd880c3b3 100644
--- a/tsl/test/expected/bgw_custom-15.out
+++ b/tsl/test/expected/bgw_custom-15.out
@@ -274,29 +274,6 @@ SELECT delete_job(:job_id_1);
 (1 row)
 
 -- tests for #3545
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
 TRUNCATE custom_log;
 -- Nested procedure call
 CREATE OR REPLACE PROCEDURE custom_proc_nested(job_id int, args jsonb) LANGUAGE PLPGSQL AS
@@ -351,13 +328,13 @@ SELECT _timescaledb_functions.start_background_workers();
 (1 row)
 
 -- Wait for jobs
-SELECT wait_for_job_to_run(:job_id_1, 1);
+SELECT test.wait_for_job_to_run(:job_id_1, 1);
  wait_for_job_to_run 
 ---------------------
  t
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_2, 1);
+SELECT test.wait_for_job_to_run(:job_id_2, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -389,7 +366,7 @@ SELECT delete_job(:job_id_2);
 TRUNCATE custom_log;
 -- Forced Exception
 SELECT add_job('custom_proc4', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_3 \gset
-SELECT wait_for_job_to_run(:job_id_3, 1);
+SELECT test.wait_for_job_to_run(:job_id_3, 1);
 INFO:  wait_for_job_to_run: job execution failed
  wait_for_job_to_run 
 ---------------------
@@ -443,7 +420,7 @@ SELECT * FROM _timescaledb_internal.compressed_chunk_stats ORDER BY chunk_name;
 
 -- Compression policy
 SELECT add_compression_policy('conditions', interval '1 day') AS job_id_4 \gset
-SELECT wait_for_job_to_run(:job_id_4, 1);
+SELECT test.wait_for_job_to_run(:job_id_4, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -479,7 +456,7 @@ select t.schedule_interval FROM alter_job(:job_id_4, next_start=> now() ) t;
  @ 12 hours
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_4, 2);
+SELECT test.wait_for_job_to_run(:job_id_4, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -525,7 +502,7 @@ GROUP BY location, bucket
 WITH NO DATA;
 -- Refresh Continous Aggregate by Job
 SELECT add_job('custom_proc5', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_5 \gset
-SELECT wait_for_job_to_run(:job_id_5, 1);
+SELECT test.wait_for_job_to_run(:job_id_5, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -840,7 +817,7 @@ END
 $$;
 select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
 -- wait for enough time
-SELECT wait_for_job_to_run(:last_job_id, 1);
+SELECT test.wait_for_job_to_run(:last_job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/bgw_custom-16.out b/tsl/test/expected/bgw_custom-16.out
index c13889328..bd880c3b3 100644
--- a/tsl/test/expected/bgw_custom-16.out
+++ b/tsl/test/expected/bgw_custom-16.out
@@ -274,29 +274,6 @@ SELECT delete_job(:job_id_1);
 (1 row)
 
 -- tests for #3545
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
 TRUNCATE custom_log;
 -- Nested procedure call
 CREATE OR REPLACE PROCEDURE custom_proc_nested(job_id int, args jsonb) LANGUAGE PLPGSQL AS
@@ -351,13 +328,13 @@ SELECT _timescaledb_functions.start_background_workers();
 (1 row)
 
 -- Wait for jobs
-SELECT wait_for_job_to_run(:job_id_1, 1);
+SELECT test.wait_for_job_to_run(:job_id_1, 1);
  wait_for_job_to_run 
 ---------------------
  t
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_2, 1);
+SELECT test.wait_for_job_to_run(:job_id_2, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -389,7 +366,7 @@ SELECT delete_job(:job_id_2);
 TRUNCATE custom_log;
 -- Forced Exception
 SELECT add_job('custom_proc4', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_3 \gset
-SELECT wait_for_job_to_run(:job_id_3, 1);
+SELECT test.wait_for_job_to_run(:job_id_3, 1);
 INFO:  wait_for_job_to_run: job execution failed
  wait_for_job_to_run 
 ---------------------
@@ -443,7 +420,7 @@ SELECT * FROM _timescaledb_internal.compressed_chunk_stats ORDER BY chunk_name;
 
 -- Compression policy
 SELECT add_compression_policy('conditions', interval '1 day') AS job_id_4 \gset
-SELECT wait_for_job_to_run(:job_id_4, 1);
+SELECT test.wait_for_job_to_run(:job_id_4, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -479,7 +456,7 @@ select t.schedule_interval FROM alter_job(:job_id_4, next_start=> now() ) t;
  @ 12 hours
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id_4, 2);
+SELECT test.wait_for_job_to_run(:job_id_4, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -525,7 +502,7 @@ GROUP BY location, bucket
 WITH NO DATA;
 -- Refresh Continous Aggregate by Job
 SELECT add_job('custom_proc5', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_5 \gset
-SELECT wait_for_job_to_run(:job_id_5, 1);
+SELECT test.wait_for_job_to_run(:job_id_5, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -840,7 +817,7 @@ END
 $$;
 select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
 -- wait for enough time
-SELECT wait_for_job_to_run(:last_job_id, 1);
+SELECT test.wait_for_job_to_run(:last_job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/cagg_bgw-13.out b/tsl/test/expected/cagg_bgw-13.out
index cbf9d9420..7990fd717 100644
--- a/tsl/test/expected/cagg_bgw-13.out
+++ b/tsl/test/expected/cagg_bgw-13.out
@@ -195,27 +195,8 @@ BEGIN
     RETURN false;
 END
 $BODY$;
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    num_runs INTEGER;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO num_runs;
-    if (num_runs = expected_runs) THEN
-        RETURN true;
-    ELSEIF (num_runs > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RETURN false;
-END
-$BODY$;
 --make sure there is 1 job to start with
-SELECT wait_for_job_to_run(:job_id, 1);
+SELECT test.wait_for_job_to_run(:job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -254,7 +235,7 @@ SELECT ts_bgw_params_reset_time(extract(epoch from interval '12 hour')::bigint *
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 2);
+SELECT test.wait_for_job_to_run(:job_id, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -289,7 +270,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 3);
+SELECT test.wait_for_job_to_run(:job_id, 3);
  wait_for_job_to_run 
 ---------------------
  t
@@ -320,7 +301,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 4);
+SELECT test.wait_for_job_to_run(:job_id, 4);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/cagg_bgw-14.out b/tsl/test/expected/cagg_bgw-14.out
index cbf9d9420..7990fd717 100644
--- a/tsl/test/expected/cagg_bgw-14.out
+++ b/tsl/test/expected/cagg_bgw-14.out
@@ -195,27 +195,8 @@ BEGIN
     RETURN false;
 END
 $BODY$;
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    num_runs INTEGER;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO num_runs;
-    if (num_runs = expected_runs) THEN
-        RETURN true;
-    ELSEIF (num_runs > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RETURN false;
-END
-$BODY$;
 --make sure there is 1 job to start with
-SELECT wait_for_job_to_run(:job_id, 1);
+SELECT test.wait_for_job_to_run(:job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -254,7 +235,7 @@ SELECT ts_bgw_params_reset_time(extract(epoch from interval '12 hour')::bigint *
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 2);
+SELECT test.wait_for_job_to_run(:job_id, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -289,7 +270,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 3);
+SELECT test.wait_for_job_to_run(:job_id, 3);
  wait_for_job_to_run 
 ---------------------
  t
@@ -320,7 +301,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 4);
+SELECT test.wait_for_job_to_run(:job_id, 4);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/cagg_bgw-15.out b/tsl/test/expected/cagg_bgw-15.out
index cbf9d9420..7990fd717 100644
--- a/tsl/test/expected/cagg_bgw-15.out
+++ b/tsl/test/expected/cagg_bgw-15.out
@@ -195,27 +195,8 @@ BEGIN
     RETURN false;
 END
 $BODY$;
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    num_runs INTEGER;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO num_runs;
-    if (num_runs = expected_runs) THEN
-        RETURN true;
-    ELSEIF (num_runs > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RETURN false;
-END
-$BODY$;
 --make sure there is 1 job to start with
-SELECT wait_for_job_to_run(:job_id, 1);
+SELECT test.wait_for_job_to_run(:job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -254,7 +235,7 @@ SELECT ts_bgw_params_reset_time(extract(epoch from interval '12 hour')::bigint *
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 2);
+SELECT test.wait_for_job_to_run(:job_id, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -289,7 +270,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 3);
+SELECT test.wait_for_job_to_run(:job_id, 3);
  wait_for_job_to_run 
 ---------------------
  t
@@ -320,7 +301,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 4);
+SELECT test.wait_for_job_to_run(:job_id, 4);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/cagg_bgw-16.out b/tsl/test/expected/cagg_bgw-16.out
index d156c791a..15abb5ea0 100644
--- a/tsl/test/expected/cagg_bgw-16.out
+++ b/tsl/test/expected/cagg_bgw-16.out
@@ -195,27 +195,8 @@ BEGIN
     RETURN false;
 END
 $BODY$;
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    num_runs INTEGER;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO num_runs;
-    if (num_runs = expected_runs) THEN
-        RETURN true;
-    ELSEIF (num_runs > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RETURN false;
-END
-$BODY$;
 --make sure there is 1 job to start with
-SELECT wait_for_job_to_run(:job_id, 1);
+SELECT test.wait_for_job_to_run(:job_id, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -254,7 +235,7 @@ SELECT ts_bgw_params_reset_time(extract(epoch from interval '12 hour')::bigint *
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 2);
+SELECT test.wait_for_job_to_run(:job_id, 2);
  wait_for_job_to_run 
 ---------------------
  t
@@ -289,7 +270,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 3);
+SELECT test.wait_for_job_to_run(:job_id, 3);
  wait_for_job_to_run 
 ---------------------
  t
@@ -320,7 +301,7 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
  
 (1 row)
 
-SELECT wait_for_job_to_run(:job_id, 4);
+SELECT test.wait_for_job_to_run(:job_id, 4);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/expected/scheduler_fixed.out b/tsl/test/expected/scheduler_fixed.out
index 08b583db3..f006708d3 100644
--- a/tsl/test/expected/scheduler_fixed.out
+++ b/tsl/test/expected/scheduler_fixed.out
@@ -5,29 +5,6 @@
 -- Setup for testing bgw jobs ---
 --
 \c :TEST_DBNAME :ROLE_SUPERUSER
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
 CREATE OR REPLACE FUNCTION ts_test_next_scheduled_execution_slot(schedule_interval INTERVAL, finish_time TIMESTAMPTZ, initial_start TIMESTAMPTZ, timezone TEXT = NULL)
 RETURNS TIMESTAMPTZ AS :MODULE_PATHNAME LANGUAGE C VOLATILE;
 -- follow exactly cagg_bgw_drop_chunks
@@ -61,13 +38,13 @@ SELECT _timescaledb_functions.start_background_workers();
 
 select initial_start as initial_start_given from timescaledb_information.jobs where job_id = :short_job_fixed \gset
 -- wait for the job to run
-SELECT wait_for_job_to_run(:short_job_fixed, 1);
+SELECT test.wait_for_job_to_run(:short_job_fixed, 1);
  wait_for_job_to_run 
 ---------------------
  t
 (1 row)
 
-SELECT wait_for_job_to_run(:short_job_drifting, 1);
+SELECT test.wait_for_job_to_run(:short_job_drifting, 1);
  wait_for_job_to_run 
 ---------------------
  t
@@ -84,7 +61,7 @@ select :'next_start_short'::timestamptz - :'initial_start_given'::timestamptz as
 
 -- test job that runs for longer than the schedule interval
 select add_job('job_20', schedule_interval => INTERVAL '15 seconds', initial_start => now()) as long_job_fixed \gset
-select wait_for_job_to_run(:long_job_fixed, 1);
+select test.wait_for_job_to_run(:long_job_fixed, 1);
  wait_for_job_to_run 
 ---------------------
  t
diff --git a/tsl/test/sql/bgw_custom.sql.in b/tsl/test/sql/bgw_custom.sql.in
index d32f81139..1c733eff4 100644
--- a/tsl/test/sql/bgw_custom.sql.in
+++ b/tsl/test/sql/bgw_custom.sql.in
@@ -129,30 +129,6 @@ SELECT * FROM timescaledb_information.job_stats WHERE job_id > 1000;
 SELECT delete_job(:job_id_1);
 
 -- tests for #3545
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
-
 TRUNCATE custom_log;
 
 -- Nested procedure call
@@ -209,8 +185,8 @@ SELECT add_job('custom_proc3', '1h', config := '{"type":"procedure"}'::jsonb, in
 SELECT _timescaledb_functions.start_background_workers();
 
 -- Wait for jobs
-SELECT wait_for_job_to_run(:job_id_1, 1);
-SELECT wait_for_job_to_run(:job_id_2, 1);
+SELECT test.wait_for_job_to_run(:job_id_1, 1);
+SELECT test.wait_for_job_to_run(:job_id_2, 1);
 
 -- Check results
 SELECT * FROM custom_log ORDER BY job_id, extra;
@@ -222,7 +198,7 @@ TRUNCATE custom_log;
 
 -- Forced Exception
 SELECT add_job('custom_proc4', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_3 \gset
-SELECT wait_for_job_to_run(:job_id_3, 1);
+SELECT test.wait_for_job_to_run(:job_id_3, 1);
 
 -- Check results
 SELECT * FROM custom_log ORDER BY job_id, extra;
@@ -254,7 +230,7 @@ SELECT * FROM _timescaledb_internal.compressed_chunk_stats ORDER BY chunk_name;
 
 -- Compression policy
 SELECT add_compression_policy('conditions', interval '1 day') AS job_id_4 \gset
-SELECT wait_for_job_to_run(:job_id_4, 1);
+SELECT test.wait_for_job_to_run(:job_id_4, 1);
 
 -- Chunk compress stats
 SELECT * FROM _timescaledb_internal.compressed_chunk_stats ORDER BY chunk_name;
@@ -270,7 +246,7 @@ order by id;
 
 --running job second time, wait for it to complete
 select t.schedule_interval FROM alter_job(:job_id_4, next_start=> now() ) t;
-SELECT wait_for_job_to_run(:job_id_4, 2);
+SELECT test.wait_for_job_to_run(:job_id_4, 2);
 
 SELECT id, table_name, status from _timescaledb_catalog.chunk
 where hypertable_id = (select id from _timescaledb_catalog.hypertable
@@ -297,7 +273,7 @@ WITH NO DATA;
 
 -- Refresh Continous Aggregate by Job
 SELECT add_job('custom_proc5', '1h', config := '{"type":"procedure"}'::jsonb, initial_start := now()) AS job_id_5 \gset
-SELECT wait_for_job_to_run(:job_id_5, 1);
+SELECT test.wait_for_job_to_run(:job_id_5, 1);
 SELECT count(*) FROM conditions_summary_daily;
 
 -- TESTs for alter_job_set_hypertable_id API
@@ -517,7 +493,7 @@ $$;
 
 select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
 -- wait for enough time
-SELECT wait_for_job_to_run(:last_job_id, 1);
+SELECT test.wait_for_job_to_run(:last_job_id, 1);
 select total_runs, total_successes, last_run_status from timescaledb_information.job_stats where job_id = :last_job_id;
 
 -- test coverage for alter_job
diff --git a/tsl/test/sql/cagg_bgw.sql.in b/tsl/test/sql/cagg_bgw.sql.in
index 9cec31699..4d1a0a34b 100644
--- a/tsl/test/sql/cagg_bgw.sql.in
+++ b/tsl/test/sql/cagg_bgw.sql.in
@@ -151,28 +151,8 @@ BEGIN
 END
 $BODY$;
 
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    num_runs INTEGER;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO num_runs;
-    if (num_runs = expected_runs) THEN
-        RETURN true;
-    ELSEIF (num_runs > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RETURN false;
-END
-$BODY$;
-
 --make sure there is 1 job to start with
-SELECT wait_for_job_to_run(:job_id, 1);
+SELECT test.wait_for_job_to_run(:job_id, 1);
 
 SELECT ts_bgw_params_mock_wait_returns_immediately(:WAIT_FOR_OTHER_TO_ADVANCE);
 
@@ -184,7 +164,7 @@ SELECT wait_for_timer_to_run(0);
 --advance to 12:00 so that it runs one more time; now we know the
 --scheduler has loaded up the job with the old schedule_interval
 SELECT ts_bgw_params_reset_time(extract(epoch from interval '12 hour')::bigint * 1000000, true);
-SELECT wait_for_job_to_run(:job_id, 2);
+SELECT test.wait_for_job_to_run(:job_id, 2);
 
 --advance clock 1us to make the scheduler realize the job is done
 SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint * 1000000)+1, true);
@@ -197,7 +177,7 @@ WHERE job_id=:job_id;;
 
 --advance to 12:02, job should have run at 12:01
 SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint * 1000000)+(extract(epoch from interval '2 minute')::bigint * 1000000), true);
-SELECT wait_for_job_to_run(:job_id, 3);
+SELECT test.wait_for_job_to_run(:job_id, 3);
 
 --next run in 1 minute
 SELECT job_id, next_start-last_finish as until_next, total_runs
@@ -211,7 +191,7 @@ WHERE job_id=:job_id \gset
 SELECT alter_job(:job_id, next_start => :'NEW_NEXT_START');
 
 SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint * 1000000)+(extract(epoch from interval '2 minute 30 seconds')::bigint * 1000000), true);
-SELECT wait_for_job_to_run(:job_id, 4);
+SELECT test.wait_for_job_to_run(:job_id, 4);
 
 --advance clock to quit scheduler
 SELECT ts_bgw_params_reset_time(extract(epoch from interval '25 hour')::bigint * 1000000, true);
diff --git a/tsl/test/sql/scheduler_fixed.sql b/tsl/test/sql/scheduler_fixed.sql
index a5d007e18..577d030c4 100644
--- a/tsl/test/sql/scheduler_fixed.sql
+++ b/tsl/test/sql/scheduler_fixed.sql
@@ -7,30 +7,6 @@
 --
 \c :TEST_DBNAME :ROLE_SUPERUSER
 
-CREATE FUNCTION wait_for_job_to_run(job_param_id INTEGER, expected_runs INTEGER, spins INTEGER=:TEST_SPINWAIT_ITERS) RETURNS BOOLEAN LANGUAGE PLPGSQL AS
-$BODY$
-DECLARE
-    r RECORD;
-BEGIN
-    FOR i in 1..spins
-    LOOP
-    SELECT total_successes, total_failures FROM _timescaledb_internal.bgw_job_stat WHERE job_id=job_param_id INTO r;
-    IF (r.total_failures > 0) THEN
-        RAISE INFO 'wait_for_job_to_run: job execution failed';
-        RETURN false;
-    ELSEIF (r.total_successes = expected_runs) THEN
-        RETURN true;
-    ELSEIF (r.total_successes > expected_runs) THEN
-        RAISE 'num_runs > expected';
-    ELSE
-        PERFORM pg_sleep(0.1);
-    END IF;
-    END LOOP;
-    RAISE INFO 'wait_for_job_to_run: timeout after % tries', spins;
-    RETURN false;
-END
-$BODY$;
-
 CREATE OR REPLACE FUNCTION ts_test_next_scheduled_execution_slot(schedule_interval INTERVAL, finish_time TIMESTAMPTZ, initial_start TIMESTAMPTZ, timezone TEXT = NULL)
 RETURNS TIMESTAMPTZ AS :MODULE_PATHNAME LANGUAGE C VOLATILE;
 
@@ -65,8 +41,8 @@ SELECT _timescaledb_functions.start_background_workers();
 select initial_start as initial_start_given from timescaledb_information.jobs where job_id = :short_job_fixed \gset
 
 -- wait for the job to run
-SELECT wait_for_job_to_run(:short_job_fixed, 1);
-SELECT wait_for_job_to_run(:short_job_drifting, 1);
+SELECT test.wait_for_job_to_run(:short_job_fixed, 1);
+SELECT test.wait_for_job_to_run(:short_job_drifting, 1);
 -- select ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(15000);
 
 select next_start as next_start_short from timescaledb_information.job_stats where job_id = :short_job_fixed \gset
@@ -74,7 +50,7 @@ select next_start as next_start_short from timescaledb_information.job_stats whe
 select :'next_start_short'::timestamptz - :'initial_start_given'::timestamptz as schedule_diff;
 -- test job that runs for longer than the schedule interval
 select add_job('job_20', schedule_interval => INTERVAL '15 seconds', initial_start => now()) as long_job_fixed \gset
-select wait_for_job_to_run(:long_job_fixed, 1);
+select test.wait_for_job_to_run(:long_job_fixed, 1);
 
 select initial_start as initial_start_long from timescaledb_information.jobs where job_id = :long_job_fixed \gset
 select next_start as next_start_long from timescaledb_information.job_stats where job_id = :long_job_fixed \gset