Updated Branches: refs/heads/trunk d48edfaa0 -> d125f7031
AMBARI-4370. Modify Unittest.py for running test Component Scripts (Eugene Chekanskiy via aonishuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d125f703 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d125f703 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d125f703 Branch: refs/heads/trunk Commit: d125f703153ef48ac3122653dec4fdb7db713333 Parents: d48edfa Author: Andrew Onischuk <[email protected]> Authored: Wed Jan 22 09:02:00 2014 -0800 Committer: Andrew Onischuk <[email protected]> Committed: Wed Jan 22 09:02:00 2014 -0800 ---------------------------------------------------------------------- ambari-server/pom.xml | 4 +- ambari-server/src/test/python/unitTests.py | 183 ++++++++++++++++++++++-- 2 files changed, 177 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/d125f703/ambari-server/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml index 02fd326..2972e94 100644 --- a/ambari-server/pom.xml +++ b/ambari-server/pom.xml @@ -29,6 +29,7 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <python.ver>python >= 2.6</python.ver> + <custom.tests>false</custom.tests> <hdpUrlForCentos6>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.1.1.0</hdpUrlForCentos6> </properties> <build> @@ -455,9 +456,10 @@ <workingDirectory>src/test/python</workingDirectory> <arguments> <argument>unitTests.py</argument> + <argument>${custom.tests}</argument> </arguments> <environmentVariables> - <PYTHONPATH>${project.basedir}/../ambari-common/src/test/python:${project.basedir}/src/main/python:${project.basedir}/src/main/python/ambari-server-state:${project.basedir}/src/test/python:$PYTHONPATH</PYTHONPATH> + <PYTHONPATH>${project.basedir}/../ambari-agent/src/main/python:${project.basedir}/../ambari-common/src/main/python/jinja2:${project.basedir}/../ambari-common/src/test/python:${project.basedir}/src/main/python:${project.basedir}/src/main/python/ambari-server-state:${project.basedir}/src/test/python:$PYTHONPATH</PYTHONPATH> </environmentVariables> <skip>${skipTests}</skip> </configuration> http://git-wip-us.apache.org/repos/asf/ambari/blob/d125f703/ambari-server/src/test/python/unitTests.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/python/unitTests.py b/ambari-server/src/test/python/unitTests.py index 9448bb6..c6eab75 100644 --- a/ambari-server/src/test/python/unitTests.py +++ b/ambari-server/src/test/python/unitTests.py @@ -17,29 +17,194 @@ limitations under the License. ''' import unittest -import glob +import multiprocessing import os import sys from random import shuffle +import fnmatch -TEST_MASK = 'Test*.py' +#excluded directories with non-test staff from stack and service scanning, +#also we can add service or stack to skip here +STACK_EXCLUDE = ["utils"] +SERVICE_EXCLUDE = ["configs"] -def main(): +TEST_MASK = '[Tt]est*.py' +CUSTOM_TEST_MASK = '_[Tt]est*.py' +def get_parent_path(base, directory_name): + """ + Returns absolute path for directory_name, if directory_name present in base. + For example, base=/home/user/test2, directory_name=user - will return /home/user + """ + done = False + while not done: + base = os.path.dirname(base) + if base == "/": + return None + done = True if os.path.split(base)[-1] == directory_name else False + return base + +def get_test_files(path, mask = None, recursive=True): + """ + Returns test files for path recursively + """ + current = [] + directory_items = os.listdir(path) + + for item in directory_items: + add_to_pythonpath = False + if os.path.isfile(path + "/" + item): + if fnmatch.fnmatch(item, mask): + add_to_pythonpath = True + current.append(item) + elif os.path.isdir(path + "/" + item): + if recursive: + current.extend(get_test_files(path + "/" + item, mask = mask)) + if add_to_pythonpath: + sys.path.append(path) + return current + + +def stack_test_executor(base_folder, stack, service, custom_tests, executor_result): + """ + Stack tests executor. Must be executed in separate process to prevent module + name conflicts in different stacks. + """ + #extract stack scripts folders + if custom_tests: + test_mask = CUSTOM_TEST_MASK + else: + test_mask = TEST_MASK + + server_src_dir = get_parent_path(base_folder,'src') + + base_stack_folder = os.path.join(server_src_dir, + 'main/resources/stacks/HDP/{0}'.format(stack)) - pwd = os.path.dirname(__file__) - if pwd: - global TEST_MASK - TEST_MASK = pwd + os.sep + TEST_MASK + script_folders = set() + for root, subFolders, files in os.walk(base_stack_folder): + if os.path.split(root)[-1] == "scripts" and service in root: + script_folders.add(root) + + sys.path.extend(script_folders) + + tests = get_test_files(base_folder, mask = test_mask) - tests = glob.glob(TEST_MASK) shuffle(tests) modules = [os.path.basename(s)[:-3] for s in tests] suites = [unittest.defaultTestLoader.loadTestsFromName(name) for name in modules] testSuite = unittest.TestSuite(suites) + textRunner = unittest.TextTestRunner(verbosity=2).run(testSuite) + + #for pretty output + sys.stdout.flush() + sys.stderr.flush() + exit_code = 0 if textRunner.wasSuccessful() else 1 + executor_result.put({'exit_code':exit_code, + 'tests_run':textRunner.testsRun, + 'errors':[(str(item[0]),str(item[1]),"ERROR") for item in textRunner.errors], + 'failures':[(str(item[0]),str(item[1]),"FAIL") for item in textRunner.failures], + 'skipped':[(str(item[0]),str(item[1]),"SKIPPED") for item in textRunner.skipped]}) + executor_result.put(0) if textRunner.wasSuccessful() else executor_result.put(1) + +def main(): + custom_tests = False + if len(sys.argv) > 1: + if sys.argv[1] == "true": + custom_tests = True + pwd = os.path.abspath(os.path.dirname(__file__)) + ambari_server_folder = get_parent_path(pwd,'ambari-server') + ambari_agent_folder = os.path.join(ambari_server_folder,"../ambari-agent") + ambari_common_folder = os.path.join(ambari_server_folder,"../ambari-common") + sys.path.append(ambari_common_folder + "/src/main/python/jinja2") + sys.path.append(ambari_agent_folder + "/src/main/python") + + stacks_folder = pwd+'/stacks' + #generate test variants(path, service, stack) + test_variants = [] + for stack in os.listdir(stacks_folder): + current_stack_dir = stacks_folder+"/"+stack + if os.path.isdir(current_stack_dir) and stack not in STACK_EXCLUDE: + for service in os.listdir(current_stack_dir): + current_service_dir = current_stack_dir+"/"+service + if os.path.isdir(current_service_dir) and service not in SERVICE_EXCLUDE: + test_variants.append({'directory':current_service_dir, + 'service':service, + 'stack':stack}) + + #run tests for every service in every stack in separate process + has_failures = False + test_runs = 0 + test_failures = [] + test_errors = [] + test_skipped = [] + for variant in test_variants: + executor_result = multiprocessing.Queue() + sys.stderr.write( "Running tests for stack:{0} service:{1}\n" + .format(variant['stack'],variant['service'])) + process = multiprocessing.Process(target=stack_test_executor, + args=(variant['directory'], + variant['service'], + variant['stack'], + custom_tests, + executor_result) + ) + process.start() + process.join() + #for pretty output + sys.stdout.flush() + sys.stderr.flush() + variant_result = executor_result.get() + test_runs += variant_result['tests_run'] + test_errors.extend(variant_result['errors']) + test_failures.extend(variant_result['failures']) + test_skipped.extend(variant_result['skipped']) + + if variant_result['exit_code'] != 0: + has_failures = True + + #run base ambari-server tests + sys.stderr.write("Running tests for ambari-server\n") + if custom_tests: + test_mask = CUSTOM_TEST_MASK + else: + test_mask = TEST_MASK + + tests = get_test_files(pwd, mask=test_mask, recursive=False) + shuffle(tests) + modules = [os.path.basename(s)[:-3] for s in tests] + suites = [unittest.defaultTestLoader.loadTestsFromName(name) for name in + modules] + testSuite = unittest.TestSuite(suites) textRunner = unittest.TextTestRunner(verbosity=2).run(testSuite) - return 0 if textRunner.wasSuccessful() else 1 + test_runs += textRunner.testsRun + test_errors.extend([(str(item[0]),str(item[1]),"ERROR") for item in textRunner.errors]) + test_failures.extend([(str(item[0]),str(item[1]),"FAIL") for item in textRunner.failures]) + test_skipped.extend([(str(item[0]),str(item[1]),"SKIPPED") for item in textRunner.skipped]) + tests_status = textRunner.wasSuccessful() and not has_failures + + if not tests_status: + sys.stderr.write("----------------------------------------------------------------------\n") + sys.stderr.write("Failed tests:\n") + for failed_tests in [test_errors,test_failures,test_skipped]: + for err in failed_tests: + sys.stderr.write("{0}: {1}\n".format(err[2],err[0])) + sys.stderr.write("----------------------------------------------------------------------\n") + sys.stderr.write("{0}\n".format(err[1])) + sys.stderr.write("----------------------------------------------------------------------\n") + sys.stderr.write("Total run:{0}\n".format(test_runs)) + sys.stderr.write("Total errors:{0}\n".format(len(test_errors))) + sys.stderr.write("Total failures:{0}\n".format(len(test_failures))) + sys.stderr.write("Total skipped:{0}\n".format(len(test_skipped))) + + if tests_status: + sys.stderr.write("OK\n") + exit_code = 0 + else: + sys.stderr.write("ERROR\n") + exit_code = 1 + return exit_code if __name__ == "__main__":
