Skip to content

Commit af0d490

Browse files
Add test for pg_upgrade file transfer modes.
This new test checks all of pg_upgrade's file transfer modes. For each mode, we verify that pg_upgrade either succeeds (and some test objects successfully reach the new version) or fails with an error that indicates the mode is not supported on the current platform. For cross-version tests, we also check that pg_upgrade transfers non-default tablespaces. (Tablespaces can't be tested on same version upgrades because of the version-specific subdirectory conflict, but we might be able to enable such tests once we teach pg_upgrade how to handle in-place tablespaces.) Suggested-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/Zyvop-LxLXBLrZil%40nathan
1 parent 0164a0f commit af0d490

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

src/bin/pg_upgrade/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ tests += {
4646
't/003_logical_slots.pl',
4747
't/004_subscription.pl',
4848
't/005_char_signedness.pl',
49+
't/006_transfer_modes.pl',
4950
],
5051
'test_kwargs': {'priority': 40}, # pg_upgrade tests are slow
5152
},
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Copyright (c) 2025, PostgreSQL Global Development Group
2+
3+
# Tests for file transfer modes
4+
5+
use strict;
6+
use warnings FATAL => 'all';
7+
8+
use PostgreSQL::Test::Cluster;
9+
use PostgreSQL::Test::Utils;
10+
use Test::More;
11+
12+
sub test_mode
13+
{
14+
my ($mode) = @_;
15+
16+
my $old = PostgreSQL::Test::Cluster->new('old', install_path => $ENV{oldinstall});
17+
my $new = PostgreSQL::Test::Cluster->new('new');
18+
19+
if (defined($ENV{oldinstall}))
20+
{
21+
# Checksums are now enabled by default, but weren't before 18, so pass
22+
# '-k' to initdb on older versions so that upgrades work.
23+
$old->init(extra => ['-k']);
24+
}
25+
else
26+
{
27+
$old->init();
28+
}
29+
$new->init();
30+
31+
# Create a small variety of simple test objects on the old cluster. We'll
32+
# check that these reach the new version after upgrading.
33+
$old->start;
34+
$old->safe_psql('postgres', "CREATE TABLE test1 AS SELECT generate_series(1, 100)");
35+
$old->safe_psql('postgres', "CREATE DATABASE testdb1");
36+
$old->safe_psql('testdb1', "CREATE TABLE test2 AS SELECT generate_series(200, 300)");
37+
$old->safe_psql('testdb1', "VACUUM FULL test2");
38+
$old->safe_psql('testdb1', "CREATE SEQUENCE testseq START 5432");
39+
40+
# For cross-version tests, we can also check that pg_upgrade handles
41+
# tablespaces.
42+
if (defined($ENV{oldinstall}))
43+
{
44+
my $tblspc = PostgreSQL::Test::Utils::tempdir_short();
45+
$old->safe_psql('postgres', "CREATE TABLESPACE test_tblspc LOCATION '$tblspc'");
46+
$old->safe_psql('postgres', "CREATE DATABASE testdb2 TABLESPACE test_tblspc");
47+
$old->safe_psql('postgres', "CREATE TABLE test3 TABLESPACE test_tblspc AS SELECT generate_series(300, 401)");
48+
$old->safe_psql('testdb2', "CREATE TABLE test4 AS SELECT generate_series(400, 502)");
49+
}
50+
$old->stop;
51+
52+
my $result = command_ok_or_fails_like(
53+
[
54+
'pg_upgrade', '--no-sync',
55+
'--old-datadir' => $old->data_dir,
56+
'--new-datadir' => $new->data_dir,
57+
'--old-bindir' => $old->config_data('--bindir'),
58+
'--new-bindir' => $new->config_data('--bindir'),
59+
'--socketdir' => $new->host,
60+
'--old-port' => $old->port,
61+
'--new-port' => $new->port,
62+
$mode
63+
],
64+
qr/.* not supported on this platform|could not .* between old and new data directories: .*/,
65+
qr/^$/,
66+
"pg_upgrade with transfer mode $mode");
67+
68+
# If pg_upgrade was successful, check that all of our test objects reached
69+
# the new version.
70+
if ($result)
71+
{
72+
$new->start;
73+
$result = $new->safe_psql('postgres', "SELECT COUNT(*) FROM test1");
74+
is($result, '100', "test1 data after pg_upgrade $mode");
75+
$result = $new->safe_psql('testdb1', "SELECT COUNT(*) FROM test2");
76+
is($result, '101', "test2 data after pg_upgrade $mode");
77+
$result = $new->safe_psql('testdb1', "SELECT nextval('testseq')");
78+
is($result, '5432', "sequence data after pg_upgrade $mode");
79+
80+
# For cross-version tests, we should have some objects in a non-default
81+
# tablespace.
82+
if (defined($ENV{oldinstall}))
83+
{
84+
$result = $new->safe_psql('postgres', "SELECT COUNT(*) FROM test3");
85+
is($result, '102', "test3 data after pg_upgrade $mode");
86+
$result = $new->safe_psql('testdb2', "SELECT COUNT(*) FROM test4");
87+
is($result, '103', "test4 data after pg_upgrade $mode");
88+
}
89+
$new->stop;
90+
}
91+
92+
$old->clean_node();
93+
$new->clean_node();
94+
}
95+
96+
test_mode('--clone');
97+
test_mode('--copy');
98+
test_mode('--copy-file-range');
99+
test_mode('--link');
100+
101+
done_testing();

