~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to tests/kewpie/lib/test_mgmt/test_execution.py

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
# -*- mode: python; indent-tabs-mode: nil; -*-
 
3
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
4
#
 
5
# Copyright (C) 2010 Patrick Crews
 
6
#
 
7
# This program is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free Software Foundation; either version 2 of the License, or
 
10
# (at your option) any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program; if not, write to the Free Software
 
19
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
 
 
21
""" test_execution:
 
22
    code related to the execution of test cases 
 
23
    
 
24
    We are provided access to a testManager with 
 
25
    mode-specific testCases.  We contact the executionManager
 
26
    to produce the system and server configurations we need
 
27
    to execute a test.
 
28
 
 
29
"""
 
30
 
 
31
# imports
 
32
import os
 
33
import sys
 
34
import subprocess
 
35
 
 
36
class testExecutor():
 
37
    """ class for handling the execution of testCase
 
38
        objects.  Mode-specific executors inherit
 
39
        from me.
 
40
 
 
41
    """
 
42
 
 
43
    def __init__(self, execution_manager, name, verbose, debug):
 
44
        self.skip_keys = [ 'execution_manager'
 
45
                         , 'system_manager'
 
46
                         , 'test_manager'
 
47
                         , 'server_manager']
 
48
        self.debug = debug
 
49
        self.verbose = verbose
 
50
        self.initial_run = 1
 
51
        self.status = 0 # not running
 
52
        self.execution_manager = execution_manager
 
53
        self.system_manager = self.execution_manager.system_manager
 
54
        self.testcase_repeat_count = self.execution_manager.testcase_repeat_count
 
55
        self.cmd_prefix = self.system_manager.cmd_prefix
 
56
        self.logging = self.system_manager.logging
 
57
        self.test_manager = self.execution_manager.test_manager
 
58
        self.server_manager = self.execution_manager.server_manager
 
59
        self.time_manager = self.system_manager.time_manager
 
60
        self.name = name
 
61
        self.working_environment = {} # we pass env dict to define what we need
 
62
        self.dirset = { self.name : { 'log': None } }
 
63
        self.workdir = self.system_manager.create_dirset( self.system_manager.workdir
 
64
                                                        , self.dirset)
 
65
        self.logdir = os.path.join(self.workdir,'log')
 
66
        self.master_server = self.server_manager.allocate_server( self.name
 
67
                                                                , self
 
68
                                                                , []
 
69
                                                                , self.workdir
 
70
                                                                )
 
71
        self.record_flag=self.execution_manager.record_flag
 
72
        self.current_servers = [self.master_server]
 
73
        self.current_testcase = None    
 
74
        self.current_test_status = None
 
75
        self.current_test_retcode = None
 
76
        self.current_test_output = None
 
77
        self.current_test_exec_time = 0 
 
78
         
 
79
        self.logging.debug_class(self)
 
80
 
 
81
    def execute(self, start_and_exit):
 
82
        """ Execute a test case.  The details are *very* mode specific """
 
83
        self.status = 1 # we are running
 
84
        keep_running = 1
 
85
        self.logging.verbose("Executor: %s beginning test execution..." %(self.name))
 
86
        while self.test_manager.has_tests() and keep_running == 1:
 
87
            self.get_testCase()
 
88
            for i in range(self.testcase_repeat_count):
 
89
                if keep_running:
 
90
                    self.handle_system_reqs()
 
91
                    self.handle_server_reqs()
 
92
                    self.handle_utility_reqs()
 
93
                    self.handle_start_and_exit(start_and_exit)
 
94
                    if self.current_test_status != 'fail':
 
95
                        self.execute_testCase()
 
96
                    self.record_test_result()
 
97
                    if self.current_test_status == 'fail' and not self.execution_manager.force:
 
98
                        self.logging.error("Failed test.  Use --force to execute beyond the first test failure")
 
99
                        keep_running = 0
 
100
                    self.current_test_status = None # reset ourselves
 
101
        self.status = 0
 
102
 
 
103
    def get_testCase(self):
 
104
        """ Ask our execution_manager for a testCase to work on """
 
105
        
 
106
        #self.test_manager.mutex.acquire()
 
107
        self.current_testcase = self.test_manager.get_testCase(self.name)
 
108
        #self.test_manager.mutex.release()
 
109
        
 
110
 
 
111
    def handle_server_reqs(self):
 
112
        """ Get the servers required to execute the testCase 
 
113
            and ensure that we have servers and they were started
 
114
            as expected.  We take necessary steps if not
 
115
            We also handle --start-and-exit here
 
116
 
 
117
        """
 
118
 
 
119
        server_requirements = self.current_testcase.server_requirements
 
120
        if server_requirements:
 
121
            (self.current_servers,bad_start) = self.server_manager.request_servers( self.name
 
122
                                                                  , self.workdir
 
123
                                                                  , self.current_testcase.cnf_path
 
124
                                                                  , self.current_testcase.server_requests
 
125
                                                                  , server_requirements
 
126
                                                                  , self)
 
127
            if self.current_servers == 0 or bad_start:
 
128
                # error allocating servers, test is a failure
 
