Skip to content

Commit 683defd

Browse files
adunstanCommitfest Bot
authored andcommitted
Add more TAP tests for pg_dumpall
Author: Matheus Alcantara <matheusssilv97@gmail.com>
1 parent 98b5038 commit 683defd

File tree

2 files changed

+332
-0
lines changed

2 files changed

+332
-0
lines changed

src/bin/pg_dump/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ tests += {
102102
't/003_pg_dump_with_server.pl',
103103
't/004_pg_dump_parallel.pl',
104104
't/005_pg_dump_filterfile.pl',
105+
't/006_pg_dumpall.pl',
105106
't/010_dump_connstr.pl',
106107
],
107108
},

src/bin/pg_dump/t/006_pg_dumpall.pl

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
# Copyright (c) 2021-2025, PostgreSQL Global Development Group
2+
3+
use strict;
4+
use warnings FATAL => 'all';
5+
6+
use PostgreSQL::Test::Cluster;
7+
use PostgreSQL::Test::Utils;
8+
use Test::More;
9+
10+
my $tempdir = PostgreSQL::Test::Utils::tempdir;
11+
my $run_db = 'postgres';
12+
my $sep = $windows_os ? "\\" : "/";
13+
14+
# Tablespace locations used by "restore_tablespace" test case.
15+
my $tablespace1 = "${tempdir}${sep}tbl1";
16+
my $tablespace2 = "${tempdir}${sep}tbl2";
17+
mkdir($tablespace1) || die "mkdir $tablespace1 $!";
18+
mkdir($tablespace2) || die "mkdir $tablespace2 $!";
19+
20+
# Scape tablespace locations on Windows.
21+
$tablespace1 = $windows_os ? ($tablespace1 =~ s/\\/\\\\/gr) : $tablespace1;
22+
$tablespace2 = $windows_os ? ($tablespace2 =~ s/\\/\\\\/gr) : $tablespace2;
23+
24+
# Where pg_dumpall will be executed.
25+
my $node = PostgreSQL::Test::Cluster->new('node');
26+
$node->init;
27+
$node->start;
28+
29+
30+
###############################################################
31+
# Definition of the pg_dumpall test cases to run.
32+
#
33+
# Each of these test cases are named and those names are used for fail
34+
# reporting and also to save the dump and restore information needed for the
35+
# test to assert.
36+
#
37+
# The "setup_sql" is a psql valid script that contains SQL commands to execute
38+
# before of actually execute the tests. The setups are all executed before of
39+
# any test execution.
40+
#
41+
# The "dump_cmd" and "restore_cmd" are the commands that will be executed. The
42+
# "restore_cmd" must have the --file flag to save the restore output so that we
43+
# can assert on it.
44+
#
45+
# The "like" and "unlike" is a regexp that is used to match the pg_restore
46+
# output. It must have at least one of then filled per test cases but it also
47+
# can have both. See "excluding_databases" test case for example.
48+
my %pgdumpall_runs = (
49+
restore_roles => {
50+
setup_sql => '
51+
CREATE ROLE dumpall WITH ENCRYPTED PASSWORD \'admin\' SUPERUSER;
52+
CREATE ROLE dumpall2 WITH REPLICATION CONNECTION LIMIT 10;',
53+
dump_cmd => [
54+
'pg_dumpall',
55+
'--format' => 'directory',
56+
'--file' => "$tempdir/restore_roles",
57+
],
58+
restore_cmd => [
59+
'pg_restore', '-C',
60+
'--format' => 'directory',
61+
'--file' => "$tempdir/restore_roles.sql",
62+
"$tempdir/restore_roles",
63+
],
64+
like => qr/
65+
^\s*\QCREATE ROLE dumpall;\E\s*\n
66+
\s*\QALTER ROLE dumpall WITH SUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN NOREPLICATION NOBYPASSRLS PASSWORD 'SCRAM-SHA-256\E
67+
[^']+';\s*\n
68+
\s*\QCREATE ROLE dumpall2;\E
69+
\s*\QALTER ROLE dumpall2 WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN REPLICATION NOBYPASSRLS CONNECTION LIMIT 10;\E
70+
/xm
71+
},
72+
73+
restore_tablespace => {
74+
setup_sql => "
75+
CREATE ROLE tap;
76+
CREATE TABLESPACE tbl1 OWNER tap LOCATION '$tablespace1';
77+
CREATE TABLESPACE tbl2 OWNER tap LOCATION '$tablespace2' WITH (seq_page_cost=1.0);",
78+
dump_cmd => [
79+
'pg_dumpall',
80+
'--format' => 'directory',
81+
'--file' => "$tempdir/restore_tablespace",
82+
],
83+
restore_cmd => [
84+
'pg_restore', '-C',
85+
'--format' => 'directory',
86+
'--file' => "$tempdir/restore_tablespace.sql",
87+
"$tempdir/restore_tablespace",
88+
],
89+
# Match "E" as optional since it is added on LOCATION when running on
90+
# Windows.
91+
like => qr/^
92+
\n\QCREATE TABLESPACE tbl1 OWNER tap LOCATION \E(?:E)?\Q'$tablespace1';\E
93+
\n\QCREATE TABLESPACE tbl2 OWNER tap LOCATION \E(?:E)?\Q'$tablespace2';\E
94+
\n\QALTER TABLESPACE tbl2 SET (seq_page_cost=1.0);\E
95+
/xm,
96+
},
97+
98+
restore_grants => {
99+
setup_sql => "
100+
CREATE DATABASE tapgrantsdb;
101+
CREATE SCHEMA private;
102+
CREATE SEQUENCE serial START 101;
103+
CREATE FUNCTION fn() RETURNS void AS \$\$
104+
BEGIN
105+
END;
106+
\$\$ LANGUAGE plpgsql;
107+
CREATE ROLE super;
108+
CREATE ROLE grant1;
109+
CREATE ROLE grant2;
110+
CREATE ROLE grant3;
111+
CREATE ROLE grant4;
112+
CREATE ROLE grant5;
113+
CREATE ROLE grant6;
114+
CREATE ROLE grant7;
115+
CREATE ROLE grant8;
116+
117+
CREATE TABLE t (id int);
118+
119+
GRANT SELECT ON TABLE t TO grant1;
120+
GRANT INSERT ON TABLE t TO grant2;
121+
GRANT ALL PRIVILEGES ON TABLE t to grant3;
122+
GRANT CONNECT, CREATE ON DATABASE tapgrantsdb TO grant4;
123+
GRANT USAGE, CREATE ON SCHEMA private TO grant5;
124+
GRANT USAGE, SELECT, UPDATE ON SEQUENCE serial TO grant6;
125+
GRANT super TO grant7;
126+
GRANT EXECUTE ON FUNCTION fn() TO grant8;
127+
",
128+
dump_cmd => [
129+
'pg_dumpall',
130+
'--format' => 'directory',
131+
'--file' => "$tempdir/restore_grants",
132+
],
133+
restore_cmd => [
134+
'pg_restore', '-C',
135+
'--format' => 'directory',
136+
'--file' => "$tempdir/restore_grants.sql",
137+
"$tempdir/restore_grants",
138+
],
139+
like => qr/^
140+
\n\QGRANT super TO grant7 WITH INHERIT TRUE GRANTED BY\E
141+
(.*\n)*
142+
\n\QGRANT ALL ON SCHEMA private TO grant5;\E
143+
(.*\n)*
144+
\n\QGRANT ALL ON FUNCTION public.fn() TO grant8;\E
145+
(.*\n)*
146+
\n\QGRANT ALL ON SEQUENCE public.serial TO grant6;\E
147+
(.*\n)*
148+
\n\QGRANT SELECT ON TABLE public.t TO grant1;\E
149+
\n\QGRANT INSERT ON TABLE public.t TO grant2;\E
150+
\n\QGRANT ALL ON TABLE public.t TO grant3;\E
151+
(.*\n)*
152+
\n\QGRANT CREATE,CONNECT ON DATABASE tapgrantsdb TO grant4;\E
153+
/xm,
154+
},
155+
156+
excluding_databases => {
157+
setup_sql => 'CREATE DATABASE db1;
158+
\c db1
159+
CREATE TABLE t1 (id int);
160+
CREATE TABLE t2 (id int);
161+
162+
CREATE DATABASE db2;
163+
\c db2
164+
CREATE TABLE t3 (id int);
165+
CREATE TABLE t4 (id int);
166+
167+
CREATE DATABASE dbex3;
168+
\c dbex3
169+
CREATE TABLE t5 (id int);
170+
CREATE TABLE t6 (id int);
171+
172+
CREATE DATABASE dbex4;
173+
\c dbex4
174+
CREATE TABLE t7 (id int);
175+
CREATE TABLE t8 (id int);
176+
177+
CREATE DATABASE db5;
178+
\c db5
179+
CREATE TABLE t9 (id int);
180+
CREATE TABLE t10 (id int);
181+
',
182+
dump_cmd => [
183+
'pg_dumpall',
184+
'--format' => 'directory',
185+
'--file' => "$tempdir/excluding_databases",
186+
'--exclude-database' => 'dbex*',
187+
],
188+
restore_cmd => [
189+
'pg_restore', '-C',
190+
'--format' => 'directory',
191+
'--file' => "$tempdir/excluding_databases.sql",
192+
'--exclude-database' => 'db5',
193+
"$tempdir/excluding_databases",
194+
],
195+
like => qr/^
196+
\n\QCREATE DATABASE db1\E
197+
(.*\n)*
198+
\n\QCREATE TABLE public.t1 (\E
199+
(.*\n)*
200+
\n\QCREATE TABLE public.t2 (\E
201+
(.*\n)*
202+
\n\QCREATE DATABASE db2\E
203+
(.*\n)*
204+
\n\QCREATE TABLE public.t3 (\E
205+
(.*\n)*
206+
\n\QCREATE TABLE public.t4 (/xm,
207+
unlike => qr/^
208+
\n\QCREATE DATABASE db3\E
209+
(.*\n)*
210+
\n\QCREATE TABLE public.t5 (\E
211+
(.*\n)*
212+
\n\QCREATE TABLE public.t6 (\E
213+
(.*\n)*
214+
\n\QCREATE DATABASE db4\E
215+
(.*\n)*
216+
\n\QCREATE TABLE public.t7 (\E
217+
(.*\n)*
218+
\n\QCREATE TABLE public.t8 (\E
219+
\n\QCREATE DATABASE db5\E
220+
(.*\n)*
221+
\n\QCREATE TABLE public.t9 (\E
222+
(.*\n)*
223+
\n\QCREATE TABLE public.t10 (\E
224+
/xm,
225+
},
226+
227+
format_directory => {
228+
setup_sql =>
229+
'CREATE TABLE format_directory(a int, b boolean, c text);',
230+
dump_cmd => [
231+
'pg_dumpall',
232+
'--format' => 'directory',
233+
'--file' => "$tempdir/format_directory",
234+
],
235+
restore_cmd => [
236+
'pg_restore', '-C',
237+
'--format' => 'directory',
238+
'--file' => "$tempdir/format_directory.sql",
239+
"$tempdir/format_directory",
240+
],
241+
like => qr/^\n\QCREATE TABLE public.format_directory (/xm
242+
},
243+
244+
format_tar => {
245+
setup_sql => 'CREATE TABLE format_tar(id int);',
246+
dump_cmd => [
247+
'pg_dumpall',
248+
'--format' => 'tar',
249+
'--file' => "$tempdir/format_tar",
250+
],
251+
restore_cmd => [
252+
'pg_restore', '-C',
253+
'--format' => 'tar',
254+
'--file' => "$tempdir/format_tar.sql",
255+
"$tempdir/format_tar",
256+
],
257+
like => qr/^\n\QCREATE TABLE public.format_tar (/xm
258+
},
259+
260+
format_custom => {
261+
setup_sql => 'CREATE TABLE format_custom(a int, b boolean, c text);',
262+
dump_cmd => [
263+
'pg_dumpall',
264+
'--format' => 'custom',
265+
'--file' => "$tempdir/format_custom",
266+
],
267+
restore_cmd => [
268+
'pg_restore', '-C',
269+
'--format' => 'custom',
270+
'--file' => "$tempdir/format_custom.sql",
271+
"$tempdir/format_custom",
272+
],
273+
like => qr/^ \n\QCREATE TABLE public.format_custom (/xm
274+
},);
275+
276+
277+
# First execute the setup_sql
278+
foreach my $run (sort keys %pgdumpall_runs)
279+
{
280+
if ($pgdumpall_runs{$run}->{setup_sql})
281+
{
282+
$node->safe_psql($run_db, $pgdumpall_runs{$run}->{setup_sql});
283+
}
284+
}
285+
286+
# Execute the tests
287+
foreach my $run (sort keys %pgdumpall_runs)
288+
{
289+
# Create a new target cluster to pg_restore each test case run so that we
290+
# don't need to take care of the cleanup from the target cluster after each
291+
# run.
292+
my $target_node = PostgreSQL::Test::Cluster->new("target_$run");
293+
$target_node->init;
294+
$target_node->start;
295+
296+
# Dumpall from node cluster.
297+
$node->command_ok(\@{ $pgdumpall_runs{$run}->{dump_cmd} },
298+
"$run: pg_dumpall runs");
299+
300+
# Restore the dump on "target_node" cluster.
301+
my @restore_cmd = (
302+
@{ $pgdumpall_runs{$run}->{restore_cmd} },
303+
'--host', $target_node->host, '--port', $target_node->port);
304+
305+
my ($stdout, $stderr) = run_command(\@restore_cmd);
306+
307+
# pg_restore --file output file.
308+
my $output_file = slurp_file("$tempdir/${run}.sql");
309+
310+
if (!($pgdumpall_runs{$run}->{like}) && !($pgdumpall_runs{$run}->{unlike}))
311+
{
312+
die "missing \"like\" or \"unlike\" in test \"$run\"";
313+
}
314+
315+
if ($pgdumpall_runs{$run}->{like})
316+
{
317+
like($output_file, $pgdumpall_runs{$run}->{like}, "should dump $run");
318+
}
319+
320+
if ($pgdumpall_runs{$run}->{unlike})
321+
{
322+
unlike(
323+
$output_file,
324+
$pgdumpall_runs{$run}->{unlike},
325+
"should not dump $run");
326+
}
327+
}
328+
329+
$node->stop('fast');
330+
331+
done_testing();

0 commit comments

Comments
 (0)