Skip to content

Commit fd7dd56

Browse files
committed
meson: ci: test extensions
1 parent 879b849 commit fd7dd56

File tree

3 files changed

+291
-1
lines changed

3 files changed

+291
-1
lines changed

.cirrus.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,16 +358,32 @@ task:
358358
task:
359359
<<: *linux_opensuse_template
360360

361-
name: Linux - OpenSuse Tumbleweed (LLVM) - Meson
361+
name: Linux - OpenSuse Tumbleweed (LLVM) - Meson - Test Extensions
362362

363363
configure_script:
364364
- su postgres -c 'meson setup --buildtype debug -Dcassert=true -Dssl=openssl -Duuid=e2fs -Dllvm=enabled build'
365365

366+
###
367+
# build & run tests
366368
build_script: su postgres -c 'ninja -C build'
369+
367370
upload_caches: ccache
368371

369372
tests_world_script:
370373
- su postgres -c 'meson test --no-rebuild -C build --num-processes ${TEST_JOBS}'
374+
###
375+
376+
###
377+
# test extensions
378+
install_script: ninja -C build install
379+
380+
# some of the make commands of test_execution script needs to run with sudo,
381+
# that command makes postgres user can execute sudo commands without password
382+
dont_ask_sudo_pw_script:
383+
- echo "postgres ALL=(ALL:ALL) NOPASSWD: ALL" | tee /etc/sudoers.d/postgres
384+
385+
install_extensions_script: su postgres -c 'python3 src/tools/ci/test_extensions'
386+
###
371387

372388
on_failure:
373389
<<: *on_failure

src/tools/ci/docker/linux_opensuse_tumbleweed

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ RUN \
4949
lz4 \
5050
zstd \
5151
\
52+
### packages needed by extensions ###
53+
sudo \
54+
\
55+
# pgbouncer
56+
libevent-devel \
57+
pandoc \
58+
\
59+
# postgis
60+
geos-devel \
61+
proj-devel \
62+
protobuf-c \
63+
\
64+
###
5265
&& \
5366
zypper -n clean -a
5467

