#!perl
use Cassandane::Tiny;

sub test_reconstruct_orphans
{
    my ($self) = @_;

    xlog $self, "test resources usage calculated when reconstructing an index";
    xlog $self, "with messages disappearing, resulting in orphan annotations";

    $self->_set_quotaroot('user.cassandane');
    my $folder = 'INBOX';
    my $fentry = '/private/comment';
    my $mentry1 = '/comment';
    my $mentry2 = '/altsubject';
    my $mattrib = 'value.priv';

    my $store = $self->{store};
    $store->set_fetch_attributes('uid',
                                 "annotation ($mentry1 $mattrib)",
                                 "annotation ($mentry2 $mattrib)");
    my $talk = $store->get_client();
    my $admintalk = $self->{adminstore}->get_client();

    xlog $self, "set ourselves a basic limit";
    $self->_set_limits(
        storage => 100000,
        message => 50000,
        $self->res_annot_storage => 100000,
    );
    $self->_check_usages(
        storage => 0,
        message => 0,
        $self->res_annot_storage => 0,
    );
    my $expected_annotation_storage = 0;
    my $expected_storage = 0;
    my $expected_message = 0;

    xlog $self, "store annotations";
    my $data = $self->make_random_data(10);
    $expected_annotation_storage += length($data);
    $talk->setmetadata($folder, $fentry, { Quote => $data });
    $self->assert_str_equals('ok', $talk->get_last_completion_response());

    xlog $self, "add some messages";
    my $uid = 1;
    my %exp;
    for (1..10)
    {
        my $msg = $self->make_message("Message $_",
                                      extra_lines => 10 + rand(5000));
        $exp{$uid} = $msg;
        my $data1 = $self->make_random_data(7);
        my $data2 = $self->make_random_data(3);
        $msg->set_attribute('uid', $uid);
        $msg->set_annotation($mentry1, $mattrib, $data1);
        $msg->set_annotation($mentry2, $mattrib, $data2);
        $talk->store('' . $uid, 'annotation',
                    [$mentry1, [$mattrib, { Quote => $data1 }],
                     $mentry2, [$mattrib, { Quote => $data2 }]]);
        $self->assert_str_equals('ok', $talk->get_last_completion_response());
        $expected_annotation_storage += (length($data1) + length($data2));
        $expected_storage += length($msg->as_string());
        $expected_message++;
        $uid++;
    }

    xlog $self, "Check the messages are all there";
    $self->check_messages(\%exp);

    xlog $self, "Check the mailbox annotation is still there";
    my $res = $talk->getmetadata($folder, $fentry);
    $self->assert_str_equals('ok', $talk->get_last_completion_response());
    $self->assert_deep_equals({
        $folder => { $fentry => $data }
    }, $res);

    xlog $self, "Check the quota usage is as expected";
    $self->_check_usages(
        storage => int($expected_storage/1024),
        message => $expected_message,
        $self->res_annot_storage => int($expected_annotation_storage/1024),
    );

    $self->{store}->disconnect();
    $self->{adminstore}->disconnect();
    $talk = undef;
    $admintalk = undef;

    xlog $self, "Moving the cyrus.index file out of the way";
    my $datadir = $self->{instance}->folder_to_directory('user.cassandane');
    my $cyrus_index = "$datadir/cyrus.index";
    $self->assert_file_test($cyrus_index, '-f');
    rename($cyrus_index, $cyrus_index . '.NOT')
        or die "Cannot rename $cyrus_index: $!";

    xlog $self, "Delete a couple of messages";
    foreach $uid (2, 7)
    {
        xlog $self, "Deleting uid $uid";
        unlink("$datadir/$uid.");

        my $msg = delete $exp{$uid};
        my $data1 = $msg->get_annotation($mentry1, $mattrib);
        my $data2 = $msg->get_annotation($mentry2, $mattrib);

        $expected_annotation_storage -= (length($data1) + length($data2));
        $expected_storage -= length($msg->as_string());
        $expected_message--;
    }

    xlog $self, "Running reconstruct";
    $self->{instance}->run_command({ cyrus => 1 },
                                   'reconstruct', 'user.cassandane');
    xlog $self, "Running quota -f";
    $self->{instance}->run_command({ cyrus => 1 },
                                   'quota', '-f', "user.cassandane");

    $talk = $store->get_client();

    xlog $self, "Check the messages are still all there";
    $self->check_messages(\%exp);

    xlog $self, "Check the mailbox annotation is still there";
    $res = $talk->getmetadata($folder, $fentry);
    $self->assert_str_equals('ok', $talk->get_last_completion_response());
    $self->assert_deep_equals({
        $folder => { $fentry => $data }
    }, $res);

    xlog $self, "Check the quota usage is still as expected";
    $self->_check_usages(
        storage => int($expected_storage/1024),
        message => $expected_message,
        $self->res_annot_storage => int($expected_annotation_storage/1024),
    );

    # We should have generated a SYNCERROR or two
    $self->assert_syslog_matches($self->{instance},
                                 qr/IOERROR: opening index/);
}