src/test/perl/PostgreSQL/Test/Cluster.pm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,6 +2801,25 @@ sub command_fails_like
28012801

28022802
=pod
28032803
2804+
=item $node->command_ok_or_fails_like(...)
2805+
2806+
PostgreSQL::Test::Utils::command_ok_or_fails_like with our connection parameters. See command_ok(...)
2807+
2808+
=cut
2809+
2810+
sub command_ok_or_fails_like
2811+
{
2812+
local $Test::Builder::Level = $Test::Builder::Level + 1;
2813+
2814+
my $self = shift;
2815+
2816+
local %ENV = $self->_get_env();
2817+
2818+
return PostgreSQL::Test::Utils::command_ok_or_fails_like(@_);
2819+
}
2820+
2821+
=pod
2822+
28042823
=item $node->command_checks_all(...)
28052824
28062825
PostgreSQL::Test::Utils::command_checks_all with our connection parameters. See

src/test/perl/PostgreSQL/Test/Utils.pm

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ our @EXPORT = qw(
8989
command_like
9090
command_like_safe
9191
command_fails_like
92+
command_ok_or_fails_like
9293
command_checks_all
9394
9495
$windows_os
@@ -1067,6 +1068,30 @@ sub command_fails_like
10671068

10681069
=pod
10691070
1071+
=item command_ok_or_fails_like(cmd, expected_stdout, expected_stderr, test_name)
1072+
1073+
Check that the command either succeeds or fails with an error that matches the
1074+
given regular expressions.
1075+
1076+
=cut
1077+
1078+
sub command_ok_or_fails_like
1079+
{
1080+
local $Test::Builder::Level = $Test::Builder::Level + 1;
1081+
my ($cmd, $expected_stdout, $expected_stderr, $test_name) = @_;
1082+
my ($stdout, $stderr);
1083+
print("# Running: " . join(" ", @{$cmd}) . "\n");
1084+
my $result = IPC::Run::run $cmd, '>' => \$stdout, '2>' => \$stderr;
1085+
if (!$result)
1086+
{
1087+
like($stdout, $expected_stdout, "$test_name: stdout matches");
1088+
like($stderr, $expected_stderr, "$test_name: stderr matches");
1089+
}
1090+
return $result;
1091+
}
1092+
1093+
=pod
1094+
10701095
=item command_checks_all(cmd, ret, out, err, test_name)
10711096
10721097
Run a command and check its status and outputs.

0 commit comments

Comments
 (0)