#!/usr/bin/env perl
# -*-mode:cperl; indent-tabs-mode: nil-*-

## Test makedelta functionality

use 5.008003;
use strict;
use warnings;
use lib 't','.';
use DBD::Pg;
use Test::More tests => 51;
use BucardoTesting;
my $bct = BucardoTesting->new({ location => 'makedelta' })
    or BAIL_OUT "Creation of BucardoTesting object failed\n";

END { $bct->stop_bucardo if $bct }

ok my $dbhA = $bct->repopulate_cluster('A'), 'Populate cluster A';
ok my $dbhB = $bct->repopulate_cluster('B'), 'Populate cluster B';
ok my $dbhC = $bct->repopulate_cluster('C'), 'Populate cluster C';
ok my $dbhX = $bct->setup_bucardo('A'), 'Set up Bucardo';

END { $_->disconnect for grep { $_ } $dbhA, $dbhB, $dbhC, $dbhX }

# Teach Bucardo about the databases.
for my $db (qw(A B C)) {
    my ($user, $port, $host) = $bct->add_db_args($db);
    like $bct->ctl(
        "bucardo add db $db dbname=bucardo_test user=$user port=$port host=$host"
    ), qr/Added database "$db"/, qq{Add database "$db" to Bucardo};
}

# Let's just deal with table bucardo_test1 (single column primary key)
# and bucardo_test2 (multi-column primary key).
# Create bucardo_test4 with makedelta off.
for my $num (1, 2, 4) {
    my $md = $num == 4 ? 'off' : 'on';
    like $bct->ctl("bucardo add table bucardo_test$num db=A relgroup=myrels makedelta=$md"),
        qr/Added the following tables/, "Add table bucardo_test$num";
}

# Create a sync for multi-master replication between A and B
like $bct->ctl('bucardo add sync deltatest1 relgroup=myrels dbs=A:source,B:source'),
    qr/Added sync "deltatest1"/, 'Create sync "deltatest1"';

# Create a sync for replication from B to C
like $bct->ctl('bucardo add sync deltatest2 relgroup=myrels dbs=B,C autokick=no'),
    qr/Added sync "deltatest2"/, 'Create sync "deltatest2"';

# Create an inactive sync from C to A. This is so makedelta on C tables works
like $bct->ctl('bucardo add sync deltafake relgroup=myrels dbs=C,A status=inactive autokick=no'),
    qr/Added sync "deltafake"/, 'Create sync "deltafake"';

# Listen in on things.
ok $dbhX->do('LISTEN bucardo_syncdone_deltatest1'),
    'Listen for syncdone_deltatest1';
ok $dbhX->do('LISTEN bucardo_syncdone_deltatest2'),
    'Listen for syncdone_deltatest2';
ok $dbhX->do('LISTEN bucardo_syncdone_deltatest3'),
    'Listen for syncdone_deltatest3';

# Start up Bucardo and wait for initial syncs to finish.
ok $bct->restart_bucardo($dbhX), 'Bucardo should start';
ok $bct->wait_for_notice($dbhX, [qw(
    syncdone_deltatest1
)]), 'The deltatest1 sync finished';

# Should have no rows.
$bct->check_for_row([], [qw(A B C)], undef, 'test[124]$');

# Let's add some data into A.bucardo_test1.
ok $dbhA->do(q{INSERT INTO bucardo_test1 (id, data1) VALUES (1, 'foo')}),
    'Insert a row into test1 on A';
$dbhA->commit;

ok $bct->wait_for_notice($dbhX, [qw(
    syncdone_deltatest1
)]), 'The deltatest1 sync has finished';

## Bucardo will not fire off deltatest2 itself, so we kick it
$bct->ctl('bucardo kick sync deltatest2 0');

ok $bct->wait_for_notice($dbhX, [qw(
    syncdone_deltatest2
)]), 'The deltatest2 sync has finished';

# The row should be in A and B, as well as C!
is_deeply $dbhB->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test1'
), [[1, 'foo']], 'Should have the test1 row in B';

is_deeply $dbhC->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test1'
), [[1, 'foo']], 'Second sync moved row from B to C';

# Now let's insert into test2 on B.
# This will cause both syncs to fire
# deltatest1 (A<=>B) will copy the row from B to A
# deltatest2 (B=>C) will copy the row from B to C
ok $dbhB->do(q{INSERT INTO bucardo_test2 (id, data1) VALUES (2, 'foo')}),
    'Insert a row into test2 on B';
$dbhB->commit;

## Sync deltatest2 is not automatic, so we need to kick it
# Kick off the second sync
$bct->ctl('bucardo kick sync deltatest2 0');

ok $bct->wait_for_notice($dbhX, [qw(
    syncdone_deltatest1
    syncdone_deltatest2
)]), 'The deltatest1 and deltatest2 syncs finished';

is_deeply $dbhA->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test2'
), [[2, 'foo']], 'Should have the A test2 row in A';

is_deeply $dbhC->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test2'
), [[2, 'foo']], 'Should have the A test2 row in C';

# Finally, try table 4, which has no makedelta.
ok $dbhA->do(q{INSERT INTO bucardo_test4 (id, data1) VALUES (3, 'foo')}),
    'Insert a row into test4 on A';
$dbhA->commit;

ok $bct->wait_for_notice($dbhX, [qw(
    syncdone_deltatest1
)]), 'The deltatest1 sync finished';

# Kick off the second sync
$bct->ctl('bucardo kick sync deltatest2 0');

is_deeply $dbhB->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test4'
), [[3, 'foo']], 'Should have the test4 row in B';

is_deeply $dbhC->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test4'
), [], 'Should have no test4 row row in C';

$dbhA->commit();
$dbhB->commit();
$dbhC->commit();

##############################################################################
# Okay, what if we have C be a target from either A or B?
like $bct->ctl('bucardo remove sync deltatest2'),
    qr/Removed sync "deltatest2"/, 'Remove sync "deltatest2"';
like $bct->ctl('bucardo add sync deltatest3 relgroup=myrels dbs=A:source,B:source,C'),
   qr/Added sync "deltatest3"/, 'Created sync "deltatest3"';

ok $bct->restart_bucardo($dbhX), 'Bucardo restarted';

ok $dbhA->do(q{INSERT INTO bucardo_test2 (id, data1) VALUES (3, 'howdy')}),
    'Insert a row into test2 on A';
$dbhA->commit;

ok $bct->wait_for_notice($dbhX, [qw(
   syncdone_deltatest1
   syncdone_deltatest3
)]), 'Syncs deltatest1 and deltatest3 finished';

is_deeply $dbhB->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test2'
), [[2, 'foo'], [3, 'howdy']], 'Should have the A test2 row in B';

is_deeply $dbhC->selectall_arrayref(
    'SELECT id, data1 FROM bucardo_test2'
), [[2, 'foo'], [3, 'howdy']], 'Should have the A test2 row in C';

