From 912260657dc1a5ebc1534ac755f4f8065c5719aa Mon Sep 17 00:00:00 2001
From: Nazir Bilal Yavuz <byavuz81@gmail.com>
Date: Thu, 27 Feb 2025 17:45:31 +0300
Subject: [PATCH v6 3/7] meson: Test building extensions by using
 postgresql-extension.pc

The 'test_meson_extensions' pyton wrapper is added to run these tests.
It compiles and builds extensions at
${build}/testrun/meson_extensions/${extension_name} path.

The tests for building amcheck, auth_delay and postgres_fdw extensions
are added. These are also examples of how to build extensions by using
postgresql-extension.pc.

Author: Andres Freund <andres@anarazel.de>
Author: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/206b001d-1884-4081-bd02-bed5c92f02ba%40eisentraut.org
---
 src/test/modules/meson.build                  |  1 +
 .../modules/test_meson_extensions/meson.build |  3 +
 .../amcheck/meson.build                       | 28 ++++++++
 .../auth_delay/meson.build                    | 17 +++++
 .../test_pkg_config_extensions/meson.build    | 24 +++++++
 .../postgres_fdw/meson.build                  | 30 ++++++++
 meson.build                                   | 32 +++++++++
 src/tools/ci/test_meson_extensions            | 70 +++++++++++++++++++
 8 files changed, 205 insertions(+)
 create mode 100644 src/test/modules/test_meson_extensions/meson.build
 create mode 100644 src/test/modules/test_meson_extensions/test_pkg_config_extensions/amcheck/meson.build
 create mode 100644 src/test/modules/test_meson_extensions/test_pkg_config_extensions/auth_delay/meson.build
 create mode 100644 src/test/modules/test_meson_extensions/test_pkg_config_extensions/meson.build
 create mode 100644 src/test/modules/test_meson_extensions/test_pkg_config_extensions/postgres_fdw/meson.build
 create mode 100644 src/tools/ci/test_meson_extensions

diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 9de0057bd1d..94db733c4ad 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -26,6 +26,7 @@ subdir('test_ginpostinglist')
 subdir('test_integerset')
 subdir('test_json_parser')
 subdir('test_lfind')
+subdir('test_meson_extensions')
 subdir('test_misc')
 subdir('test_oat_hooks')
 subdir('test_parser')