129
                self.logging.warning("Problem starting server(s) for test...failing test case")
 
130
                self.current_test_status = 'fail'
 
131
                self.set_server_status(self.current_test_status)
 
132
                output = ''           
 
133
            if self.initial_run:
 
134
                self.initial_run = 0
 
135
                self.current_servers[0].report()
 
136
            self.master_server = self.current_servers[0]
 
137
            if len(self.current_servers) > 1:
 
138
                # We have a validation server or something we need to communicate with
 
139
                # We export some env vars with EXECUTOR_SERVER and expect the randge
 
140
                # code to know enough to look for this marker
 
141
                extra_reqs = {}
 
142
                for server in self.current_servers:
 
143
                    variable_name = "%s_%s" %(self.name.upper(), server.name.upper())
 
144
                    variable_value = str(server.master_port)
 
145
                    extra_reqs[variable_name] = variable_value
 
146
                    variable_name = variable_name + "_PID"
 
147
                    variable_value = str(server.pid)
 
148
                    extra_reqs[variable_name] = variable_value
 
149
                self.working_environment.update(extra_reqs)
 
150
            return 
 
151
 
 
152
    def handle_start_and_exit(self, start_and_exit):
 
153
        """ Do what needs to be done if we have the
 
154
            --start-and-exit flag
 
155
 
 
156
        """
 
157
        if start_and_exit:
 
158
                # We blow away any port_management files for our ports
 
159
                # Technically this won't let us 'lock' any ports that 
 
160
                # we aren't explicitly using (visible to netstat scan)
 
161
                # However one could argue that if we aren't using it, 
 
162
                # We shouldn't hog it ; )
 
163
                # We might need to do this better later
 
164
                for server in self.current_servers:
 
165
                    if server != self.master_server:
 
166
                        server.report()
 
167
                    server.cleanup() # this only removes any port files
 
168
                self.logging.info("User specified --start-and-exit.  kewpie.py exiting and leaving servers running...") 
 
169
                sys.exit(0)
 
170
 
 
171
    def handle_utility_reqs(self):
 
172
        """ Call any utilities we want to use before starting a test
 
173
            At present this is envisioned for use with datagen
 
174
            but there may be other things we wish to use
 
175
            At that point, we may need to explore other ways of
 
176
            defining our testing environment, such as with
 
177
            nice config files / modules
 
178
 
 
179
        """
 
180
 
 
181
        # We call gendata against the server(s) with the
 
182
        # specified file
 
183
        if self.execution_manager.gendata_file:
 
184
            dsn = "--dsn=dbi:%s:host=127.0.0.1:port=%d:user=root:password="":database=test" %( self.master_server.type
 
185
                                                                                             , self.master_server.master_port)
 
186
            gendata_cmd = "./gendata.pl %s --spec=%s" %( dsn 
 
187
                                                       , self.execution_manager.gendata_file
 
188
                                                       )
 
189
            #self.system_manager.execute_cmd(gendata_cmd)
 
190
            gendata_subproc = subprocess.Popen( gendata_cmd
 
191
                                              , shell=True
 
192
                                              , cwd=self.system_manager.randgen_path
 
193
                                              , stdout = None
 
194
                                              , stderr = None
 
195
                                              )
 
196
            gendata_subproc.wait()
 
197
            gendata_retcode = gendata_subproc.returncode
 
198
            if gendata_retcode:
 
199
                self.logging.error("gendata command: %s failed with retcode: %d" %(gendata_cmd
 
200
                                                                             , gendata_retcode))
 
201
 
 
202
    def execute_testCase(self):
 
203
        """ Do whatever evil voodoo we must do to execute a testCase """
 
204
        self.logging.verbose("Executor: %s executing test: %s" %(self.name, self.current_testcase.fullname))
 
205
 
 
206
    def record_test_result(self):
 
207
        """ We get the test_manager to record the result """
 
208
 
 
209
        self.test_manager.record_test_result( self.current_testcase
 
210
                                                , self.current_test_status
 
211
                                                , self.current_test_output
 
212
                                                , self.current_test_exec_time )
 
213
 
 
214
            
 
215
    def set_server_status(self, test_status):
 
216
        """ We update our servers to indicate if a test passed or failed """
 
217
        for server in self.current_servers:
 
218
            if test_status == 'fail':
 
219
                server.failed_test = 1
 
220
 
 
221
   
 
222
    def handle_system_reqs(self):
 
223
        """ We check our test case and see what we need to do
 
224
            system-wise to get ready.  This is likely to be 
 
225
            mode-dependent and this is just a placeholder
 
226
            method
 
227
 
 
228
        """
 
229
 
 
230
        self.process_environment_reqs()
 
231
        self.process_symlink_reqs()
 
232
        self.process_master_sh()  
 
233
        return
 
234
 
 
235
    def process_master_sh(self):
 
236
        """ We do what we need to if we have a master.sh file """
 
237
        if self.current_testcase.master_sh:
 
238
            retcode, output = self.system_manager.execute_cmd("/bin/sh %s" %(self.current_testcase.master_sh))
 
