# Copyright (c) 2021-2025, PostgreSQL Global Development Group use strict; use warnings FATAL => 'all'; use File::Copy; use PostgreSQL::Test::Cluster; use PostgreSQL::Test::Utils; use Test::More; # Can be changed to test the other modes. my $mode = $ENV{PG_TEST_PG_COMBINEBACKUP_MODE} || '--copy'; note "testing using mode $mode"; # Set up a new database instance. my $primary = PostgreSQL::Test::Cluster->new('primary'); $primary->init(has_archiving => 1, allows_streaming => 1); $primary->append_conf('postgresql.conf', 'summarize_wal = on'); $primary->start; # Take a full backup. my $backup1path = $primary->backup_dir . '/backup1'; $primary->command_ok( [ 'pg_basebackup', '--pgdata' => $backup1path, '--no-sync', '--checkpoint' => 'fast' ], "full backup"); # Take an incremental backup. my $backup2path = $primary->backup_dir . '/backup2'; $primary->command_ok( [ 'pg_basebackup', '--pgdata' => $backup2path, '--no-sync', '--checkpoint' => 'fast', '--incremental' => $backup1path . '/backup_manifest' ], "incremental backup"); # Find an incremental file in the incremental backup for which there is a full # file in the full backup. When we find one, replace the full file with an # incremental file. my @filelist = grep { /^INCREMENTAL\./ } slurp_dir("$backup2path/base/1"); my $success = 0; for my $iname (@filelist) { my $name = $iname; $name =~ s/^INCREMENTAL.//; if (-f "$backup1path/base/1/$name") { copy("$backup2path/base/1/$iname", "$backup1path/base/1/$iname") || die "copy $backup2path/base/1/$iname: $!"; unlink("$backup1path/base/1/$name") || die "unlink $backup1path/base/1/$name: $!"; $success = 1; last; } } # pg_combinebackup should fail. my $outpath = $primary->backup_dir . '/out'; $primary->command_fails_like( [ 'pg_combinebackup', $backup1path, $backup2path, '--output' => $outpath, ], qr/full backup contains unexpected incremental file/, "pg_combinebackup fails"); done_testing();