diff --git a/src/test/modules/test_meson_extensions/meson.build b/src/test/modules/test_meson_extensions/meson.build
new file mode 100644
index 00000000000..06cf5d555df
--- /dev/null
+++ b/src/test/modules/test_meson_extensions/meson.build
@@ -0,0 +1,3 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+subdir('test_pkg_config_extensions')
diff --git a/src/test/modules/test_meson_extensions/test_pkg_config_extensions/amcheck/meson.build b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/amcheck/meson.build
new file mode 100644
index 00000000000..482a543eb86
--- /dev/null
+++ b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/amcheck/meson.build
@@ -0,0 +1,28 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+project('amcheck', 'c')
+
+amcheck_path = '../../../../../../contrib/amcheck/'
+
+amcheck_sources = files(
+  amcheck_path / 'verify_heapam.c',
+  amcheck_path / 'verify_nbtree.c',
+)
+
+pg_ext = dependency('postgresql-extension-warnings')
+
+amcheck = shared_module('amcheck',
+  amcheck_sources,
+  dependencies: pg_ext,
+  install_dir: pg_ext.get_variable(pkgconfig: 'dir_mod'),
+)
+
+install_data(
+  amcheck_path / 'amcheck.control',
+  amcheck_path / 'amcheck--1.0.sql',
+  amcheck_path / 'amcheck--1.0--1.1.sql',
+  amcheck_path / 'amcheck--1.1--1.2.sql',
+  amcheck_path / 'amcheck--1.2--1.3.sql',
+  amcheck_path / 'amcheck--1.3--1.4.sql',
+  install_dir: pg_ext.get_variable(pkgconfig: 'dir_data'),
+)
diff --git a/src/test/modules/test_meson_extensions/test_pkg_config_extensions/auth_delay/meson.build b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/auth_delay/meson.build
new file mode 100644
index 00000000000..98ad24cc183
--- /dev/null
+++ b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/auth_delay/meson.build
@@ -0,0 +1,17 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+project('auth_delay', 'c')
+
+auth_delay_path = '../../../../../../contrib/auth_delay/'
+
+auth_delay_sources = files(
+  auth_delay_path / 'auth_delay.c',
+)
+
+pg_ext = dependency('postgresql-extension-warnings')
+
+auth_delay = shared_module('auth_delay',
+  auth_delay_sources,
+  dependencies: pg_ext,
+  install_dir: pg_ext.get_variable(pkgconfig: 'dir_mod'),
+)
diff --git a/src/test/modules/test_meson_extensions/test_pkg_config_extensions/meson.build b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/meson.build
new file mode 100644
index 00000000000..dae94a384a1
--- /dev/null
+++ b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/meson.build
@@ -0,0 +1,24 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+# pkgconfig is not available on Windows, so skip it.
+if host_machine.system() == 'windows'
+  subdir_done()
+endif
+
+meson_extension_tests += {
+  'name': 'amcheck',
+  'kind': 'pkg_config',
+  'sd': meson.current_source_dir() / 'amcheck',
+}
+
+meson_extension_tests += {
+  'name': 'auth_delay',
+  'kind': 'pkg_config',
+  'sd': meson.current_source_dir() / 'auth_delay',
+}
+
+meson_extension_tests += {
+  'name': 'postgres_fdw',
+  'kind': 'pkg_config',
+  'sd': meson.current_source_dir() / 'postgres_fdw',
+}
diff --git a/src/test/modules/test_meson_extensions/test_pkg_config_extensions/postgres_fdw/meson.build b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/postgres_fdw/meson.build
new file mode 100644
index 00000000000..6d561e3789b
--- /dev/null
+++ b/src/test/modules/test_meson_extensions/test_pkg_config_extensions/postgres_fdw/meson.build
@@ -0,0 +1,30 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+project('auth_delay', 'c')
+
+postgres_fdw_path = '../../../../../../contrib/postgres_fdw/'
+
+postgres_fdw_sources = files(
+  postgres_fdw_path / 'connection.c',
+  postgres_fdw_path / 'deparse.c',
+  postgres_fdw_path / 'option.c',
+  postgres_fdw_path / 'postgres_fdw.c',
+  postgres_fdw_path / 'shippable.c',
+)
+
+pg_ext = dependency('postgresql-extension-warnings')
+libpq = dependency('libpq')
+
+postgres_fdw = shared_module('postgres_fdw',
+  postgres_fdw_sources,
+  dependencies: [pg_ext, libpq],
+  install_dir: pg_ext.get_variable(pkgconfig: 'dir_mod'),
+)
+
+install_data(
+  postgres_fdw_path / 'postgres_fdw.control',
+  postgres_fdw_path / 'postgres_fdw--1.0.sql',
+  postgres_fdw_path / 'postgres_fdw--1.0--1.1.sql',
+  postgres_fdw_path / 'postgres_fdw--1.1--1.2.sql',
+  install_dir: pg_ext.get_variable(pkgconfig: 'dir_data'),
+)
diff --git a/meson.build b/meson.build
index 6a03bc461e6..455f4715bf3 100644
--- a/meson.build
+++ b/meson.build
@@ -3048,6 +3048,7 @@ nls_targets = []
 # Define the tests to distribute them to the correct test styles later
 test_deps = []
 tests = []
+meson_extension_tests = []
 
 
 # Default options for targets
@@ -3603,6 +3604,37 @@ sys.exit(sp.returncode)
      suite: ['setup'])
 
 