239
            self.logging.debug("retcode: %retcode")
 
240
            self.logging.debug("%output")
 
241
 
 
242
    def process_environment_reqs(self):
 
243
        """ We generate the ENV vars we need set
 
244
            and then ask systemManager to do so
 
245
 
 
246
        """
 
247
        # We need to have a default set / file / whatever based
 
248
        # on the dbqp config file / what we're using dbqp for
 
249
        # will move this dict elsewhere to make this method more generic
 
250
        #
 
251
        # We're also doing the kludgy thing of basing env_reqs on 
 
252
        # the master_server type.  At some point, we'll see about making
 
253
        # this more flexible / extensible.
 
254
 
 
255
        if self.master_server.type == 'drizzle':
 
256
            env_reqs = { 'DRIZZLETEST_VARDIR': self.master_server.vardir
 
257
                       ,  'DRIZZLE_TMP_DIR': self.master_server.tmpdir
 
258
                       ,  'MASTER_MYSOCK': self.master_server.socket_file
 
259
                       ,  'MASTER_MYPORT': str(self.master_server.master_port)
 
260
                       ,  'MC_PORT': str(self.master_server.mc_port)
 
261
                       ,  'PBMS_PORT': str(self.master_server.pbms_port)
 
262
                       ,  'JSON_SERVER_PORT': str(self.master_server.json_server_port)
 
263
                       ,  'RABBITMQ_NODE_PORT': str(self.master_server.rabbitmq_node_port)
 
264
                       ,  'DRIZZLE_TCP_PORT': str(self.master_server.drizzle_tcp_port)
 
265
                       ,  'EXE_DRIZZLE': self.master_server.drizzle_client
 
266
                       ,  'MASTER_SERVER_SLAVE_CONFIG' : self.master_server.slave_config_file
 
267
                       ,  'DRIZZLE_DUMP': "%s --no-defaults -uroot -p%d" %( self.master_server.drizzledump
 
268
                                                            , self.master_server.master_port)
 
269
                       ,  'DRIZZLE_SLAP': "%s -uroot -p%d" %( self.master_server.drizzleslap
 
270
                                                            , self.master_server.master_port)
 
271
                       ,  'DRIZZLE_IMPORT': "%s -uroot -p%d" %( self.master_server.drizzleimport
 
272
                                                              , self.master_server.master_port)
 
273
                       ,  'DRIZZLE': "%s -uroot -p%d" %( self.master_server.drizzle_client
 
274
                                                       , self.master_server.master_port)
 
275
                       ,  'DRIZZLE_BASEDIR' : self.system_manager.code_manager.code_trees['drizzle'][0].basedir
 
276
                       ,  'DRIZZLE_TEST_WORKDIR' : self.system_manager.workdir
 
277
                       ,  'SQLBENCH_DIR' : os.path.join( self.system_manager.testdir
 
278
                                                       , 'sql-bench')
 
279
                       }
 
280
        elif self.master_server.type in ['mysql','percona','galera']:
 
281
            env_reqs = {  'MYSQLTEST_VARDIR': self.master_server.vardir
 
282
                       ,  'MYSQL_TMP_DIR': self.master_server.tmpdir
 
283
                       ,  'MASTER_MYSOCK': self.master_server.socket_file
 
284
                       ,  'MASTER_MYPORT': str(self.master_server.master_port)
 
285
                       ,  'EXE_MYSQL': self.master_server.mysql_client
 
286
                       ,  'MYSQL_DUMP': "%s --no-defaults -uroot -p%d" %( self.master_server.mysqldump
 
287
                                                            , self.master_server.master_port)
 
288
                       ,  'MYSQL_SLAP': "%s -uroot -p%d" %( self.master_server.mysqlslap
 
289
                                                          , self.master_server.master_port)
 
290
                       ,  'MYSQL_IMPORT': "%s -uroot -p%d" %( self.master_server.mysqlimport
 
291
                                                            , self.master_server.master_port)
 
292
                       ,  'MYSQL_UPGRADE': "%s -uroot --datadir=%s" %( self.master_server.mysql_upgrade
 
293
                                                                     , self.master_server.datadir)
 
294
                       ,  'MYSQL': "%s -uroot -p%d" %( self.master_server.mysql_client
 
295
                                                     , self.master_server.master_port)
 
296
                       #,  'MYSQL_BASEDIR' : self.system_manager.code_manager.code_trees['mysql'][0].basedir
 
297
                       ,  'MYSQL_TEST_WORKDIR' : self.system_manager.workdir
 
298
                       ,  'SQLBENCH_DIR' : os.path.join( self.system_manager.testdir
 
299
                                                       , 'sql-bench')
 
300
                       }         
 
301
 
 
302
        self.working_environment = self.system_manager.env_manager.create_working_environment(env_reqs)
 
303
 
 
304
    def process_symlink_reqs(self):
 
305
        """ Create any symlinks we may need """
 
306
        needed_symlinks = []
 
307
 
 
308
        self.system_manager.create_symlinks(needed_symlinks)
 
309
 
 
310
    
 
311
   
 
312
 
 
313
 
 
314