| #!/usr/bin/env python2.7 |
| # -*- encoding: utf-8 -*- |
| |
| # 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. |
| |
| """ main.py """ |
| import getpass |
| import json |
| import logging |
| import os |
| import pkgutil |
| import time |
| import socket |
| import subprocess |
| import sys |
| from collections import namedtuple |
| |
| from ..common import status |
| from heron.common.src.python.utils import log |
| |
| # import test_kill_bolt |
| import test_kill_metricsmgr |
| import test_kill_stmgr |
| import test_kill_stmgr_metricsmgr |
| import test_kill_tmaster |
| import test_scale_up |
| import test_template |
| |
| TEST_CLASSES = [ |
| test_template.TestTemplate, |
| test_kill_tmaster.TestKillTMaster, |
| test_kill_stmgr.TestKillStmgr, |
| test_kill_metricsmgr.TestKillMetricsMgr, |
| test_kill_stmgr_metricsmgr.TestKillStmgrMetricsMgr, |
| test_scale_up.TestScaleUp, |
| # test_kill_bolt.TestKillBolt, |
| ] |
| |
| # The location of default configure file |
| DEFAULT_TEST_CONF_FILE = "integration_test/src/python/local_test_runner/resources/test.conf" |
| |
| ProcessTuple = namedtuple('ProcessTuple', 'pid cmd') |
| |
| def run_tests(test_classes, args): |
| """ Run the test for each topology specified in the conf file """ |
| successes = [] |
| failures = [] |
| tracker_process = _start_tracker(args['trackerPath'], args['trackerPort']) |
| |
| try: |
| for test_class in test_classes: |
| testname = test_class.__name__ |
| logging.info("==== Starting test %s of %s: %s ====", |
| len(successes) + len(failures) + 1, len(test_classes), testname) |
| template = test_class(testname, args) |
| try: |
| result = template.run_test() |
| if isinstance(result, status.TestSuccess): # testcase passed |
| successes += [testname] |
| elif isinstance(result, status.TestFailure): |
| failures += [testname] |
| else: |
| logging.error( |
| "Unrecognized test response returned for test %s: %s", testname, str(result)) |
| failures += [testname] |
| except status.TestFailure: |
| failures += [testname] |
| |
| except Exception as e: |
| logging.error("Exception thrown while running tests: %s", str(e)) |
| finally: |
| tracker_process.kill() |
| |
| return successes, failures |
| |
| def _start_tracker(tracker_path, tracker_port): |
| splitcmd = [tracker_path, '--verbose', '--port=%s' % tracker_port] |
| |
| logging.info("Starting heron tracker: %s", splitcmd) |
| popen = subprocess.Popen(splitcmd) |
| logging.info("Successfully started heron tracker on port %s", tracker_port) |
| return popen |
| |
| def _random_port(): |
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| s.bind(("", 0)) |
| s.listen(1) |
| port = s.getsockname()[1] |
| s.close() |
| return port |
| |
| def main(): |
| """ main """ |
| log.configure(level=logging.DEBUG) |
| |
| # Read the configuration file from package |
| conf_file = DEFAULT_TEST_CONF_FILE |
| conf_string = pkgutil.get_data(__name__, conf_file) |
| decoder = json.JSONDecoder(strict=False) |
| |
| # Convert the conf file to a json format |
| conf = decoder.decode(conf_string) |
| |
| args = dict() |
| home_directory = os.path.expanduser("~") |
| args['cluster'] = conf['cluster'] |
| args['topologyName'] = conf['topology']['topologyName'] |
| args['topologyClassPath'] = conf['topology']['topologyClassPath'] |
| args['workingDirectory'] = os.path.join( |
| home_directory, |
| ".herondata", |
| "topologies", |
| conf['cluster'], |
| getpass.getuser(), |
| args['topologyName'] |
| ) |
| args['cliPath'] = os.path.expanduser(conf['heronCliPath']) |
| args['trackerPath'] = os.path.expanduser(conf['heronTrackerPath']) |
| args['trackerPort'] = _random_port() |
| args['outputFile'] = os.path.join(args['workingDirectory'], conf['topology']['outputFile']) |
| args['readFile'] = os.path.join(args['workingDirectory'], conf['topology']['readFile']) |
| args['testJarPath'] = conf['testJarPath'] |
| |
| test_classes = TEST_CLASSES |
| if len(sys.argv) > 1: |
| first_arg = sys.argv[1] |
| class_tokens = first_arg.split(".") |
| if first_arg == "-h" or len(class_tokens) < 2: |
| usage() |
| |
| import importlib |
| package_tokens = class_tokens[:-1] |
| test_class = class_tokens[-1] |
| if len(package_tokens) == 1: # prepend base packages for convenience |
| test_module = "integration_test.src.python.local_test_runner." + package_tokens[0] |
| else: |
| test_module = '.'.join(package_tokens) |
| |
| logging.info("test_module %s", test_module) |
| logging.info("test_class %s", test_class) |
| test_classes = [getattr(importlib.import_module(test_module), test_class)] |
| |
| start_time = time.time() |
| (successes, failures) = run_tests(test_classes, args) |
| elapsed_time = time.time() - start_time |
| total = len(failures) + len(successes) |
| |
| if not failures: |
| logging.info("Success: %s (all) tests passed", len(successes)) |
| logging.info("Elapsed time: %s", elapsed_time) |
| sys.exit(0) |
| else: |
| logging.error("Fail: %s/%s test failed:", len(failures), total) |
| for test in failures: |
| logging.error(" - %s", test) |
| sys.exit(1) |
| |
| def usage(): |
| logging.info("Usage: python %s [<test_module>.<testname>]", sys.argv[0]) |
| sys.exit(1) |
| |
| if __name__ == '__main__': |
| main() |