1
# Copyright (c) 2008,2011 Oracle and/or its affiliates. All rights reserved.
2
# Use is subject to license terms.
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; version 2 of the License.
8
# This program is distributed in the hope that it will be useful, but
9
# WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
# General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18
package GenTest::Mixer;
27
use GenTest::Constants;
29
use GenTest::Validator;
31
use constant MIXER_GENERATOR => 0;
32
use constant MIXER_EXECUTORS => 1;
33
use constant MIXER_VALIDATORS => 2;
34
use constant MIXER_FILTERS => 3;
35
use constant MIXER_PROPERTIES => 4;
44
my $mixer = $class->SUPER::new({
45
'generator' => MIXER_GENERATOR,
46
'executors' => MIXER_EXECUTORS,
47
'validators' => MIXER_VALIDATORS,
48
'properties' => MIXER_PROPERTIES,
49
'filters' => MIXER_FILTERS
52
foreach my $executor (@{$mixer->executors()}) {
53
my $init_result = $executor->init();
54
return undef if $init_result > STATUS_OK;
55
$executor->cacheMetaData();
58
my @validators = @{$mixer->validators()};
61
# If a Validator was specified by name, load the class and create an object.
63
foreach my $i (0..$#validators) {
64
my $validator = $validators[$i];
65
if (ref($validator) eq '') {
66
$validator = "GenTest::Validator::".$validator;
67
say("Loading Validator $validator.");
68
eval "use $validator" or print $@;
69
$validators[$i] = $validator->new();
71
$validators[$i]->configure($mixer->properties);
73
$validators{ref($validators[$i])}++;
76
# Query every object for its prerequisies. If one is not loaded, load it and place it
77
# in front of the Validators array.
80
foreach my $validator (@validators) {
81
my $prerequisites = $validator->prerequsites();
82
next if not defined $prerequisites;
83
foreach my $prerequisite (@$prerequisites) {
84
next if exists $validators{$prerequisite};
85
$prerequisite = "GenTest::Validator::".$prerequisite;
86
# say("Loading Prerequisite $prerequisite, required by $validator.");
87
eval "use $prerequisite" or print $@;
88
push @prerequisites, $prerequisite->new();
92
my @validators = (@prerequisites, @validators);
93
$mixer->setValidators(\@validators);
95
foreach my $validator (@validators) {
96
return undef if not defined $validator->init($mixer->executors());
105
my $executors = $mixer->executors();
106
my $filters = $mixer->filters();
108
if ($mixer->properties->freeze_time) {
109
foreach my $ex (@$executors) {
110
if ($ex->type == DB_MYSQL) {
111
$ex->execute("SET TIMESTAMP=0");
112
$ex->execute("SET TIMESTAMP=UNIX_TIMESTAMP(NOW())");
114
carp "Don't know how to freeze time for ".$ex->getName;
119
my $queries = $mixer->generator()->next($executors);
120
if (not defined $queries) {
121
say("Internal grammar problem. Terminating.");
122
return STATUS_ENVIRONMENT_FAILURE;
123
} elsif ($queries->[0] eq '') {
124
# say("Your grammar generated an empty query.");
125
# return STATUS_ENVIRONMENT_FAILURE;
128
my $max_status = STATUS_OK;
130
query: foreach my $query (@$queries) {
131
next if $query =~ m{^\s*$}o;
133
if (defined $filters) {
134
foreach my $filter (@$filters) {
135
my $explain = Dumper $executors->[0]->execute("EXPLAIN $query") if $query =~ m{^\s*SELECT}sio;
136
my $filter_result = $filter->filter($query." ".$explain);
137
next query if $filter_result == STATUS_SKIP;
141
my @execution_results;
142
foreach my $executor (@$executors) {
143
my $execution_result = $executor->execute($query);
144
$max_status = $execution_result->status() if $execution_result->status() > $max_status;
145
push @execution_results, $execution_result;
147
# If one server has crashed, do not send the query to the second one in order to preserve consistency
148
if ($execution_result->status() == STATUS_SERVER_CRASHED) {
149
say("Server crash reported at dsn ".$executor->dsn());
153
next query if $execution_result->status() == STATUS_SKIP;
156
foreach my $validator (@{$mixer->validators()}) {
157
my $validation_result = $validator->validate($executors, \@execution_results);
158
$max_status = $validation_result if ($validation_result != STATUS_WONT_HANDLE) && ($validation_result > $max_status);
163
# Record the lowest (best) status achieved for all participating rules. The goal
164
# is for all rules to generate at least some STATUS_OK queries. If not, the offending
165
# rules will be reported on DESTROY.
168
if ((rqg_debug()) && (ref($mixer->generator()) eq 'GenTest::Generator::FromGrammar')) {
169
my $participating_rules = $mixer->generator()->participatingRules();
170
foreach my $participating_rule (@$participating_rules) {
172
(not exists $rule_status{$participating_rule}) ||
173
($rule_status{$participating_rule} > $max_status)
175
$rule_status{$participating_rule} = $max_status
186
foreach my $rule (keys %rule_status) {
187
push @rule_failures, "$rule (".status2text($rule_status{$rule}).")" if $rule_status{$rule} > STATUS_OK;
190
if ($#rule_failures > -1) {
191
say("The following rules produced no STATUS_OK queries: ".join(', ', @rule_failures));
196
return $_[0]->[MIXER_GENERATOR];
200
return $_[0]->[MIXER_EXECUTORS];
204
return $_[0]->[MIXER_VALIDATORS];
208
return $_[0]->[MIXER_PROPERTIES];
212
return $_[0]->[MIXER_FILTERS];
216
$_[0]->[MIXER_VALIDATORS] = $_[1];