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
|
use strict;
use warnings;
use RT::Test tests => undef;
use Test::MockTime qw/set_fixed_time/;
use constant KIDS => 50;
my $id;
{
my $t = RT::Ticket->new( RT->SystemUser );
($id) = $t->Create(
Queue => "General",
Subject => "Race $$",
);
}
diag "Created ticket $id";
RT->DatabaseHandle->Disconnect;
my @kids;
for (1..KIDS) {
if (my $pid = fork()) {
push @kids, $pid;
next;
}
# In the kid, load up the ticket and correspond
RT->ConnectToDatabase;
my $t = RT::Ticket->new( RT->SystemUser );
$t->Load( $id );
$t->Correspond( Content => "Correspondence from PID $$" );
undef $t;
exit 0;
}
diag "Forked @kids";
waitpid $_, 0 for @kids;
diag "All kids finished corresponding";
RT->ConnectToDatabase;
my $t = RT::Ticket->new( RT->SystemUser );
$t->Load($id);
my $txns = $t->Transactions;
$txns->Limit( FIELD => 'Type', VALUE => 'Status' );
is($txns->Count, 1, "Only one transaction change recorded" );
$txns = $t->Transactions;
$txns->Limit( FIELD => 'Type', VALUE => 'Correspond' );
is($txns->Count, KIDS, "But all correspondences were recorded" );
my @users;
for my $n (0..2) {
push @users, RT::Test->load_or_create_user(
Name => "user_$n", Password => 'password',
)->id;
}
ok(RT::Test->add_rights({
Principal => 'Privileged',
Right => 'OwnTicket',
}), "Granted OwnTicket");
for my $round (1..10) {
my ($ok, $msg) = $t->SetOwner($users[0]);
ok $ok, "Set owner back to base";
my $last_txn = $t->Transactions->Last->id;
RT->DatabaseHandle->Disconnect;
diag "Round $round..\n";
@kids = ();
for my $n (1..2) {
if (my $pid = fork()) {
push @kids, $pid;
next;
}
set_fixed_time("2017-01-03T17:17:17Z");
# In the kid, load up the ticket and claim the owner
RT->ConnectToDatabase;
my $t = RT::Ticket->new( RT->SystemUser );
$t->Load( $id );
my ($ok, $msg);
if ($n == 1) {
$RT::Handle->BeginTransaction;
$t->LockForUpdate;
($ok, $msg) = $t->SetOwner( $users[$n] );
undef $t;
$RT::Handle->Commit;
} else {
($ok, $msg) = $t->SetOwner( $users[$n] );
undef $t;
}
exit(1 - $ok);
}
diag "Forked @kids";
for my $pid (@kids) {
waitpid $pid, 0;
my $ret = $? >> 8;
is $ret, 0, "$pid returned $ret";
}
RT->ConnectToDatabase;
# Flush the process-local cache and reload, since the changes
# happened in other processes
DBIx::SearchBuilder::Record::Cachable->FlushCache;
$t->Load( $id );
$txns = $t->Transactions;
$txns->Limit( FIELD => 'id', OPERATOR => '>', VALUE => $last_txn );
$txns->Limit( FIELD => 'Type', VALUE => 'SetWatcher' );
is $txns->Count, 2, "Found two new SetWatcher transactions";
my $winner = $t->Owner;
isnt $winner, $users[0], "Not the base owner";
ok $t->OwnerGroup->HasMember( $winner ), "GroupMembers agrees";
ok $t->OwnerGroup->HasMemberRecursively( $winner ), "CachedGroupMembers agrees";
}
done_testing;
|