src/tools/ci/test_extensions

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
#!/usr/bin/env python3
2+
3+
import enum
4+
import os
5+
import shutil
6+
import subprocess
7+
import sys
8+
9+
work_dir = '/tmp/extension_test/'
10+
extensions = []
11+
git_clone_command = ['git', 'clone', '--depth', '1']
12+
13+
class ExitStatus(enum.IntEnum):
14+
already_failed = -1
15+
success = 0
16+
missing_steps = 1
17+
failed = 2
18+
ext_exit_status = []
19+
20+
# add pg_qualstats
21+
extensions.append(
22+
{
23+
'name': 'pg_qualstats',
24+
'shared_preload_name': 'pg_qualstats',
25+
'download': [
26+
git_clone_command + ['https://github.com/powa-team/pg_qualstats.git'],
27+
],
28+
'build': [
29+
['sudo', 'make', 'install'],
30+
],
31+
'test': [
32+
['make', 'installcheck'],
33+
],
34+
}
35+
)
36+
37+
38+
# add pg_cron
39+
extensions.append(
40+
{
41+
'name': 'pg_cron',
42+
'shared_preload_name': 'pg_cron',
43+
'download': [
44+
git_clone_command + ['https://github.com/citusdata/pg_cron.git'],
45+
],
46+
'build': [
47+
['make'],
48+
['sudo', 'make', 'install'],
49+
],
50+
'test': [
51+
['make', 'installcheck'],
52+
],
53+
}
54+
)
55+
56+
# add hypopg
57+
extensions.append(
58+
{
59+
'name': 'hypopg',
60+
'download': [
61+
git_clone_command + ['https://github.com/HypoPG/hypopg.git'],
62+
],
63+
'build': [
64+
['sudo', 'make', 'install'],
65+
],
66+
'test': [
67+
['make', 'installcheck'],
68+
],
69+
}
70+
)
71+
72+
# add postgresql-hll
73+
extensions.append(
74+
{
75+
'name': 'postgresql-hll',
76+
'download': [
77+
git_clone_command + ['https://github.com/citusdata/postgresql-hll.git'],
78+
],
79+
'build': [
80+
['make'],
81+
['sudo', 'make', 'install'],
82+
],
83+
'test': [
84+
['make', 'installcheck'],
85+
],
86+
}
87+
)
88+
89+
# add orafce
90+
extensions.append(
91+
{
92+
'name': 'orafce',
93+
'download': [
94+
git_clone_command + ['https://github.com/orafce/orafce.git'],
95+
],
96+
'build': [
97+
['make'],
98+
['make', 'install'],
99+
],
100+
'test': [
101+
['make', 'installcheck'],
102+
],
103+
}
104+
)
105+
106+
# add postgis
107+
extensions.append(
108+
{
109+
'name': 'postgis',
110+
'download': [
111+
git_clone_command + ['https://github.com/postgis/postgis.git'],
112+
],
113+
'build': [
114+
['./autogen.sh'],
115+
['./configure', '--without-raster'],
116+
['make'],
117+
],
118+
'test': [
119+
['make', 'check'],
120+
],
121+
}
122+
)
123+
124+
# add pg_partman
125+
# there is confirmed pg15 bug, waiting for fix
126+
# see https://github.com/pgpartman/pg_partman/issues/464
127+
# extensions.append(
128+
# {
129+
# 'name': 'pg_partman',
130+
# 'shared_preload_name': 'pg_partman_bgw',
131+
# 'download': [
132+
# git_clone_command + ['https://github.com/pgpartman/pg_partman.git'],
133+
# ],
134+
# 'build': [
135+
# ['make'],
136+
# ['sudo', 'make', 'install'],
137+
# ],
138+
# 'test': [
139+
# # there is no test command,
140+
# # see bottom of https://github.com/pgpartman/pg_partman
141+
# ],
142+
# }
143+
# )
144+
145+
# add pgbouncer
146+
extensions.append(
147+
{
148+
'name': 'pgbouncer',
149+
'download': [
150+
git_clone_command + ['https://github.com/pgbouncer/pgbouncer.git'],
151+
],
152+
'build': [
153+
['git', 'submodule', 'init'],
154+
['git', 'submodule', 'update'],
155+
['./autogen.sh'],
156+
['./configure', '--prefix=/usr/local'],
157+
['make'],
158+
['sudo', 'make', 'install'],
159+
],
160+
'test': [
161+
['make', '-C', './test', 'all'],
162+
['make', '-C', './test', 'check'],
163+
],
164+
}
165+
)
166+
167+
def start_postgres_server():
168+
shared_preload_libraries = ''
169+
170+
# get shared_preload_libraries
171+
for extension in extensions:
172+
if 'shared_preload_name' in extension:
173+
shared_preload_libraries = shared_preload_libraries + extension['shared_preload_name'] + ', '
174+
# removing last ', '
175+
shared_preload_libraries = shared_preload_libraries[:-2]
176+
177+
postgres_start_commands = [
178+
['sudo', 'mkdir', '-p', '/usr/local/pgsql/data'],
179+
['sudo', 'chown', 'postgres', '/usr/local/pgsql/data'],
180+
['/usr/local/bin/initdb', '-D', '/usr/local/pgsql/data/'],
181+
['sed', '-i',
182+
's/#shared_preload_libraries = \'\'/shared_preload_libraries = \'' + shared_preload_libraries + '\'/g',
183+
'/usr/local/pgsql/data/postgresql.conf'],
184+
['/usr/local/bin/pg_ctl', '-D', '/usr/local/pgsql/data', '-l', 'logfile', 'start'],
185+
]
186+
187+
# run postgres server
188+
print('Starting postgres server...', flush=True)
189+
for command in postgres_start_commands:
190+
subprocess.run(command, check=True)
191+
print('Done.', flush=True)
192+
193+
# if that function returns True, that means current process is successfully finished
194+
# otherwise, there can be error or missing commands
195+
def run_commands(extension, current_process, cwd):
196+
message = ''
197+
198+
if extension.get('has_error', False):
199+
return_val = ExitStatus.already_failed
200+
elif extension.get(current_process, False):
201+
print('\n\n### {} {} ###\n'.format(current_process, extension['name']), flush=True)
202+
203+
for command in extension[current_process]:
204+
result = subprocess.run(command, cwd=cwd)
205+
206+
if result.returncode:
207+
message = '`{}` failed at step `{}`'.format(extension['name'], current_process)
208+
extension['has_error'] = True
209+
return_val = ExitStatus.failed
210+
else:
211+
if current_process == 'test':
212+
message = '`{}` finished successfully'.format(extension['name'])
213+
return_val = ExitStatus.success
214+
else:
215+
message = 'No `{}` command found for `{}`'.format(current_process, extension['name'])
216+
return_val = ExitStatus.missing_step_message
217+
218+
if message:
219+
print('\n\n### {} ###\n'.format(message), flush=True)
220+
ext_exit_status.append([message, return_val])
221+
222+
return return_val
223+
224+
def clear_directory(directory):
225+
if os.path.exists(directory) and os.path.isdir(directory):
226+
print('### Clearing {} ###'.format(directory), flush=True)
227+
shutil.rmtree(directory)
228+
229+
def main():
230+
# clear and create work_dir
231+
clear_directory(work_dir)
232+
os.makedirs(work_dir)
233+
234+
# first download then build to get shared_preload_libraries
235+
for extension in extensions:
236+
process_order = [['download', work_dir], ['build', work_dir + extension['name']]]
237+
for process, cwd in process_order:
238+
run_commands(extension, process, cwd)
239+
240+
# start postgres server
241+
start_postgres_server()
242+
243+
# run tests
244+
for extension in extensions:
245+
run_commands(extension, 'test', work_dir + extension['name'])
246+
247+
# sort by exit status(success, missing step, failed)
248+
ext_exit_status.sort(key=lambda tup: tup[1])
249+
previous_exit_status = ext_exit_status[0][1]
250+
print('\nScript finished, results are:\n', flush=True)
251+
for message, current_exit_status in ext_exit_status:
252+
if current_exit_status != previous_exit_status:
253+
print('\n', flush=True)
254+
print(message, flush=True)
255+
previous_exit_status = current_exit_status
256+
257+
if ext_exit_status[-1][1] == ExitStatus.failed:
258+
sys.exit('\n\nThere are failed extensions, exiting')
259+
260+
if __name__ == "__main__":
261+
main()

0 commit comments

Comments
 (0)