[Rt-commit] rt branch, 4.2/optimize-cgm-table, updated. rt-4.0.5-326-gca557da
Ruslan Zakirov
ruz at bestpractical.com
Mon Apr 9 15:51:19 EDT 2012
The branch, 4.2/optimize-cgm-table has been updated
via ca557da50dcfbf84e6a1cfc9f48fe694d59c3abd (commit)
via 81e3392d09be87ed749364087e4685616f82a992 (commit)
via a34ab0ed4a256ef167de14aa0122a7ac79b0d780 (commit)
via 38de6a7355117c359c6f812a106c8ec00c6da783 (commit)
via 4c0e4a2ede4faa0f1a1347426e72a5f6050550d0 (commit)
via d7683c876e25e22e95fa561650ffa5118c4bda7c (commit)
via bc39464fa10ca05952bcd6f23296eeb910998f99 (commit)
via 9a64ee74a37caff1d489be9f68b0e1ed56c55e2a (commit)
via f4883e6f44743eca731eadf75b285faffc8f02dd (commit)
via ffdb4d8e6d7a8d64ec2e3e953740140d6036ee86 (commit)
via ffad239b618f0a4e9bce9f3307ace89e86672bad (commit)
via 38252bdafe1431b026a1a057aee826da52fddd07 (commit)
via af82e29208bbaeca18e1046f92b6c03ba102f4b7 (commit)
via 761e3b09fb14c57b3b55bbba7366686da942b7cc (commit)
from 2441affbf34ff22d24324948b7e35be8f0c2b8c1 (commit)
Summary of changes:
lib/RT/Shredder.pm | 7 +-
lib/RT/Shredder/CachedGroupMember.pm | 83 ++++++---
lib/RT/Shredder/GroupMember.pm | 12 +-
lib/RT/Shredder/Record.pm | 11 +-
lib/RT/Test.pm | 38 ++++
t/shredder/utils.pl => lib/RT/Test/Shredder.pm | 202 ++++++---------------
sbin/rt-validator.in | 233 +++++++++++++++++++-----
t/shredder/00load.t | 10 +-
t/shredder/00skeleton.t | 18 +--
t/shredder/01basics.t | 20 +--
t/shredder/01ticket.t | 42 ++---
t/shredder/02group_member.t | 34 ++--
t/shredder/02queue.t | 51 +++---
t/shredder/02template.t | 33 ++--
t/shredder/02user.t | 30 ++--
t/shredder/03plugin.t | 10 +-
t/shredder/03plugin_summary.t | 11 +-
t/shredder/03plugin_tickets.t | 30 ++--
t/shredder/03plugin_users.t | 10 +-
t/validator/group_members.t | 62 ++-----
20 files changed, 475 insertions(+), 472 deletions(-)
rename t/shredder/utils.pl => lib/RT/Test/Shredder.pm (55%)
- Log -----------------------------------------------------------------
commit 761e3b09fb14c57b3b55bbba7366686da942b7cc
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Mar 28 23:56:50 2012 +0400
we don't have rights delegations anymore
diff --git a/lib/RT/Shredder/GroupMember.pm b/lib/RT/Shredder/GroupMember.pm
index 5f06fae..f43a0be 100644
--- a/lib/RT/Shredder/GroupMember.pm
+++ b/lib/RT/Shredder/GroupMember.pm
@@ -75,8 +75,6 @@ sub __DependsOn
$objs->Limit( FIELD => 'ImmediateParentId', VALUE => $self->GroupId );
push( @$list, $objs );
- # XXX: right delegations should be cleaned here
-
$deps->_PushDependencies(
BaseObject => $self,
Flags => DEPENDS_ON,
commit af82e29208bbaeca18e1046f92b6c03ba102f4b7
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Mar 29 15:49:32 2012 +0400
move run_validator into RT::Test
diff --git a/lib/RT/Test.pm b/lib/RT/Test.pm
index 50188e9..276ad67 100644
--- a/lib/RT/Test.pm
+++ b/lib/RT/Test.pm
@@ -1075,6 +1075,43 @@ sub clean_caught_mails {
unlink $tmp{'mailbox'};
}
+my $validator_path = "$RT::SbinPath/rt-validator";
+sub run_validator {
+ my $self = shift;
+ my %args = (check => 1, resolve => 0, force => 1, @_ );
+
+ my $cmd = $validator_path;
+ die "Couldn't find $cmd command" unless -f $cmd;
+
+ while( my ($k,$v) = each %args ) {
+ next unless $v;
+ $cmd .= " --$k '$v'";
+ }
+ $cmd .= ' 2>&1';
+
+ require IPC::Open2;
+ my ($child_out, $child_in);
+ my $pid = IPC::Open2::open2($child_out, $child_in, $cmd);
+ close $child_in;
+
+ my $result = do { local $/; <$child_out> };
+ close $child_out;
+ waitpid $pid, 0;
+
+ DBIx::SearchBuilder::Record::Cachable->FlushCache
+ if $args{'resolve'};
+
+ return ($?, $result);
+}
+
+sub db_is_valid {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my $self = shift;
+ my ($ecode, $res) = $self->run_validator;
+ Test::More::is( $res, '', 'no invalid records' );
+}
+
=head2 get_relocatable_dir
Takes a path relative to the location of the test file that is being
diff --git a/t/validator/group_members.t b/t/validator/group_members.t
index 6e08831..1ceb214 100644
--- a/t/validator/group_members.t
+++ b/t/validator/group_members.t
@@ -35,45 +35,13 @@ sub load_or_create_group {
return $group;
}
-my $validator_path = "$RT::SbinPath/rt-validator";
-sub run_validator {
- my %args = (check => 1, resolve => 0, force => 1, @_ );
-
- my $cmd = $validator_path;
- die "Couldn't find $cmd command" unless -f $cmd;
-
- while( my ($k,$v) = each %args ) {
- next unless $v;
- $cmd .= " --$k '$v'";
- }
- $cmd .= ' 2>&1';
-
- require IPC::Open2;
- my ($child_out, $child_in);
- my $pid = IPC::Open2::open2($child_out, $child_in, $cmd);
- close $child_in;
-
- my $result = do { local $/; <$child_out> };
- close $child_out;
- waitpid $pid, 0;
-
- DBIx::SearchBuilder::Record::Cachable->FlushCache
- if $args{'resolve'};
-
- return ($?, $result);
-}
-
-{
- my ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
-}
+RT::Test->db_is_valid;
{
my $group = load_or_create_group('test', Members => [] );
ok $group, "loaded or created a group";
- my ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
}
# G1 -> G2
@@ -87,20 +55,18 @@ sub run_validator {
ok $group2->HasMember( $group1->id ), "has member";
ok $group2->HasMemberRecursively( $group1->id ), "has member";
- my ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
$RT::Handle->dbh->do("DELETE FROM CachedGroupMembers");
DBIx::SearchBuilder::Record::Cachable->FlushCache;
ok !$group2->HasMemberRecursively( $group1->id ), "has no member, broken DB";
- ($ecode, $res) = run_validator(resolve => 1);
+ my ($ecode, $res) = RT::Test->run_validator(resolve => 1);
ok $group2->HasMember( $group1->id ), "has member";
ok $group2->HasMemberRecursively( $group1->id ), "has member";
- ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
}
# G1 <- G2 <- G3 <- G4 <- G5
@@ -120,15 +86,14 @@ sub run_validator {
push @groups, $group;
}
- my ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
$RT::Handle->dbh->do("DELETE FROM CachedGroupMembers");
DBIx::SearchBuilder::Record::Cachable->FlushCache;
ok !$groups[1]->HasMemberRecursively( $groups[0]->id ), "has no member, broken DB";
- ($ecode, $res) = run_validator(resolve => 1);
+ my ($ecode, $res) = RT::Test->run_validator(resolve => 1);
for ( my $i = 1; $i < @groups; $i++ ) {
ok $groups[$i]->HasMember( $groups[$i-1]->id ),
@@ -138,8 +103,7 @@ sub run_validator {
foreach 0..$i-1;
}
- ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
}
# G1 <- (G2, G3, G4, G5)
@@ -154,8 +118,7 @@ sub run_validator {
my $parent = load_or_create_group( 'test1', Members => \@groups );
ok $parent, "loaded or created a group";
- my ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
}
# G1 <- (G2, G3, G4) <- G5
@@ -173,7 +136,6 @@ sub run_validator {
my $parent = load_or_create_group( 'test1', Members => \@groups );
ok $parent, "loaded or created a group";
- my ($ecode, $res) = run_validator();
- is $res, '', 'empty result';
+ RT::Test->db_is_valid;
}
commit 38252bdafe1431b026a1a057aee826da52fddd07
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Tue Apr 3 22:23:10 2012 +0400
make sure validator exits with meaningful exit code
diff --git a/sbin/rt-validator.in b/sbin/rt-validator.in
index ba6d6f3..be8a2d5 100644
--- a/sbin/rt-validator.in
+++ b/sbin/rt-validator.in
@@ -81,7 +81,7 @@ GetOptions(
if ( $opt{help} || !$opt{check} ) {
require Pod::Usage;
print Pod::Usage::pod2usage( { verbose => 2 } );
- exit;
+ exit 2;
}
usage_warning() if $opt{'resolve'} && !$opt{'force'};
@@ -208,7 +208,7 @@ foreach my $table ( qw(Users Groups) ) {
." The script can either create the missing record in Principals"
." or delete the record in $table.";
my ($type) = ($table =~ /^(.*)s$/);
- check_integrity(
+ return check_integrity(
$table, 'id' => 'Principals', 'id',
join_condition => 't.PrincipalType = ?',
bind_values => [ $type ],
@@ -236,7 +236,7 @@ foreach my $table ( qw(Users Groups) ) {
." In some cases it's possible to manually resurrect such records,"
." but this utility can only delete records.";
- check_integrity(
+ return check_integrity(
'Principals', 'id' => $table, 'id',
condition => 's.PrincipalType = ?',
bind_values => [ $table =~ /^(.*)s$/ ],
@@ -251,8 +251,9 @@ foreach my $table ( qw(Users Groups) ) {
}
push @CHECKS, 'User <-> ACL equivalence group' => sub {
+ my $res = 1;
# from user to group
- check_integrity(
+ $res *= check_integrity(
'Users', 'id' => 'Groups', 'Instance',
join_condition => 't.Domain = ? AND t.Type = ?',
bind_values => [ 'ACLEquivalence', 'UserEquiv' ],
@@ -268,7 +269,7 @@ push @CHECKS, 'User <-> ACL equivalence group' => sub {
},
);
# from group to user
- check_integrity(
+ $res *= check_integrity(
'Groups', 'Instance' => 'Users', 'id',
condition => 's.Domain = ? AND s.Type = ?',
bind_values => [ 'ACLEquivalence', 'UserEquiv' ],
@@ -282,25 +283,27 @@ push @CHECKS, 'User <-> ACL equivalence group' => sub {
},
);
# one ACL equiv group for each user
- check_uniqueness(
+ $res *= check_uniqueness(
'Groups',
columns => ['Instance'],
condition => '.Domain = ? AND .Type = ?',
bind_values => [ 'ACLEquivalence', 'UserEquiv' ],
);
+ return $res;
};
# check integrity of Queue role groups
push @CHECKS, 'Queues <-> Role Groups' => sub {
# XXX: we check only that there is at least one group for a queue
# from queue to group
- check_integrity(
+ my $res = 1;
+ $res *= check_integrity(
'Queues', 'id' => 'Groups', 'Instance',
join_condition => 't.Domain = ?',
bind_values => [ 'RT::Queue-Role' ],
);
# from group to queue
- check_integrity(
+ $res *= check_integrity(
'Groups', 'Instance' => 'Queues', 'id',
condition => 's.Domain = ?',
bind_values => [ 'RT::Queue-Role' ],
@@ -313,19 +316,21 @@ push @CHECKS, 'Queues <-> Role Groups' => sub {
delete_record( 'Groups', $id );
},
);
+ return $res;
};
# check integrity of Ticket role groups
push @CHECKS, 'Tickets <-> Role Groups' => sub {
# XXX: we check only that there is at least one group for a queue
# from queue to group
- check_integrity(
+ my $res = 1;
+ $res *= check_integrity(
'Tickets', 'id' => 'Groups', 'Instance',
join_condition => 't.Domain = ?',
bind_values => [ 'RT::Ticket-Role' ],
);
# from group to ticket
- check_integrity(
+ $res *= check_integrity(
'Groups', 'Instance' => 'Tickets', 'id',
condition => 's.Domain = ?',
bind_values => [ 'RT::Ticket-Role' ],
@@ -338,12 +343,13 @@ push @CHECKS, 'Tickets <-> Role Groups' => sub {
delete_record( 'Groups', $id );
},
);
+ return $res;
};
# additional CHECKS on groups
push @CHECKS, 'Role Groups (Instance, Type) uniqueness' => sub {
# Check that Domain, Instance and Type are unique
- check_uniqueness(
+ return check_uniqueness(
'Groups',
columns => ['Domain', 'Instance', 'Type'],
condition => '.Domain LIKE ?',
@@ -352,7 +358,7 @@ push @CHECKS, 'Role Groups (Instance, Type) uniqueness' => sub {
};
push @CHECKS, 'System internal group uniqueness' => sub {
- check_uniqueness(
+ return check_uniqueness(
'Groups',
columns => ['Instance', 'Type'],
condition => '.Domain = ?',
@@ -362,7 +368,7 @@ push @CHECKS, 'System internal group uniqueness' => sub {
# CHECK that user defined group names are unique
push @CHECKS, 'User Defined Group Name uniqueness' => sub {
- check_uniqueness(
+ return check_uniqueness(
'Groups',
columns => ['Name'],
condition => '.Domain = ?',
@@ -386,7 +392,8 @@ push @CHECKS, 'GMs -> Groups, Members' => sub {
my $msg = "A record in GroupMembers references an object that doesn't exist."
." Maybe you deleted a group or principal directly from the database?"
." Usually it's OK to delete such records.";
- check_integrity(
+ my $res = 1;
+ $res *= check_integrity(
'GroupMembers', 'GroupId' => 'Groups', 'id',
action => sub {
my $id = shift;
@@ -395,7 +402,7 @@ push @CHECKS, 'GMs -> Groups, Members' => sub {
delete_record( 'GroupMembers', $id );
},
);
- check_integrity(
+ $res *= check_integrity(
'GroupMembers', 'MemberId' => 'Principals', 'id',
action => sub {
my $id = shift;
@@ -404,12 +411,14 @@ push @CHECKS, 'GMs -> Groups, Members' => sub {
delete_record( 'GroupMembers', $id );
},
);
+ return $res;
};
# CGM and GM
push @CHECKS, 'CGM vs. GM' => sub {
+ my $res = 1;
# all GM record should be duplicated in CGM
- check_integrity(
+ $res *= check_integrity(
GroupMembers => ['GroupId', 'MemberId'],
CachedGroupMembers => ['GroupId', 'MemberId'],
action => sub {
@@ -429,7 +438,7 @@ push @CHECKS, 'CGM vs. GM' => sub {
);
# each group should have a CGM record where MemberId == GroupId
- check_integrity(
+ $res *= check_integrity(
Groups => ['id', 'id'],
CachedGroupMembers => ['GroupId', 'MemberId'],
action => sub {
@@ -445,13 +454,13 @@ push @CHECKS, 'CGM vs. GM' => sub {
die "Couldn't load group #$id" unless $g->id;
die "Loaded group by $id has id ". $g->id unless $g->id == $id;
my $cgm = create_record( 'CachedGroupMembers',
- GroupId => $id, MemberId => $id,
+ GroupId => $id, MemberId => $id, Disabled => 0,
);
},
);
# and back, each record in CGM with MemberId == GroupId without exceptions
# should reference a group
- check_integrity(
+ $res *= check_integrity(
CachedGroupMembers => ['GroupId', 'MemberId'],
Groups => ['id', 'id'],
condition => "s.GroupId = s.MemberId",
@@ -494,6 +503,7 @@ END
my $sth = execute_query( $query );
while ( my ($id) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "CGM #$id has no corresponding record in GM or pair in CGM table\n";
next unless prompt(
'Delete',
@@ -521,6 +531,7 @@ WHERE
END
my $sth = execute_query( $query );
while ( my ($g, $m, $d) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "CGM table has no record ($g, $m), but ($g -> X -> $m) pair exist in CGM\n";
next unless prompt(
'Create',
@@ -531,12 +542,14 @@ END
);
}
}
+ return $res;
};
# Disabled in CGM
push @CHECKS, 'Disabled in CGM' => sub {
+ my $res = 1;
# make sure every disabled group forms disabled CGM records
- check_integrity(
+ $res *= check_integrity(
Principals => ['id'],
CachedGroupMembers => ['GroupId'],
condition => "s.PrincipalType = ? AND s.Disabled != 0",
@@ -553,7 +566,7 @@ push @CHECKS, 'Disabled in CGM' => sub {
},
);
# make sure every enabled group has enabled (G,G) record in CGM
- check_integrity(
+ $res *= check_integrity(
Principals => ['id', 'id'],
CachedGroupMembers => ['GroupId', 'MemberId'],
condition => "s.PrincipalType = ? AND s.Disabled = 0",
@@ -585,6 +598,7 @@ WHERE p.id = GM.GroupId
END
my $sth = execute_query( $query );
while ( my ($g, $m) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "CGM ($g, $m) is not active while it should be\n";
next unless prompt(
'Update',
@@ -599,11 +613,14 @@ END
# now time to deal with indirect CGM records
# TODO.
+
+ return $res;
};
# Tickets
push @CHECKS, 'Tickets -> other' => sub {
- check_integrity(
+ my $res = 1;
+ $res *= check_integrity(
'Tickets', 'EffectiveId' => 'Tickets', 'id',
action => sub {
my $id = shift;
@@ -615,19 +632,21 @@ push @CHECKS, 'Tickets -> other' => sub {
delete_record( 'Tickets', $id );
},
);
- check_integrity(
+ $res *= check_integrity(
'Tickets', 'Queue' => 'Queues', 'id',
);
- check_integrity(
+ $res *= check_integrity(
'Tickets', 'Owner' => 'Users', 'id',
);
# XXX: check that owner is only member of owner role group
+ return $res;
};
push @CHECKS, 'Transactions -> other' => sub {
+ my $res = 1;
foreach my $model ( @models ) {
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'ObjectId' => m2t($model), 'id',
condition => 's.ObjectType = ?',
bind_values => [ "RT::$model" ],
@@ -642,13 +661,13 @@ push @CHECKS, 'Transactions -> other' => sub {
);
}
# type = CustomField
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'Field' => 'CustomFields', 'id',
condition => 's.Type = ?',
bind_values => [ 'CustomField' ],
);
# type = Take, Untake, Force, Steal or Give
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'OldValue' => 'Users', 'id',
condition => 's.Type IN (?, ?, ?, ?, ?)',
bind_values => [ qw(Take Untake Force Steal Give) ],
@@ -662,7 +681,7 @@ push @CHECKS, 'Transactions -> other' => sub {
delete_record( 'Transactions', $id );
},
);
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'NewValue' => 'Users', 'id',
condition => 's.Type IN (?, ?, ?, ?, ?)',
bind_values => [ qw(Take Untake Force Steal Give) ],
@@ -677,7 +696,7 @@ push @CHECKS, 'Transactions -> other' => sub {
},
);
# type = DelWatcher
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'OldValue' => 'Principals', 'id',
condition => 's.Type = ?',
bind_values => [ 'DelWatcher' ],
@@ -692,7 +711,7 @@ push @CHECKS, 'Transactions -> other' => sub {
},
);
# type = AddWatcher
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'NewValue' => 'Principals', 'id',
condition => 's.Type = ?',
bind_values => [ 'AddWatcher' ],
@@ -711,7 +730,7 @@ push @CHECKS, 'Transactions -> other' => sub {
# handled in 'Links: *' checks as {New,Old}Value store URIs
# type = Set, Field = Queue
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'NewValue' => 'Queues', 'id',
condition => 's.Type = ? AND s.Field = ?',
bind_values => [ 'Set', 'Queue' ],
@@ -725,7 +744,7 @@ push @CHECKS, 'Transactions -> other' => sub {
delete_record( 'Transactions', $id );
},
);
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'OldValue' => 'Queues', 'id',
condition => 's.Type = ? AND s.Field = ?',
bind_values => [ 'Set', 'Queue' ],
@@ -740,17 +759,19 @@ push @CHECKS, 'Transactions -> other' => sub {
},
);
# Reminders
- check_integrity(
+ $res *= check_integrity(
'Transactions', 'NewValue' => 'Tickets', 'id',
join_condition => 't.Type = ?',
condition => 's.Type IN (?, ?, ?)',
bind_values => [ 'reminder', 'AddReminder', 'OpenReminder', 'ResolveReminder' ],
);
+ return $res;
};
# Attachments
push @CHECKS, 'Attachments -> other' => sub {
- check_integrity(
+ my $res = 1;
+ $res *= check_integrity(
Attachments => 'TransactionId', Transactions => 'id',
action => sub {
my $id = shift;
@@ -760,7 +781,7 @@ push @CHECKS, 'Attachments -> other' => sub {
delete_record( 'Attachments', $id );
},
);
- check_integrity(
+ $res *= check_integrity(
Attachments => 'Parent', Attachments => 'id',
action => sub {
my $id = shift;
@@ -770,64 +791,72 @@ push @CHECKS, 'Attachments -> other' => sub {
delete_record( 'Attachments', $id );
},
);
- check_integrity(
+ $res *= check_integrity(
Attachments => 'Parent',
Attachments => 'id',
join_condition => 's.TransactionId = t.TransactionId',
);
+ return $res;
};
push @CHECKS, 'CustomFields and friends' => sub {
+ my $res = 1;
#XXX: ObjectCustomFields needs more love
- check_integrity(
+ $res *= check_integrity(
'CustomFieldValues', 'CustomField' => 'CustomFields', 'id',
);
- check_integrity(
+ $res *= check_integrity(
'ObjectCustomFieldValues', 'CustomField' => 'CustomFields', 'id',
);
foreach my $model ( @models ) {
- check_integrity(
+ $res *= check_integrity(
'ObjectCustomFieldValues', 'ObjectId' => m2t($model), 'id',
condition => 's.ObjectType = ?',
bind_values => [ "RT::$model" ],
);
}
+ return $res;
};
push @CHECKS, Templates => sub {
- check_integrity(
+ return check_integrity(
'Templates', 'Queue' => 'Queues', 'id',
);
};
push @CHECKS, Scrips => sub {
- check_integrity(
+ my $res = 1;
+ $res *= check_integrity(
'Scrips', 'Queue' => 'Queues', 'id',
);
- check_integrity(
+ $res *= check_integrity(
'Scrips', 'ScripCondition' => 'ScripConditions', 'id',
);
- check_integrity(
+ $res *= check_integrity(
'Scrips', 'ScripAction' => 'ScripActions', 'id',
);
- check_integrity(
+ $res *= check_integrity(
'Scrips', 'Template' => 'Templates', 'id',
);
+ return $res;
};
push @CHECKS, Attributes => sub {
+ my $res = 1;
foreach my $model ( @models ) {
- check_integrity(
+ $res *= check_integrity(
'Attributes', 'ObjectId' => m2t($model), 'id',
condition => 's.ObjectType = ?',
bind_values => [ "RT::$model" ],
);
}
+ return $res;
};
# Fix situations when Creator or LastUpdatedBy references ACL equivalence
# group of a user instead of user
push @CHECKS, 'FIX: LastUpdatedBy and Creator' => sub {
+ my $res = 1;
my %fix = ();
foreach my $model ( @models ) {
my $class = "RT::$model";
@@ -857,6 +886,7 @@ END
my $sth = execute_query( $query, 'ACLEquivalence', 'UserEquiv' );
while ( my ($rid, $gid, $uid) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "Record #$rid in $table refers to ACL equivalence group #$gid of user #$uid";
print STDERR " when must reference user.\n";
$action->( $gid, $uid );
@@ -879,16 +909,18 @@ END
}
$redo_check{'FIX: LastUpdatedBy and Creator'} = 1;
}
+ return $res;
};
push @CHECKS, 'LastUpdatedBy and Creator' => sub {
+ my $res = 1;
foreach my $model ( @models ) {
my $class = "RT::$model";
my $object = $class->new( RT->SystemUser );
my $table = $object->Table;
foreach my $column ( qw(LastUpdatedBy Creator) ) {
next unless $object->_Accessible( $column, 'auto' );
- check_integrity(
+ $res *= check_integrity(
$table, $column => 'Users', 'id',
action => sub {
my ($id, %prop) = @_;
@@ -906,9 +938,11 @@ push @CHECKS, 'LastUpdatedBy and Creator' => sub {
);
}
}
+ return $res;
};
push @CHECKS, 'Links: wrong organization' => sub {
+ my $res = 1;
my @URI_USES = (
{ model => 'Transaction', column => 'OldValue', Additional => { Type => 'DeleteLink' } },
{ model => 'Transaction', column => 'NewValue', Additional => { Type => 'AddLink' } },
@@ -934,6 +968,7 @@ push @CHECKS, 'Links: wrong organization' => sub {
}
my $sth = execute_query( $query, @binds );
while ( my ($id, $value) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "Record #$id in $table. Value of $column column most probably is an incorrect link\n";
my ($wrong_org) = ( $value =~ m{^\Q$scheme\E://(.+)/[^/]+/[0-9]*$} );
next unless my $replace_with = prompt(
@@ -957,9 +992,11 @@ push @CHECKS, 'Links: wrong organization' => sub {
last; # plenty of chances we covered all cases with one update
}
}
+ return $res;
};
push @CHECKS, 'Links: LocalX for non-ticket' => sub {
+ my $res = 1;
my $rt_uri = RT::URI::fsck_com_rt->new( $RT::SystemUser );
my $scheme = $rt_uri->Scheme;
my $prefix = $rt_uri->LocalURIPrefix;
@@ -973,6 +1010,7 @@ push @CHECKS, 'Links: LocalX for non-ticket' => sub {
my $sth = execute_query( "SELECT id FROM $table WHERE $where", @binds );
while ( my ($id, $value) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "Record #$id in $table. Value of Local$dir is not 0\n";
next unless my $replace_with = prompt(
'Replace',
@@ -987,9 +1025,11 @@ push @CHECKS, 'Links: LocalX for non-ticket' => sub {
last; # we covered all cases with one update
}
}
+ return $res;
};
push @CHECKS, 'Links: LocalX != X' => sub {
+ my $res = 1;
my $rt_uri = RT::URI::fsck_com_rt->new( $RT::SystemUser );
my $scheme = $rt_uri->Scheme;
my $prefix = $rt_uri->LocalURIPrefix .'/ticket/';
@@ -1006,6 +1046,7 @@ push @CHECKS, 'Links: LocalX != X' => sub {
my $sth = execute_query( "SELECT id FROM $table WHERE $where", @binds );
while ( my ($id, $value) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "Record #$id in $table. Value of $dir doesn't match ticket id in Local$dir\n";
next unless my $replace_with = prompt(
'Replace',
@@ -1022,9 +1063,11 @@ push @CHECKS, 'Links: LocalX != X' => sub {
last; # we covered all cases with one update
}
}
+ return $res;
};
push @CHECKS, 'Links: missing object' => sub {
+ my $res = 1;
my @URI_USES = (
{ model => 'Transaction', column => 'OldValue', Additional => { Type => 'DeleteLink' } },
{ model => 'Transaction', column => 'NewValue', Additional => { Type => 'AddLink' } },
@@ -1058,6 +1101,7 @@ push @CHECKS, 'Links: missing object' => sub {
my $sth = execute_query( $query, @binds );
while ( my ($sid) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "Link in $scolumn column in record #$sid in $stable table points"
." to not existing object.\n";
next unless prompt(
@@ -1072,6 +1116,7 @@ push @CHECKS, 'Links: missing object' => sub {
}
}
}
+ return $res;
};
@@ -1083,8 +1128,9 @@ if ($opt{'links-only'}) {
@do_check = grep { /^Links:/ } @do_check;
}
+my $status = 1;
while ( my $check = shift @do_check ) {
- $CHECKS{ $check }->();
+ $status *= $CHECKS{ $check }->();
foreach my $redo ( keys %redo_check ) {
die "check $redo doesn't exist" unless $CHECKS{ $redo };
@@ -1093,6 +1139,8 @@ while ( my $check = shift @do_check ) {
push @do_check, $redo;
}
}
+exit 1 unless $status;
+exit 0;
sub check_integrity {
my ($stable, @scols) = (shift, shift);
@@ -1128,8 +1176,12 @@ sub check_integrity {
push @binds, 0;
}
+ my $res = 1;
+
my $sth = execute_query( $query, @binds );
while ( my ($sid, @set) = $sth->fetchrow_array ) {
+ $res = 0;
+
print STDERR "Record #$sid in $stable references a nonexistent record in $ttable\n";
for ( my $i = 0; $i < @scols; $i++ ) {
print STDERR "\t$scols[$i] => '$set[$i]' => $tcols[$i]\n";
@@ -1138,6 +1190,7 @@ sub check_integrity {
$args{'action'}->( $sid, map { $scols[$_] => $set[$_] } (0 .. (@scols-1)) )
if $args{'action'};
}
+ return $res;
}
sub describe {
@@ -1197,13 +1250,16 @@ sub check_uniqueness {
$args{'bind_values'}? (@{ $args{'bind_values'} }, @{ $args{'bind_values'} }): (),
$args{'extra_values'}? (@{ $args{'extra_values'} }): ()
);
+ my $res = 1;
while ( my ($sid, $tid, @set) = $sth->fetchrow_array ) {
+ $res = 0;
print STDERR "Record #$tid in $on has the same set of values as $sid\n";
for ( my $i = 0; $i < @columns; $i++ ) {
print STDERR "\t$columns[$i] => '$set[$i]'\n";
}
$args{'action'}->( $tid, map { $columns[$_] => $set[$_] } (0 .. (@columns-1)) ) if $args{'action'};
}
+ return $res;
}
sub load_record {
commit ffad239b618f0a4e9bce9f3307ace89e86672bad
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Apr 6 00:25:41 2012 +0400
complete validation and fixing Disabled column in CGM
diff --git a/sbin/rt-validator.in b/sbin/rt-validator.in
index be8a2d5..452fab5 100644
--- a/sbin/rt-validator.in
+++ b/sbin/rt-validator.in
@@ -548,7 +548,7 @@ END
# Disabled in CGM
push @CHECKS, 'Disabled in CGM' => sub {
my $res = 1;
- # make sure every disabled group forms disabled CGM records
+ # make sure every disabled group forms only disabled CGM records
$res *= check_integrity(
Principals => ['id'],
CachedGroupMembers => ['GroupId'],
@@ -611,9 +611,86 @@ END
}
}
- # now time to deal with indirect CGM records
- # TODO.
+ # make sure every active CGM that is not real GM has
+ # active joint
+ {
+ my $query = <<END;
+SELECT CGM.GroupId, CGM.MemberId
+FROM CachedGroupMembers CGM
+WHERE CGM.Disabled = 0
+ AND CGM.GroupId != CGM.MemberId
+ AND NOT EXISTS (
+ SELECT 1 FROM GroupMembers GM
+ WHERE GM.GroupId = CGM.GroupId
+ AND GM.MemberId = CGM.MemberId
+ )
+ AND NOT EXISTS (
+ SELECT 1 FROM CachedGroupMembers CGML, CachedGroupMembers CGMR
+ WHERE
+ CGML.GroupId = CGM.GroupId
+ AND CGML.MemberId = CGMR.GroupId
+ AND CGMR.MemberId = CGM.MemberId
+
+ AND CGML.Disabled = 0
+ AND CGMR.Disabled = 0
+ AND CGML.GroupId != CGML.MemberId
+ AND CGMR.GroupId != CGMR.MemberId
+ )
+END
+ my $sth = execute_query( $query );
+ while ( my ($g, $m) = $sth->fetchrow_array ) {
+ $res = 0;
+ print STDERR "CGM ($g, $m) is active while it should not be\n";
+ next unless prompt(
+ 'Update',
+ "Active records in CachedGroupMembers."
+ );
+ update_records('CachedGroupMembers',
+ { GroupId => $g, MemberId => $m },
+ { Disabled => 1 }
+ );
+ }
+ }
+
+ # escape if we had problems
+ return $res unless $res;
+
+ # make sure every inactive CGM don't have active joint
+ {
+ my $query = <<END;
+SELECT CGM.GroupId, CGM.MemberId
+FROM CachedGroupMembers CGM
+WHERE CGM.Disabled != 0
+ AND CGM.GroupId != CGM.MemberId
+ AND EXISTS (
+ SELECT 1 FROM CachedGroupMembers CGML, CachedGroupMembers CGMR
+ WHERE
+ CGML.GroupId = CGM.GroupId
+ AND CGML.MemberId = CGMR.GroupId
+ AND CGMR.MemberId = CGM.MemberId
+
+ AND CGML.Disabled = 0
+ AND CGMR.Disabled = 0
+
+ AND CGML.GroupId != CGML.MemberId
+ AND CGMR.GroupId != CGMR.MemberId
+ )
+END
+ my $sth = execute_query( $query );
+ while ( my ($g, $m) = $sth->fetchrow_array ) {
+ $res = 0;
+ print STDERR "CGM ($g, $m) is not active while it should be\n";
+ next unless prompt(
+ 'Update',
+ "Inactive records in CachedGroupMembers."
+ );
+ update_records('CachedGroupMembers',
+ { GroupId => $g, MemberId => $m },
+ { Disabled => 0 }
+ );
+ }
+ }
return $res;
};
commit ffdb4d8e6d7a8d64ec2e3e953740140d6036ee86
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Apr 6 00:27:44 2012 +0400
print validation errors if any
diff --git a/lib/RT/Test.pm b/lib/RT/Test.pm
index 276ad67..9f876b2 100644
--- a/lib/RT/Test.pm
+++ b/lib/RT/Test.pm
@@ -1109,7 +1109,8 @@ sub db_is_valid {
my $self = shift;
my ($ecode, $res) = $self->run_validator;
- Test::More::is( $res, '', 'no invalid records' );
+ Test::More::is( $ecode, 0, 'no invalid records' )
+ or Test::More::diag "errors:\n$res";
}
=head2 get_relocatable_dir
commit f4883e6f44743eca731eadf75b285faffc8f02dd
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Apr 6 00:29:57 2012 +0400
check exit code when we expect DB to be invalid
diff --git a/t/validator/group_members.t b/t/validator/group_members.t
index 1ceb214..237d9b5 100644
--- a/t/validator/group_members.t
+++ b/t/validator/group_members.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 60;
+use RT::Test tests => 62;
sub load_or_create_group {
my $name = shift;
@@ -62,6 +62,7 @@ RT::Test->db_is_valid;
ok !$group2->HasMemberRecursively( $group1->id ), "has no member, broken DB";
my ($ecode, $res) = RT::Test->run_validator(resolve => 1);
+ isnt($ecode, 0, 'non-zero exit code');
ok $group2->HasMember( $group1->id ), "has member";
ok $group2->HasMemberRecursively( $group1->id ), "has member";
@@ -94,6 +95,7 @@ RT::Test->db_is_valid;
ok !$groups[1]->HasMemberRecursively( $groups[0]->id ), "has no member, broken DB";
my ($ecode, $res) = RT::Test->run_validator(resolve => 1);
+ isnt($ecode, 0, 'non-zero exit code');
for ( my $i = 1; $i < @groups; $i++ ) {
ok $groups[$i]->HasMember( $groups[$i-1]->id ),
commit bc39464fa10ca05952bcd6f23296eeb910998f99
Merge: f4883e6 9a64ee7
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Apr 6 21:49:58 2012 +0400
Merge branch '4.2/test-shredder-pm' into 4.2/optimize-cgm-table
commit d7683c876e25e22e95fa561650ffa5118c4bda7c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon Apr 9 18:45:49 2012 +0400
validate database in tests after each wipeout
diff --git a/t/shredder/01basics.t b/t/shredder/01basics.t
index aea4e49..368c9ba 100644
--- a/t/shredder/01basics.t
+++ b/t/shredder/01basics.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 3;
+use RT::Test::Shredder tests => 4;
my $test = "RT::Test::Shredder";
$test->create_savepoint();
@@ -20,4 +20,6 @@ ok( $id, "load ticket" ) or diag( "error: $msg" );
my $shredder = $test->shredder_new();
$shredder->Wipeout( Object => $ticket );
+$test->db_is_valid;
+
cmp_deeply( $test->dump_current_and_savepoint(), "current DB equal to savepoint");
diff --git a/t/shredder/01ticket.t b/t/shredder/01ticket.t
index 6f4183d..4ef4992 100644
--- a/t/shredder/01ticket.t
+++ b/t/shredder/01ticket.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 15;
+use RT::Test::Shredder tests => 20;
my $test = "RT::Test::Shredder";
$test->create_savepoint('clean');
@@ -26,6 +26,7 @@ use RT::Tickets;
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $tickets );
$shredder->WipeoutAll;
+ $test->db_is_valid;
}
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
@@ -44,10 +45,12 @@ cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to sav
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $child );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('parent_ticket'), "current DB equal to savepoint");
$shredder->PutObjects( Objects => $parent );
$shredder->WipeoutAll;
+ $test->db_is_valid;
}
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
@@ -61,16 +64,18 @@ cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to sav
my $child = RT::Ticket->new( RT->SystemUser );
my ($cid) = $child->Create( Subject => 'test', Queue => 1 );
- ok( $cid, "created new ticket" );
+ ok( $cid, "created new ticket #$cid" );
($status, $msg) = $parent->AddLink( Type => 'DependsOn', Target => $cid );
ok( $status, "Added link between tickets") or diag("error: $msg");
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $child );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('parent_ticket'), "current DB equal to savepoint");
$shredder->PutObjects( Objects => $parent );
$shredder->WipeoutAll;
+ $test->db_is_valid;
}
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
diff --git a/t/shredder/02group_member.t b/t/shredder/02group_member.t
index 4f881a0..4170c94 100644
--- a/t/shredder/02group_member.t
+++ b/t/shredder/02group_member.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 22;
+use RT::Test::Shredder tests => 26;
my $test = "RT::Test::Shredder";
### nested membership check
@@ -41,14 +41,17 @@ my $test = "RT::Test::Shredder";
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $members );
$shredder->WipeoutAll();
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('buadd'), "current DB equal to savepoint");
$shredder->PutObjects( Objects => $user );
$shredder->WipeoutAll();
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('bucreate'), "current DB equal to savepoint");
$shredder->PutObjects( Objects => [$pgroup, $cgroup] );
$shredder->WipeoutAll();
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -85,6 +88,7 @@ my $test = "RT::Test::Shredder";
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $member );
$shredder->WipeoutAll();
+ $test->db_is_valid;
$ticket = RT::Ticket->new( RT->SystemUser );
($status, $msg) = $ticket->Load( $id );
diff --git a/t/shredder/02queue.t b/t/shredder/02queue.t
index 5b83e0f..00213ec 100644
--- a/t/shredder/02queue.t
+++ b/t/shredder/02queue.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 16;
+use RT::Test::Shredder tests => 21;
my $test = "RT::Test::Shredder";
diag 'simple queue' if $ENV{TEST_VERBOSE};
@@ -16,6 +16,7 @@ diag 'simple queue' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $queue );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -39,6 +40,7 @@ diag 'queue with scrip' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $queue );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -60,6 +62,7 @@ diag 'queue with template' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $queue );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -83,6 +86,7 @@ diag 'queue with a right granted' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $queue );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -108,6 +112,7 @@ diag 'queue with a watcher' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $queue );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('bqcreate'), "current DB equal to savepoint");
# $shredder->PutObjects( Objects => $group );
diff --git a/t/shredder/02template.t b/t/shredder/02template.t
index 2f9b4ab..27c9bac 100644
--- a/t/shredder/02template.t
+++ b/t/shredder/02template.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 7;
+use RT::Test::Shredder tests => 10;
my $test = "RT::Test::Shredder";
diag 'global template' if $ENV{TEST_VERBOSE};
@@ -19,6 +19,7 @@ diag 'global template' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $template );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -36,6 +37,7 @@ diag 'local template' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $template );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
@@ -63,5 +65,6 @@ diag 'template used in scrip' if $ENV{TEST_VERBOSE};
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => $template );
$shredder->WipeoutAll;
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
}
diff --git a/t/shredder/02user.t b/t/shredder/02user.t
index 776a26d..0aa80ee 100644
--- a/t/shredder/02user.t
+++ b/t/shredder/02user.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 8;
+use RT::Test::Shredder tests => 10;
my $test = "RT::Test::Shredder";
$test->create_savepoint('clean');
@@ -38,6 +38,7 @@ $test->create_savepoint('aucreate'); # after user create
my $shredder = $test->shredder_new();
$shredder->PutResolver( BaseClass => 'RT::User', Code => $resolver );
$shredder->Wipeout( Object => $user );
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('bucreate'), "current DB equal to savepoint");
}
@@ -49,5 +50,6 @@ $test->create_savepoint('aucreate'); # after user create
my $shredder = $test->shredder_new();
eval { $shredder->Wipeout( Object => $user ) };
ok($@, "wipeout throw exception if no resolvers");
+ $test->db_is_valid;
cmp_deeply( $test->dump_current_and_savepoint('aucreate'), "current DB equal to savepoint");
}
diff --git a/t/shredder/03plugin_tickets.t b/t/shredder/03plugin_tickets.t
index 5e223ae..536e6ce 100644
--- a/t/shredder/03plugin_tickets.t
+++ b/t/shredder/03plugin_tickets.t
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Test::Deep;
-use RT::Test::Shredder tests => 45;
+use RT::Test::Shredder tests => 49;
my $test = "RT::Test::Shredder";
use_ok('RT::Shredder');
@@ -55,6 +55,7 @@ use_ok('RT::Tickets');
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => \@objs );
$shredder->WipeoutAll;
+ $test->db_is_valid;
}
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
@@ -97,6 +98,7 @@ cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to sav
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => \@objs );
$shredder->WipeoutAll;
+ $test->db_is_valid;
}
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
@@ -133,6 +135,7 @@ cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to sav
my $shredder = $test->shredder_new();
$shredder->PutObjects( Objects => \@objs );
$shredder->WipeoutAll;
+ $test->db_is_valid;
my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $cid1 );
@@ -140,5 +143,6 @@ cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to sav
$shredder->PutObjects( Objects => $ticket );
$shredder->WipeoutAll;
+ $test->db_is_valid;
}
cmp_deeply( $test->dump_current_and_savepoint('clean'), "current DB equal to savepoint");
commit 4c0e4a2ede4faa0f1a1347426e72a5f6050550d0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon Apr 9 18:50:19 2012 +0400
make sure IsLinkValid doesn't skip anything
shredder doesn't care if link links deleted tickets,
often it's actually the case.
diff --git a/lib/RT/Shredder/Record.pm b/lib/RT/Shredder/Record.pm
index d1c74bf..c053dd5 100644
--- a/lib/RT/Shredder/Record.pm
+++ b/lib/RT/Shredder/Record.pm
@@ -145,12 +145,13 @@ sub __DependsOn
push( @$list, $objs );
# Links
- if ( $self->can('_Links') ) {
- # XXX: We don't use Links->Next as it's dies when object
- # is linked to object that doesn't exist
- # also, ->Next skip links to deleted tickets :(
+ if ( $self->can('Links') ) {
+ # make sure we don't skip any record
+ no warnings 'redefine';
+ local *RT::Links::IsValidLink = sub { 1 };
+
foreach ( qw(Base Target) ) {
- my $objs = $self->_Links( $_ );
+ my $objs = $self->Links( $_ );
$objs->_DoSearch;
push @$list, $objs->ItemsArrayRef;
}
commit 38de6a7355117c359c6f812a106c8ec00c6da783
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon Apr 9 18:53:34 2012 +0400
ImmediateParent is not in the DB
diff --git a/lib/RT/Shredder/GroupMember.pm b/lib/RT/Shredder/GroupMember.pm
index f43a0be..6b06637 100644
--- a/lib/RT/Shredder/GroupMember.pm
+++ b/lib/RT/Shredder/GroupMember.pm
@@ -71,8 +71,8 @@ sub __DependsOn
my $list = [];
my $objs = RT::CachedGroupMembers->new( $self->CurrentUser );
+ $objs->Limit( FIELD => 'GroupId', VALUE => $self->GroupId );
$objs->Limit( FIELD => 'MemberId', VALUE => $self->MemberId );
- $objs->Limit( FIELD => 'ImmediateParentId', VALUE => $self->GroupId );
push( @$list, $objs );
$deps->_PushDependencies(
commit a34ab0ed4a256ef167de14aa0122a7ac79b0d780
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon Apr 9 18:56:21 2012 +0400
wipeout GMs using API so it handles CGMs
diff --git a/lib/RT/Shredder/GroupMember.pm b/lib/RT/Shredder/GroupMember.pm
index 6b06637..5ebfe6e 100644
--- a/lib/RT/Shredder/GroupMember.pm
+++ b/lib/RT/Shredder/GroupMember.pm
@@ -134,6 +134,14 @@ sub __DependsOn
return $self->SUPER::__DependsOn( %args );
}
+sub __Wipeout
+{
+ my $self = shift;
+ my $msg = $self->_AsString ." wiped out";
+ $self->Delete;
+ $RT::Logger->info( $msg );
+ return;
+}
#TODO: If we plan write export tool we also should fetch parent groups
# now we only wipeout things.
commit 81e3392d09be87ed749364087e4685616f82a992
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon Apr 9 23:35:22 2012 +0400
change how we wipeout CGM records
actual delete is performed by API via GM record,
CGM.pm only deals with dumping.
diff --git a/lib/RT/Shredder/CachedGroupMember.pm b/lib/RT/Shredder/CachedGroupMember.pm
index f5542a2..ea767fe 100644
--- a/lib/RT/Shredder/CachedGroupMember.pm
+++ b/lib/RT/Shredder/CachedGroupMember.pm
@@ -57,47 +57,67 @@ use RT::Shredder::Constants;
use RT::Shredder::Exceptions;
use RT::Shredder::Dependency;
-
-sub __DependsOn
+sub _AsInsertQuery
{
my $self = shift;
- my %args = (
- Shredder => undef,
- Dependencies => undef,
- @_,
- );
- my $deps = $args{'Dependencies'};
- my $list = [];
-
-# deep memebership
- my $objs = RT::CachedGroupMembers->new( $self->CurrentUser );
- $objs->Limit( FIELD => 'Via', VALUE => $self->Id );
- $objs->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->Id );
- push( @$list, $objs );
+ return $self->SUPER::_AsInsertQuery( @_ )
+ if $self->MemberId == $self->GroupId;
+
+ my $table = $self->Table;
+ my $dbh = $RT::Handle->dbh;
+ my @quoted = ( map $dbh->quote($self->$_()), qw(GroupId MemberId Disabled) );
+
+ my $query =
+ "SELECT ". join( ', ', @quoted ) .' WHERE NOT EXISTS ('
+ ."SELECT id FROM $table WHERE GroupId = $quoted[0] AND MemberId = $quoted[1]"
+ .')'
+ ;
+ my $res = $self->BuildInsertFromSelectQuery( $query ) ."\n";
+
+ $query = "SELECT CGM1.GroupId, CGM2.MemberId, CASE WHEN CGM1.Disabled + CGM2.Disabled > 0 THEN 1 ELSE 0 END FROM
+ $table CGM1 CROSS JOIN $table CGM2
+ LEFT JOIN $table CGM3
+ ON CGM3.GroupId = CGM1.GroupId AND CGM3.MemberId = CGM2.MemberId
+ WHERE
+ CGM1.MemberId = $quoted[0] AND (CGM1.GroupId != CGM1.MemberId OR CGM1.MemberId = $quoted[1])
+ AND CGM3.id IS NULL
+ ";
+
+ if ( $self->MemberObj->IsGroup ) {
+ $query .= "
+ AND CGM2.GroupId = $quoted[1]
+ AND (CGM2.GroupId != CGM2.MemberId OR CGM2.GroupId = $quoted[1])
+ ";
+ }
+ else {
+ $query .= " AND CGM2.GroupId = $quoted[0] AND CGM2.MemberId = $quoted[1]";
+ }
+ $res .= $self->BuildInsertFromSelectQuery( $query ) ."\n";
-# principal lost group membership and lost some rights which he could delegate to
-# some body
+ return $res;
+}
-# XXX: Here is problem cause HasMemberRecursively would return true allways
-# cause we didn't delete anything yet. :(
- # if pricipal is not member anymore(could be via other groups) then proceed
- if( $self->GroupObj->Object->HasMemberRecursively( $self->MemberObj ) ) {
- my $acl = RT::ACL->new( $self->CurrentUser );
- $acl->LimitToPrincipal( Id => $self->GroupId );
+sub BuildInsertFromSelectQuery {
+ my $self = shift;
+ my $query = shift;
+ my $table = $self->Table;
+ if ( RT->Config->Get('DatabaseType') eq 'Oracle' ) {
+ $query = "(SELECT ${table}_seq.nextval, insert_from.* FROM ($query) insert_from)";
}
+ return "INSERT INTO $table(GroupId, MemberId, Disabled) $query;";
+}
+sub __Wipeout {
+ my $self = shift;
+ return $self->SUPER::__Wipeout( @_ )
+ if $self->MemberId == $self->GroupId;
- $deps->_PushDependencies(
- BaseObject => $self,
- Flags => DEPENDS_ON,
- TargetObjects => $list,
- Shredder => $args{'Shredder'}
- );
-
- return $self->SUPER::__DependsOn( %args );
+ # GroupMember takes care of wiping other records
+ return 1;
}
+
#TODO: If we plan write export tool we also should fetch parent groups
# now we only wipeout things.
@@ -140,4 +160,5 @@ sub __Relates
);
return $self->SUPER::__Relates( %args );
}
+
1;
commit ca557da50dcfbf84e6a1cfc9f48fe694d59c3abd
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon Apr 9 23:50:33 2012 +0400
update shredder's docs
diff --git a/lib/RT/Shredder.pm b/lib/RT/Shredder.pm
index 10d3536..bb45022 100644
--- a/lib/RT/Shredder.pm
+++ b/lib/RT/Shredder.pm
@@ -133,7 +133,12 @@ SQL commands to re-insert your objects into the RT database.
mysql -u your_rt_user -p your_rt_database < /path/to/rt/var/data/shredder/dump.sql
-That's it.i This will restore everything you'd deleted during a
+3) Validate database with the following command. This is required as
+ DB may be inconsistent because of changes since shredding, also some
+ restore operations are hard to implement in SQL that will work
+ on any DB runs on.
+
+That's it. This will restore everything you'd deleted during a
shredding session when the file had been created.
=head1 CONFIGURATION
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list