blob: 743f76792314f51524ec67cc7b115a99ae2acf06 [file] [log] [blame]
#! /usr/bin/env python
#/**
#* @@@ START COPYRIGHT @@@
#*
#* Licensed to the Apache Software Foundation (ASF) under one
#* or more contributor license agreements. See the NOTICE file
#* distributed with this work for additional information
#* regarding copyright ownership. The ASF licenses this file
#* to you under the Apache License, Version 2.0 (the
#* "License"); you may not use this file except in compliance
#* with the License. You may obtain a copy of the License at
#*
#* http://www.apache.org/licenses/LICENSE-2.0
#*
#* Unless required by applicable law or agreed to in writing,
#* software distributed under the License is distributed on an
#* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#* KIND, either express or implied. See the License for the
#* specific language governing permissions and limitations
#* under the License.
#*
#* @@@ END COPYRIGHT @@@
# */
import sys
import subprocess
import fcntl
import select
import errno
import os
import string
import inspect
import optparse
#----------------------------------------------------------------------------
# A function (or a structure in C's sense) that contains all variables
# recording user's command-line parameters.
#----------------------------------------------------------------------------
def ArgList():
_appid = None
_target = None
_user = None
_pw = None
_role = None
_dsn = None
_schema = None
_javahome = None
_jdbc_classpath = None
_jdbc_version = None
_prop_file = None
_export_str1 = None
_export_str2 = None
_export_str3 = None
_export_str4 = None
_export_str5 = None
_jdbc_type = None
_tests = None
_dbmaj = None
_dbmin = None
#----------------------------------------------------------------------------
# Tracking all of the global variables in here.
#----------------------------------------------------------------------------
def gvars():
my_ROOT = None
my_EXPORT_CMD = None
#----------------------------------------------------------------------------
# Make a call to the shell and fetch the results back.
#----------------------------------------------------------------------------
def stdout_write(output):
sys.stdout.write(output)
sys.stdout.flush()
def read_async(fd):
try:
return fd.read()
except IOError, e:
if e.errno != errno.EAGAIN:
raise e
else:
return ''
def shell_call(cmd):
# subprocess.call(cmd)
ON_POSIX = 'posix' in sys.builtin_module_names
hpipe = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
bufsize=1, close_fds=ON_POSIX, shell=True)
# Change to non-blocking mode, so read returns even if there is no data.
fcntl.fcntl(hpipe.stdout, fcntl.F_SETFL, os.O_NONBLOCK)
fcntl.fcntl(hpipe.stderr, fcntl.F_SETFL, os.O_NONBLOCK)
total_output_stdout = ''
total_output_stderr = ''
while True:
# wait for data to become available
select.select([hpipe.stdout, hpipe.stderr], [], [])
# Try reading some data from each
output_stdout = read_async(hpipe.stdout)
output_stderr = read_async(hpipe.stderr)
if output_stdout:
stdout_write(output_stdout)
total_output_stdout += output_stdout
if output_stderr:
stdout_write(output_stderr)
total_output_stderr += output_stderr
rc = hpipe.poll()
if rc != None:
return total_output_stdout + total_output_stderr
#----------------------------------------------------------------------------
# Find the token after s2 in s1
#----------------------------------------------------------------------------
def get_token_after_string(s1, s2, extra_split_chars=None):
if s2 not in s1:
return None
else:
token = s1[s1.find(s2)+len(s2):].split()[0]
if extra_split_chars != None:
token = token.split(extra_split_chars)[0]
return token
#----------------------------------------------------------------------------
# Find the sub string after s2 in s1
#----------------------------------------------------------------------------
def get_substr_after_string(s1, s2):
if s2 not in s1:
return None
else:
return s1[s1.find(s2)+len(s2):]
#----------------------------------------------------------------------------
# Generate pom.xml
#----------------------------------------------------------------------------
def generate_pom_xml(appid, jdbccp, jdbc_version):
fd1= open(os.path.join(gvars.my_ROOT, 'pom.xml.template'), 'r')
fd2 = open(os.path.join(gvars.my_ROOT, 'pom.xml'), 'w')
t, jdbc_artifact_id = jdbc_version.rsplit('.', 1)
for line in fd1:
line = string.replace(line, 'MY_APP_ID', appid)
line = string.replace(line, 'MY_JDBC_VERSION', jdbc_version)
line = string.replace(line, 'MY_JDBC_ARTIFACT_ID', jdbc_artifact_id.lower())
line = string.replace(line, 'MY_JDBC_SYS_PATH', jdbccp)
fd2.write(line)
fd1.close()
fd2.close()
#----------------------------------------------------------------------------
# Generate propfile
#----------------------------------------------------------------------------
def generate_t4_propfile(propfile, target, user, pw, role, dsn, schema, appname, jdbc_version, db_maj, db_min):
fd = open(propfile, 'w')
fd.write('url=jdbc:t4jdbc://' + target + '/\n')
fd.write('user=' + user + '\n')
fd.write('role=' + role + '\n')
fd.write('password=' + pw + '\n')
fd.write('catalog=TRAFODION\n')
fd.write('schema=' + schema + '\n')
fd.write('serverDataSource=' + dsn + '\n')
fd.write('trafjdbc_version=' + jdbc_version + '\n')
fd.write('db_major=' + db_maj + '\n')
fd.write('db_minor=' + db_min + '\n')
fd.write('sessionName=' + appname + '\n')
fd.write('applicationName=' + appname + '\n')
fd.write('batchBinding=500\n')
fd.close()
def generate_t2_propfile(propfile, user, pw, role, dsn, schema, appname, jdbc_version, db_maj, db_min):
fd = open(propfile, 'w')
fd.write('url=jdbc:sql:\n')
fd.write('user=' + user + '\n')
fd.write('role=' + role + '\n')
fd.write('password=' + pw + '\n')
fd.write('catalog=TRAFODION\n')
fd.write('schema=' + schema + '\n')
fd.write('serverDataSource=' + dsn + '\n')
fd.write('trafjdbc_version=' + jdbc_version + '\n')
fd.write('db_major=' + db_maj + '\n')
fd.write('db_minor=' + db_min + '\n')
fd.write('sessionName=' + appname + '\n')
fd.write('applicationName=' + appname + '\n')
fd.write('batchBinding=500\n')
fd.close()
#----------------------------------------------------------------------------
# Parse the argument list for main
#----------------------------------------------------------------------------
def prog_parse_args():
rec = inspect.stack()[1] # 0 reprents this line,
# 1 reprents line at caller,
# 2 reprents line at caller's caller,
# ... and so on ...
frame = rec[0]
info = inspect.getframeinfo(frame)
gvars.my_ROOT = os.path.dirname(os.path.abspath(info.filename))
DEFAULT_JDBC_CLASSPATH = '${project.basedir}/lib/jdbcT4-${TRAFODION_VER}.jar'
DEFAULT_PROP_FILE = os.path.join(gvars.my_ROOT, 'jdbcprop')
# alas, the more powerful argparse module only exists in >= 2.7 and >= 3.2,
# use optparse instead.
option_list = [
# No need to add '-h' or '-help', optparse automatically adds one.
# we do not use short options, hence the first ''.
# required args
optparse.make_option('', '--appid', action='store', type='string',
dest='appid',
help='Test application id. For instance, phoenix, jdbc_test, etc. Required argument with no default.'),
optparse.make_option('', '--target', action='store', type='string',
dest='target',
help='target \'<IP>:<port>\', required argument with no default. This is still needed for jdbc loader even when using sqlci.'),
optparse.make_option('', '--user', action='store', type='string',
dest='user',
help='user id for the target, required argument with no default. It can be any non-empty string if using sqlci.'),
optparse.make_option('', '--pw', action='store', type='string',
dest='pw',
help='password for the target, required argument with no default. It can be any non-empty string if using sqlci.'),
# optional args
optparse.make_option('', '--role', action='store', type='string',
dest='role', default='',
help='role for the target, defaulted to \'\''),
optparse.make_option('', '--dsn', action='store', type='string',
dest='dsn', default='TDM_Default_DataSource',
help='data source for the target, defaulted to \'TDM_Default_DataSource\''),
optparse.make_option('', '--schema', action='store', type='string',
dest='schema', default='AUTO',
help='schema name for the target, defaulted to \'AUTO\'. This means this is automatically generated.'),
optparse.make_option('', '--javahome', action='store', type='string',
dest='javahome', default='/usr',
help='java program (version 1.7 required) location, defaulted to \'/usr\''),
optparse.make_option('', '--jdbccp', action='store', type='string',
dest='jdbccp', default=DEFAULT_JDBC_CLASSPATH,
help='jdbc classpath, defaulted to \'${project.basedir}/lib/jdbcT4-${TRAFODION_VER}.jar\', <test_root> is where this program is.'),
optparse.make_option('', '--propfile', action='store', type='string',
dest='propfile', default=DEFAULT_PROP_FILE,
help='property file, defaulted to automatically generated \'<test root>/jdbcprop\', <test root> is where this program is.'),
optparse.make_option('', '--jdbctype', action='store', type='string',
dest='jdbctype', default='T4',
help='jdbctype, defaulted to T4'),
optparse.make_option('', '--dbmaj', action='store', type='string',
dest='dbmaj', default='2',
help='DB major version, defaulted to 2'),
optparse.make_option('', '--dbmin', action='store', type='string',
dest='dbmin', default='0',
help='DB minor version, defaulted to 0'),
optparse.make_option('', '--export1', action='store', type='string',
dest='exportstr1', default='NONE',
help='any export string, defaulted to NONE'),
optparse.make_option('', '--export2', action='store', type='string',
dest='exportstr2', default='NONE',
help='any export string, defaulted to NONE'),
optparse.make_option('', '--export3', action='store', type='string',
dest='exportstr3', default='NONE',
help='any export string, defaulted to NONE'),
optparse.make_option('', '--export4', action='store', type='string',
dest='exportstr4', default='NONE',
help='any export string, defaulted to NONE'),
optparse.make_option('', '--export5', action='store', type='string',
dest='exportstr5', default='NONE',
help='any export string, defaulted to NONE'),
optparse.make_option('', '--tests', action='store', type='string',
dest='tests', default='.*',
help='specify a subset of tests to run, for example: --tests=AlterTableTest or --tests=AlterTableTest,ArithmeticQueryTest. Multiple tests can be specified as a string with each test sperated by \',\' without space characters. When this option is omitted, the default is ALL tests.')
]
usage = 'usage: %prog [-h|--help|<options>]'
parser = optparse.OptionParser(usage=usage, option_list=option_list)
# OptionParser gets the options out, whatever is not preceeded by
# an option is considered args.
(options, args) = parser.parse_args()
# we are not expecting any args right now. In the future, if we do,
# make a list of the known args and check against it.
if args:
parser.error('Invalid argment(s) found: ' + str(args))
if options.jdbctype != 'T2' and options.jdbctype != 'T4':
parser.error('Invalid --jdbctype. Only T2 or T4 is supported: ' +
options.jdbctype);
# set certain dynamic parameters for JDBC and check for the required args
if options.jdbctype == 'T4':
ArgList._jdbc_version = 'org.trafodion.jdbc.t4.T4Driver'
if options.schema == 'AUTO':
ArgList._schema = 'T4QA'
else:
ArgList._schema = options.schema
not_found = []
T4_required_args = ['target', 'user', 'pw']
for r in T4_required_args:
if options.__dict__[r] == None:
not_found.append('--' + r)
if not_found:
parser.error('Required option(s) not found: ' + str(not_found))
elif options.jdbctype == 'T2':
ArgList._jdbc_version = 'org.trafodion.sql.T2Driver'
if options.schema == 'AUTO':
ArgList._schema = 'T2QA'
else:
ArgList._schema = options.schema
ArgList._appid = options.appid
ArgList._target = options.target
ArgList._user = options.user
ArgList._pw = options.pw
ArgList._role = options.role
ArgList._dsn = options.dsn
ArgList._javahome = options.javahome
if options.jdbccp != DEFAULT_JDBC_CLASSPATH:
options.jdbccp = os.path.abspath(options.jdbccp)
ArgList._jdbc_classpath = options.jdbccp
ArgList._prop_file = os.path.abspath(options.propfile)
ArgList._jdbc_type = options.jdbctype
ArgList._dbmaj = options.dbmaj
ArgList._dbmin = options.dbmin
ArgList._export_str1 = options.exportstr1
ArgList._export_str2 = options.exportstr2
ArgList._export_str3 = options.exportstr3
ArgList._export_str4 = options.exportstr4
ArgList._export_str5 = options.exportstr5
ArgList._tests = options.tests
# Automatically generate the prop file if the user did not specify one
if options.propfile == DEFAULT_PROP_FILE:
if options.jdbctype == 'T2':
generate_t2_propfile(ArgList._prop_file, ArgList._user, ArgList._pw, ArgList._role, ArgList._dsn, ArgList._schema, ArgList._appid, ArgList._jdbc_version, ArgList._dbmaj, ArgList._dbmin)
elif options.jdbctype == 'T4':
generate_t4_propfile(ArgList._prop_file, ArgList._target, ArgList._user, ArgList._pw, ArgList._role, ArgList._dsn, ArgList._schema, ArgList._appid, ArgList._jdbc_version, ArgList._dbmaj, ArgList._dbmin)
# Generate the pom.xml file from the template according to target type
generate_pom_xml(ArgList._appid, ArgList._jdbc_classpath, ArgList._jdbc_version)
print 'appid: ', ArgList._appid
print 'target: ', ArgList._target
print 'user: ', ArgList._user
print 'pw: ', ArgList._pw
print 'role: ', ArgList._role
print 'dsn: ', ArgList._dsn
print 'schema: ', ArgList._schema
print 'java home: ', ArgList._javahome
print 'jdbc classpath: ', ArgList._jdbc_classpath
print 'prop file: ', ArgList._prop_file
print 'jdbc type: ', ArgList._jdbc_type
print 'jdbc version: ', ArgList._jdbc_version
print 'DB version: ', ArgList._dbmaj + "." + ArgList._dbmin
print 'export string 1: ', ArgList._export_str1
print 'export string 2: ', ArgList._export_str2
print 'export string 3: ', ArgList._export_str3
print 'export string 4: ', ArgList._export_str4
print 'export string 5: ', ArgList._export_str5
if options.tests != '.*':
print 'tests to be run: ', ArgList._tests
else:
print 'tests to be run: ALL tests'
print
sys.stdout.flush()
gvars.my_EXPORT_CMD = 'export PATH=' + ArgList._javahome + '/bin:$PATH'
if ArgList._export_str1 != 'NONE':
if gvars.my_EXPORT_CMD != '':
gvars.my_EXPORT_CMD += ';'
gvars.my_EXPORT_CMD += 'export ' + ArgList._export_str1
if ArgList._export_str2 != 'NONE':
if gvars.my_EXPORT_CMD != '':
gvars.my_EXPORT_CMD += ';'
gvars.my_EXPORT_CMD += 'export ' + ArgList._export_str2
if ArgList._export_str3 != 'NONE':
if gvars.my_EXPORT_CMD != '':
gvars.my_EXPORT_CMD += ';'
gvars.my_EXPORT_CMD += 'export ' + ArgList._export_str3
if ArgList._export_str4 != 'NONE':
if gvars.my_EXPORT_CMD != '':
gvars.my_EXPORT_CMD += ';'
gvars.my_EXPORT_CMD += 'export ' + ArgList._export_str4
if ArgList._export_str5 != 'NONE':
if gvars.my_EXPORT_CMD != '':
gvars.my_EXPORT_CMD += ';'
gvars.my_EXPORT_CMD += 'export ' + ArgList._export_str5
#----------------------------------------------------------------------------
# main
#----------------------------------------------------------------------------
prog_parse_args()
# clean the target
output = shell_call('unset JAVA_HOME;' + gvars.my_EXPORT_CMD + '; mvn clean')
stdout_write(output + '\n')
# do the whole build, including running tests
output = shell_call('unset JAVA_HOME;' + gvars.my_EXPORT_CMD + '; mvn test -Dtest=' + ArgList._tests)
lines = output.split('\n')
to_parse = False
num_tests_run=0
num_tests_failed=0
num_tests_errors=0
num_tests_skipped=0
for ln in lines:
if ln.startswith('Results '):
to_parse = True
continue
if to_parse:
if ln.startswith('Tests run: '):
num_tests_run = int(get_token_after_string(ln, 'Tests run:', ','))
num_tests_failed = int(get_token_after_string(ln, 'Failures:', ','))
num_tests_errors = int(get_token_after_string(ln, 'Errors:', ','))
num_tests_skipped = int(get_token_after_string(ln, 'Skipped:', ','))
sumfile_output = '\n---------- SUMARY ----------\n'
sumfile_output += ('Total number of tests run: ' + str(num_tests_run) + '\n')
sumfile_output += ('Total number of failures: ' + str(num_tests_failed) + '\n')
sumfile_output += ('Total number of errors: ' + str(num_tests_errors) + '\n')
sumfile_output += ('Total number of tests skipped: ' + str(num_tests_skipped) + '\n')
stdout_write(sumfile_output)