+# it seems freebsd doesn't use libdir for pkgconfig path
+if host_system == 'freebsd'
+  pkgconf_installdir =  dir_prefix / 'libdata' / 'pkgconfig'
+else
+  pkgconf_installdir = dir_prefix / dir_lib / 'pkgconfig'
+endif
+test_pkg_conf_file = files('src/tools/ci/test_meson_extensions')
+
+foreach test : meson_extension_tests
+  if test['kind'] not in ['pkg_config']
+    error('unknown kind @0@ of test in @1@'.format(test['kind'], test['sd']))
+  endif
+
+  test_group = 'meson_@0@_extensions'.format(test['kind'])
+
+  test(test_group / test['name'],
+      test_pkg_conf_file,
+      args: [
+        '--meson', meson_bin.path(),
+        '--meson_args', meson_args,
+        '--test_dir', test['sd'],
+        '--test_out_dir', test_result_dir / 'meson_extensions' / test['name'],
+        '--builddir', meson.build_root(),
+        '--pkg_conf_path', get_option('pkg_config_path'),
+        '--',
+          cc.cmd_array(),
+        ],
+        suite: test_group,
+      )
+
+endforeach
 
 ###############################################################
 # Test Generation
diff --git a/src/tools/ci/test_meson_extensions b/src/tools/ci/test_meson_extensions
new file mode 100644
index 00000000000..50358121f49
--- /dev/null
+++ b/src/tools/ci/test_meson_extensions
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import shutil
+import subprocess
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--meson', help='path to meson binary',
+                    type=str, required=True)
+parser.add_argument('--meson_args', help='args of meson binary',
+                    type=str, nargs='*', required=False)
+parser.add_argument('--test_dir', help='test source directory',
+                    type=str, required=True)
+parser.add_argument('--test_out_dir', help='test output directory',
+                    type=str, required=True)
+parser.add_argument('--builddir', help='meson build directory',
+                    type=str, required=True)
+parser.add_argument('--pkg_conf_path',
+                    help='PKG_CONF_PATH from surrounding meson build',
+                    type=str, nargs='?', const='', required=False)
+parser.add_argument('c_args', help='c_args from surrounding meson build',
+                     nargs='*')
+
+args = parser.parse_args()
+
+meson_bin = args.meson
+meson_args = ' '.join(args.meson_args)
+test_source_dir = args.test_dir
+test_out_dir = args.test_out_dir
+build_dir = args.builddir
+pkg_conf_path = args.pkg_conf_path
+c_args = ' '.join(args.c_args)
+
+exit_code = 0
+
+def remove_duplicates(duplicate_str):
+    words = duplicate_str.split()
+    return ' '.join(sorted(set(words), key=words.index))
+
+
+def run_tests(pkg_conf_path_local, message):
+    print('\n{}\n{}\n'.format('#' * 60, message), flush=True)
+
+    env = {**os.environ, }
+    env['PKG_CONFIG_PATH'] = '{}:{}:{}'.format(
+      pkg_conf_path_local, pkg_conf_path, env.get('PKG_CONFIG_PATH', ''),
+    ).strip(': ')
+    env['CC'] = '{} {}'.format(
+      c_args, env.get('CC', ''),
+    )
+    env['CC'] = remove_duplicates(env['CC'])
+
+    # Clear the build directory beforehand.
+    if os.path.exists(test_out_dir):
+        shutil.rmtree(test_out_dir)
+
+    if meson_args:
+        meson_setup_command = [meson_bin, meson_args, 'setup', test_out_dir]
+    else:
+        meson_setup_command = [meson_bin, 'setup', test_out_dir]
+
+    meson_compile_command = ['meson', 'compile', '-C', test_out_dir, '-v']
+
+    subprocess.run(meson_setup_command, env=env, cwd=test_source_dir, check=True)
+    subprocess.run(meson_compile_command, cwd=test_source_dir, check=True)
+
+run_tests(os.path.join(build_dir, 'meson-uninstalled'),
+          message='Testing postgresql-extension-warnings-uninstalled')
-- 
2.49.0

