~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to lib/GenTest/Validator/ResultsetComparator3Simplify.pm

merge from internal tree

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# 2-way and 3-way result set comparartor with minority report in the
 
2
# case of 3-way comparision. Does also the same job as
 
3
# ResultsetComparator and may replace it for 2-ay comparision.
 
4
 
 
5
package GenTest::Validator::ResultsetComparator3Simplify;
 
6
 
 
7
require Exporter;
 
8
@ISA = qw(GenTest GenTest::Validator);
 
9
 
 
10
use strict;
 
11
 
 
12
use GenTest;
 
13
use GenTest::Constants;
 
14
use GenTest::Comparator;
 
15
use GenTest::Result;
 
16
use GenTest::Validator;
 
17
use GenTest::Simplifier::SQL;
 
18
use GenTest::Simplifier::Test;
 
19
 
 
20
 
 
21
sub compareTwo {
 
22
    my ($self, $q, $s1, $s2, $res1, $res2) = @_;
 
23
    
 
24
    my $outcome = GenTest::Comparator::compare($res1, $res2);
 
25
 
 
26
    if ($outcome == STATUS_LENGTH_MISMATCH) {
 
27
        if ($q =~ m{^\s*select}io) {
 
28
            say("-----------");
 
29
            say("Result length mismatch between $s1 and $s2 (".$res1->rows()." vs. ".$res2->rows().")");
 
30
            say("Query1: " . $res1->query());
 
31
            say("Query2: " . $res2->query());
 
32
            say(GenTest::Comparator::dumpDiff($res1,$res2));
 
33
        } else {
 
34
            say("-----------");
 
35
            say("Affected_rows mismatch between $s1 and $s2 (".$res1->affectedRows()." vs. ".$res2->affectedRows().")");
 
36
            say("Query1: " . $res1->query());
 
37
            say("Query2: " . $res2->query());
 
38
        }
 
39
    } elsif ($outcome == STATUS_CONTENT_MISMATCH) {
 
40
        say("-----------");
 
41
        say("Result content mismatch between $s1 and $s2.");
 
42
        say("Query1: " . $res1->query());
 
43
        say("Query2: " . $res2->query());
 
44
        say(GenTest::Comparator::dumpDiff($res1, $res2));
 
45
    }
 
46
 
 
47
    return $outcome;
 
48
    
 
49
}
 
50
 
 
51
sub simplifyTwo {
 
52
    my ($self, $query, $ex1, $ex2, $r1, $r2) = @_;
 
53
 
 
54
    my @executors = ( $ex1, $ex2 );
 
55
 
 
56
    my @results = ($r1, $r2);
 
57
 
 
58
    my $simplifier_sql = GenTest::Simplifier::SQL->new(
 
59
        oracle => sub {
 
60
            my $oracle_query = shift;
 
61
            
 
62
            my @oracle_results;
 
63
            foreach my $executor (@executors) {
 
64
                push @oracle_results, $executor->execute($oracle_query, 1);
 
65
            }
 
66
            my $oracle_compare = GenTest::Comparator::compare($oracle_results[0], $oracle_results[1]);
 
67
            if (
 
68
                ($oracle_compare == STATUS_LENGTH_MISMATCH) ||
 
69
                ($oracle_compare == STATUS_CONTENT_MISMATCH)
 
70
                ) {
 
71
                return ORACLE_ISSUE_STILL_REPEATABLE;
 
72
            } else {
 
73
                return ORACLE_ISSUE_NO_LONGER_REPEATABLE;
 
74
            }
 
75
        }
 
76
        );
 
77
    
 
78
    my $simplified_query = $simplifier_sql->simplify($query);
 
79
        
 
80
    if (defined $simplified_query) {
 
81
        my $simplified_results = [];
 
82
 
 
83
        foreach my $i (0,1) {
 
84
            $simplified_results->[$i] = 
 
85
                $executors[$i]->execute($simplified_query, 1);
 
86
            say("Simplified query".($i+1)." (".
 
87
                $executors[$i]->getName()." ".
 
88
                $executors[$i]->version()."): ".
 
89
                $simplified_results->[$i]->query().";");
 
90
        }
 
91
        
 
92
        say(GenTest::Comparator::dumpDiff($simplified_results->[0], $simplified_results->[1]));
 
93
        
 
94
        my $simplifier_test = GenTest::Simplifier::Test->new(
 
95
            executors   => \@executors ,
 
96
            results     => [ $simplified_results , \@results ]
 
97
            );
 
98
            
 
99
        my $simplified_test = $simplifier_test->simplify();
 
100
 
 
101
        my $tmpfile = tmpdir().$$.time().".test";
 
102
        say("Dumping .test to $tmpfile");
 
103
        open (TESTFILE, '>'.$tmpfile);
 
104
        print TESTFILE $simplified_test;
 
105
        close TESTFILE;
 
106
    } else {
 
107
        say("Could not simplify failure, appears to be sporadic.");
 
108
    }
 
109
}
 
