summaryrefslogtreecommitdiffstats
path: root/t/045_backup.t
blob: be09cbb5fe6c5738c92ef0dc7b9a84cf6a3c4920 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
use strict;

use lib 't';
use TestLib;
use PgCommon;

use Test::More;
use Time::HiRes qw/usleep/;

my ($pg_uid, $pg_gid) = (getpwnam 'postgres')[2,3];
my $systemd = (-d "/run/systemd/system" and not $ENV{_SYSTEMCTL_SKIP_REDIRECT});
note $systemd ? "We are running systemd" : "We are not running systemd";

foreach my $v (@MAJORS) {
    if ($v < 9.1) {
        ok 1, "pg_backupcluster not supported on $v";
        next;
    }
    note "PostgreSQL $v";

    note "create cluster";
    program_ok 0, "pg_createcluster --locale en_US.UTF-8 $v main --start";
    like_program_out 0, "pg_lsclusters -h", 0, qr/$v main 5432 online/;
    program_ok 0, "pg_conftool $v main set work_mem 11MB";
    if ($v <= 9.6) {
        open my $hba, ">>", "/etc/postgresql/$v/main/pg_hba.conf";
        print $hba "local replication all peer\n";
        close $hba;
        program_ok 0, "pg_conftool $v main set max_wal_senders 10";
        program_ok 0, "pg_conftool $v main set wal_level archive";
        program_ok 0, "pg_conftool $v main set max_replication_slots 10" if ($v >= 9.4);
        program_ok 0, "pg_conftool $v main set ssl off" if ($v <= 9.1); # cert symlinks not backed up in 9.1
        program_ok 0, "pg_ctlcluster $v main restart";
    }
    program_ok $pg_uid, "createdb -E SQL_ASCII -T template0 mydb";
    program_ok $pg_uid, "psql -c 'alter database mydb set search_path=public'";
    program_ok $pg_uid, "psql -c 'create table foo (t text)' mydb";
    program_ok $pg_uid, "psql -c \"insert into foo values ('data from backup')\" mydb";
    program_ok $pg_uid, "psql -c 'CREATE USER myuser'";
    program_ok $pg_uid, "psql -c 'alter role myuser set search_path=public, myschema'";
    SKIP: { # in PG 10, ARID is part of globals.sql which we try to restore before databases.sql
        skip "alter role in database handling in PG <= 10 not supported", 1 if ($v <= 10);
        program_ok $pg_uid, "psql -c 'alter role myuser in database mydb set search_path=public, myotherschema'";
    }

    note "create directory";
    program_ok 0, "pg_backupcluster $v main createdirectory";
    my $dir = "/var/backups/postgresql/$v-main";
    my @stat = stat $dir;
    is $stat[4], $pg_uid, "$dir owned by uid postgres";
    is $stat[5], $pg_gid, "$dir owned by gid postgres";

    my @backups = ();
    my $dump = '';
    SKIP: {
        skip "dump not supported before 9.3", 1 if ($v < 9.3);
        note "dump";
        if ($systemd) {
            program_ok 0, "systemctl start pg_dump\@$v-main";
        } else {
            program_ok 0, "pg_backupcluster $v main dump";
        }
        ($dump) = glob "$dir/*.dump";
        ok -d $dump, "dump created in $dump";
        @stat = stat $dump;
        is $stat[4], $pg_uid, "$dump owned by uid postgres";
        is $stat[5], $pg_gid, "$dump owned by gid postgres";
        push @backups, $dump;
    }

    note "basebackup";
    my $receivewal_pid;
    if ($v >= 9.5) {
        if ($systemd) {
            program_ok 0, "systemctl start pg_receivewal\@$v-main";
        } else {
            $receivewal_pid = fork;
            if ($receivewal_pid == 0) {
                # suppress "not renaming "000000010000000000000003.gz.partial", segment is not complete"
                exec "pg_backupcluster $v main receivewal 2>/dev/null";
            }
        }
        program_ok $pg_uid, "psql -c 'create table poke_receivewal (t text)' mydb";
        usleep($delay);
        my $wal = "000000010000000000000001";
        $wal .= ".gz" if ($v >= 10);
        $wal .= ".partial";
        TODO: {
        local $TODO = "WAL test is unstable";
        ok_dir "$dir/wal", [$wal], "$dir/wal contains $wal";
        }
    }
    if ($systemd) {
        program_ok 0, "systemctl start pg_basebackup\@$v-main";
    } else {
        program_ok 0, "pg_backupcluster $v main basebackup";
    }
    my ($basebackup) = glob "$dir/*.backup";
    ok -d $basebackup, "dump created in $basebackup";
    @stat = stat $basebackup;
    is $stat[4], $pg_uid, "$basebackup owned by uid postgres";
    is $stat[5], $pg_gid, "$basebackup owned by gid postgres";
    push @backups, $basebackup;

    note "list";
    like_program_out 0, "pg_backupcluster $v main list", 0, qr/$dump.*$basebackup/s;

    note "more database changes";
    program_ok $pg_uid, "psql -c \"insert into foo values ('data later deleted')\" mydb";
    program_ok $pg_uid, "psql -c \"insert into foo values ('data from archive')\" mydb";
    my $timestamp = `su -c "psql -XAtc 'select now()'" postgres`;
    ok $timestamp, "retrieve recovery timestamp";
    program_ok $pg_uid, "psql -c \"delete from foo where t = 'data later deleted'\" mydb";
    usleep($delay);
    if ($v >= 9.5) {
        # since we are stopping pg_receivewal before postgresql, this implicitly tests restoring from .partial WAL files as well
        if ($systemd) {
            program_ok 0, "systemctl stop pg_receivewal\@$v-main";
        } else {
            is kill('INT', $receivewal_pid), 1, "stop receivewal";
        }
    }

    for my $backup (@backups) {
        note "restore $backup";
        program_ok 0, "pg_dropcluster $v main --stop";
        program_ok 0, "pg_restorecluster $v main $backup --start --datadir /var/lib/postgresql/$v/snowflake";
        like_program_out 0, "pg_lsclusters -h", 0, qr/$v main 5432 online postgres .var.lib.postgresql.$v.snowflake/;
        like_program_out $pg_uid, "psql -XAtl", 0, qr%mydb\|postgres\|SQL_ASCII\|en_US.UTF-8\|en_US.UTF-8\|(\|libc\|)?
postgres\|postgres\|UTF8\|en_US.UTF-8\|en_US.UTF-8\|(\|libc\|)?
template0\|postgres\|UTF8\|en_US.UTF-8\|en_US.UTF-8\|(\|libc\|)?=c/postgres
postgres=CTc/postgres
template1\|postgres\|UTF8\|en_US.UTF-8\|en_US.UTF-8\|(\|libc\|)?=c/postgres
postgres=CTc/postgres\n%;
        is_program_out $pg_uid, "psql -XAtc 'show work_mem'", 0, "11MB\n";
        is_program_out $pg_uid, "psql -XAtc 'select * from foo' mydb", 0, "data from backup\n";
        is_program_out $pg_uid, "psql -XAtc \"select analyze_count from pg_stat_user_tables where relname = 'foo'\" mydb", 0,
            ($v >= 9.4 ? "3\n" : "1\n"); # --analyze-in-stages does 3 passes
        SKIP: {
            skip "alter role in database handling in PG <= 10 not supported", 1 if ($v <= 10);
            like_program_out $pg_uid, "psql -XAtc '\\drds'", 0, qr/myuser\|mydb\|search_path=public, myotherschema.*
myuser\|\|search_path=public, myschema.*
\|mydb\|search_path=public.*\n/;
        }
    }

    if ($v >= 9.5) {
        note "restore $basebackup with WAL archive";
        program_ok 0, "pg_dropcluster $v main --stop";
        program_ok 0, "pg_restorecluster $v main $basebackup --start --archive --port 5430";
        like_program_out 0, "pg_lsclusters -h", 0, qr/$v main 5430 online postgres .var.lib.postgresql.$v.main/;
        is_program_out $pg_uid, "psql -XAtc 'select * from foo order by t' mydb", 0, "data from archive\ndata from backup\n";

        note "restore $basebackup with PITR";
        program_ok 0, "pg_dropcluster $v main --stop";
        program_ok 0, "pg_restorecluster $v main $basebackup --start --pitr '$timestamp'";
        like_program_out 0, "pg_lsclusters -h", 0, qr/$v main 5432 online postgres .var.lib.postgresql.$v.main/;
        is_program_out $pg_uid, "psql -XAtc 'select * from foo order by t' mydb", 0, "data from archive\ndata from backup\ndata later deleted\n";
    }

    program_ok 0, "pg_dropcluster $v main --stop";
    check_clean;

} # foreach version

done_testing();

# vim: filetype=perl