110
 
 
111
 
 
112
sub validate {
 
113
    my ($self, $executors, $results) = @_;
 
114
 
 
115
    # Skip the whole stuff if only one resultset.
 
116
 
 
117
    return STATUS_OK if $#$results < 1;
 
118
 
 
119
    return STATUS_WONT_HANDLE 
 
120
        if $results->[0]->status() == STATUS_SEMANTIC_ERROR || 
 
121
           $results->[1]->status() == STATUS_SEMANTIC_ERROR;
 
122
    return STATUS_WONT_HANDLE if $results->[0]->query() =~ m{EXPLAIN}sio;
 
123
 
 
124
    ## Compare the two first resultsets
 
125
 
 
126
    my $query = $results->[0]->query();
 
127
 
 
128
    my $server1 = $executors->[0]->getName()." ".$executors->[0]->version();
 
129
    my $server2 = $executors->[1]->getName()." ".$executors->[1]->version();
 
130
    
 
131
    my $compare_1_2 = $self->compareTwo($query, $server1, $server2, $results->[0], $results->[1]);
 
132
    my $compare_result = $compare_1_2;
 
133
 
 
134
    # If 3 of them, do some more comparisions
 
135
 
 
136
    if ($#$results > 1) {
 
137
        my $server3 = $executors->[2]->getName()." ".$executors->[2]->version();
 
138
 
 
139
        return STATUS_WONT_HANDLE if $results->[2]->status() == STATUS_SEMANTIC_ERROR;
 
140
 
 
141
        my $compare_1_3 = $self->compareTwo($query, $server1, $server3, $results->[0], $results->[2]);
 
142
 
 
143
        ## If some of the above were different, we need compare 2 and
 
144
        ## 3 too to see if there exists a minority
 
145
        if ($compare_1_2 > STATUS_OK or $compare_1_3 > STATUS_OK) {
 
146
 
 
147
            return STATUS_WONT_HANDLE if $results->[2]->status() == STATUS_SEMANTIC_ERROR;
 
148
            
 
149
            my $compare_2_3 = $self->compareTwo($query, $server2, $server3, $results->[1], $results->[2]);
 
150
 
 
151
            if ($compare_1_2 > STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 > STATUS_OK) {
 
152
                say("Minority report: no minority");
 
153
                say("-----------");
 
154
            } elsif ($compare_1_2 > STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 == STATUS_OK) {
 
155
                say("Minority report: $server1(dsn1) differs from the two others");
 
156
                say("-----------");
 
157
                ####
 
158
                #### In this first shot, we only do simplification if
 
159
                #### Server 1, which is assumed to be MySQL is the
 
160
                #### minority, and we do the simplification only withe
 
161
                #### excutions on 1 and 2. This should be sufficirnt
 
162
                #### for hunting down MYSQL bugs.
 
163
                #### 
 
164
                if (($query =~ m{^\s*select}sio) && (
 
165
                        ($compare_1_2 == STATUS_LENGTH_MISMATCH) ||
 
166
                        ($compare_1_2 == STATUS_CONTENT_MISMATCH))) {
 
167
                    $self->simplifyTwo($query,$executors->[0],$executors->[1],$results->[0],$results->[1]);
 
168
                }
 
169
            } elsif ($compare_1_2 > STATUS_OK and $compare_1_3 == STATUS_OK and $compare_2_3 > STATUS_OK) {
 
170
                say("Minority report: $server2(dsn2) differs from the two others");
 
171
                say("-----------");
 
172
            } elsif ($compare_1_2 == STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 > STATUS_OK) {
 
173
                say("Minority report: $server3(dsn3) differs from the two others");
 
174
                say("-----------");
 
175
            }
 
176
 
 
177
            $compare_result = $compare_2_3 if $compare_2_3 > $compare_result;
 
178
        }
 
179
        
 
180
        $compare_result = $compare_1_3 if $compare_1_3 > $compare_result;
 
181
    }
 
182
    
 
183
    
 
184
    #
 
185
    # If the discrepancy is found on SELECT, we reduce the severity of
 
186
    # the error so that the test can continue hopefully finding
 
187
    # further errors in the same run or providing an indication as to
 
188
    # how frequent the error is.
 
189
    #
 
190
    # If the discrepancy is on an UPDATE, then the servers have
 
191
    # diverged and the test can not continue safely.
 
192
    # 
 
193
 
 
194
    # CAVEAT: This may cause false positives if one execution
 
195
    # influences the following executions. Failures due to a previous
 
196
    # failure have been seen.
 
197
    
 
198
    if ($query =~ m{^[\s/*!0-9]*(EXPLAIN|SELECT|ALTER|LOAD\s+INDEX|CACHE\s+INDEX)}io) {
 
199
        return $compare_result - STATUS_SELECT_REDUCTION;
 
200
    } else {
 
201
        return $compare_result;
 
202
    }
 
203
}
 
204
 
 
205
1;