class NPMPackage(RequiredTool): def __init__(self, tool_name, package_name, tools_dir, node_tool, npm_tool, parent_logger): super(NPMPackage, self).__init__(tool_name, "") self.package_name = package_name self.tools_dir = tools_dir self.node_tool = node_tool self.npm_tool = npm_tool self.log = parent_logger.getChild(self.__class__.__name__) self.env = Environment(self.log, dict(os.environ)) self.env.add_path({"NODE_PATH": os.path.join(tools_dir, "node_modules")}) def check_if_installed(self): try: node_binary = self.node_tool.executable package = self.package_name cmdline = [node_binary, '-e', "require('%s'); console.log('%s is installed');" % (package, package)] self.log.debug("%s check cmdline: %s", package, cmdline) self.log.debug("NODE_PATH for check: %s", self.env.get("NODE_PATH")) output = subprocess.check_output(cmdline, env=self.env.get(), stderr=subprocess.STDOUT) self.log.debug("%s check output: %s", self.package_name, output) return True except (CalledProcessError, OSError): self.log.debug("%s check failed: %s", self.package_name, traceback.format_exc()) return False def install(self): try: cmdline = [self.npm_tool.executable, 'install', self.package_name, '--prefix', self.tools_dir] output = subprocess.check_output(cmdline, stderr=subprocess.STDOUT) self.log.debug("%s install output: %s", self.tool_name, output) return True except (CalledProcessError, OSError): self.log.debug("%s install failed: %s", self.package_name, traceback.format_exc()) return False
def _load_tasks(self, stage, container): if not isinstance(self.parameters.get(stage, []), list): self.parameters[stage] = [self.parameters[stage]] for index, stage_task in enumerate(self.parameters.get(stage, [])): stage_task = ensure_is_dict(self.parameters[stage], index, "command") task_config = self.parameters[stage][index] default_cwd = self.settings.get("default-cwd", None) cwd = self.engine.find_file(task_config.get("cwd", default_cwd)) if cwd is None: working_dir = self.engine.default_cwd elif cwd == 'artifacts-dir': working_dir = self.engine.artifacts_dir else: working_dir = cwd # make copy of env for every task env = Environment(self.log, self.env.get()) env.set(task_config.get('env')) env.add_path({"PYTHONPATH": working_dir}) task = Task(task_config, self.log, working_dir, env) container.append(task) self.log.debug("Added %s task: %s", stage, stage_task)
class NPMPackage(RequiredTool): def __init__(self, tool_name, package_name, tools_dir, node_tool, npm_tool, parent_logger): super(NPMPackage, self).__init__(tool_name, "") if "@" in package_name: self.package_name, self.version = package_name.split("@") else: self.package_name = package_name self.version = None self.tools_dir = tools_dir self.node_tool = node_tool self.npm_tool = npm_tool self.log = parent_logger.getChild(self.__class__.__name__) self.env = Environment(self.log, dict(os.environ)) self.env.add_path( {"NODE_PATH": os.path.join(tools_dir, "node_modules")}) def check_if_installed(self): try: cmdline = [self.node_tool.executable, "-e"] ok_msg = "%s is installed" % self.package_name cmdline.append("require('%s'); console.log('%s');" % (self.package_name, ok_msg)) self.log.debug("%s check cmdline: %s", self.package_name, cmdline) self.log.debug("NODE_PATH for check: %s", self.env.get("NODE_PATH")) output = sync_run(cmdline, env=self.env.get()) return ok_msg in output except CALL_PROBLEMS: self.log.debug("%s check failed: %s", self.package_name, traceback.format_exc()) return False def install(self): try: package_name = self.package_name if self.version: package_name += "@" + self.version cmdline = [ self.npm_tool.executable, 'install', package_name, '--prefix', self.tools_dir, '--no-save' ] output = sync_run(cmdline) self.log.debug("%s install output: %s", self.tool_name, output) return True except CALL_PROBLEMS: self.log.debug("%s install failed: %s", self.package_name, traceback.format_exc()) return False
def _load_tasks(self, stage, container): if not isinstance(self.parameters.get(stage, []), list): self.parameters[stage] = [self.parameters[stage]] for index, stage_task in enumerate(self.parameters.get(stage, [])): stage_task = ensure_is_dict(self.parameters[stage], index, "command") task_config = self.parameters[stage][index] default_cwd = self.settings.get("default-cwd", None) cwd = self.engine.find_file(task_config.get("cwd", default_cwd)) if cwd is None: working_dir = self.engine.default_cwd elif cwd == 'artifacts-dir': working_dir = self.engine.artifacts_dir else: working_dir = cwd # make copy of env for every task env = Environment(self.log, self.env) env.set(task_config.get('env')) env.add_path({"PYTHONPATH": working_dir}) task = Task(task_config, self.log, working_dir, env) f_name = 'shellexec_%s_%s' % (stage, index) if task.out: task.out = open(task.out, 'at') else: if task.is_background: out = self.engine.create_artifact(f_name, '.out') self.log.debug( 'STDOUT of background task "%s" redirected to "%s"' % (task, out)) task.out = open(out, 'at') else: task.out = PIPE if task.err: task.err = open(task.err, 'at') else: if task.is_background: err = self.engine.create_artifact(f_name, '.err') self.log.debug( 'STDERR of background task "%s" redirected to "%s"' % (task, err)) task.err = open(err, 'at') else: task.err = PIPE container.append(task) self.log.debug("Added %s task: %s", stage, stage_task)
def _load_tasks(self, stage, container): if not isinstance(self.parameters.get(stage, []), list): self.parameters[stage] = [self.parameters[stage]] for index, stage_task in enumerate(self.parameters.get(stage, [])): stage_task = ensure_is_dict(self.parameters[stage], index, "command") task_config = self.parameters[stage][index] default_cwd = self.settings.get("default-cwd", None) cwd = self.engine.find_file(task_config.get("cwd", default_cwd)) if cwd is None: working_dir = self.engine.default_cwd elif cwd == 'artifacts-dir': working_dir = self.engine.artifacts_dir else: working_dir = cwd # make copy of env for every task env = Environment(self.log, self.env) env.set(task_config.get('env')) env.add_path({"PYTHONPATH": working_dir}) task = Task(task_config, self.log, working_dir, env) f_name = 'shellexec_%s_%s' % (stage, index) if task.out: task.out = open(task.out, 'at') else: if task.is_background: out = self.engine.create_artifact(f_name, '.out') self.log.debug('STDOUT of background task "%s" redirected to "%s"' % (task, out)) task.out = open(out, 'at') else: task.out = PIPE if task.err: task.err = open(task.err, 'at') else: if task.is_background: err = self.engine.create_artifact(f_name, '.err') self.log.debug('STDERR of background task "%s" redirected to "%s"' % (task, err)) task.err = open(err, 'at') else: task.err = PIPE container.append(task) self.log.debug("Added %s task: %s", stage, stage_task)
def test_nesting(self): v1 = 'val_param_name' v2 = 'path_param_name' v3 = 'const_val' os.environ[v1] = 'v1.1' os.environ[v2] = 'v1.2' os.environ[v3] = 'v1.3' e1 = Environment() e1.set({v1: 'local_val1.1'}) e1.add_path({v2: 'param_val1.1'}, finish=True) e2 = Environment(parent=e1) e1.add_path({v2: 'param_val1.3'}, finish=True) os.environ[v1] = 'v2.1' os.environ[v2] = 'v2.2' os.environ[v3] = 'v2.3' e1.set({v1: 'local_val1.2'}) e2.add_path({v2: 'param_val1.2'}, finish=True) self.assertEqual(e1.get(v1), 'local_val1.2') self.assertEqual(e2.get(v1), 'local_val1.1') self.assertEqual( e1.get(v2), os.pathsep.join(('v2.2', 'param_val1.1', 'param_val1.3'))) self.assertEqual( e2.get(v2), os.pathsep.join(('v2.2', 'param_val1.1', 'param_val1.2'))) self.assertEqual(e1.get(v3), 'v2.3') self.assertEqual(e2.get(v3), 'v2.3')
def test_nesting(self): v1 = 'val_param_name' v2 = 'path_param_name' v3 = 'const_val' os.environ[v1] = 'v1.1' os.environ[v2] = 'v1.2' os.environ[v3] = 'v1.3' e1 = Environment() e1.set({v1: 'local_val1.1'}) e1.add_path({v2: 'param_val1.1'}, finish=True) e2 = Environment(parent=e1) e1.add_path({v2: 'param_val1.3'}, finish=True) os.environ[v1] = 'v2.1' os.environ[v2] = 'v2.2' os.environ[v3] = 'v2.3' e1.set({v1: 'local_val1.2'}) e2.add_path({v2: 'param_val1.2'}, finish=True) self.assertEqual(e1.get(v1), 'local_val1.2') self.assertEqual(e2.get(v1), 'local_val1.1') self.assertEqual(e1.get(v2), os.pathsep.join(('v2.2', 'param_val1.1', 'param_val1.3'))) self.assertEqual(e2.get(v2), os.pathsep.join(('v2.2', 'param_val1.1', 'param_val1.2'))) self.assertEqual(e1.get(v3), 'v2.3') self.assertEqual(e2.get(v3), 'v2.3')
class SeleniumExecutor(AbstractSeleniumExecutor, WidgetProvider, FileLister, HavingInstallableTools, SelfDiagnosable): """ Selenium executor :type runner: bzt.modules.SubprocessedExecutor """ SUPPORTED_RUNNERS = ["nose", "junit", "testng", "rspec", "mocha", "nunit", "pytest", "wdio", "robot"] SELENIUM_TOOLS_DIR = "~/.bzt/selenium-taurus/tools" def __init__(self): super(SeleniumExecutor, self).__init__() self.end_time = None self.runner = None self.script = None self.runner_working_dir = None self.register_reader = True self.webdrivers = [] def add_env(self, env): # compatibility with taurus-cloud self.env.set(env) def get_runner_working_dir(self): if self.runner_working_dir is None: self.runner_working_dir = self.engine.create_artifact("classes", "") return self.runner_working_dir def subscribe_to_transactions(self, listener): self.runner.subscribe_to_transactions(listener) self.runner.set_source(self) def create_runner(self): runner_type = self.get_runner_type() self.runner = self.engine.instantiate_module(runner_type) self.runner.env = self.env self.runner.parameters = self.parameters self.runner.provisioning = self.provisioning self.runner.execution = copy.deepcopy(self.execution) self.runner.execution['files'] = self.execution.get('files', [], force_set=True) self.runner.execution['executor'] = runner_type self.runner.register_reader = self.register_reader self.runner.settings = self.settings.merge(self.runner.settings) if runner_type == "nose": self.runner.execution["test-mode"] = "selenium" def get_virtual_display(self): pass # for compatibility with taurus server def install_required_tools(self): self.webdrivers = [self._get_tool(ChromeDriver, config=self.settings.get('chromedriver')), self._get_tool(GeckoDriver, config=self.settings.get('geckodriver'))] for tool in self.webdrivers: if not tool.check_if_installed(): self.log.info("Installing %s...", tool.tool_name) tool.install() def prepare(self): if self.env is None: self.env = Environment(self.log, self.engine.env.get()) # for backward compatibility with taurus-server self.install_required_tools() for driver in self.webdrivers: self.env.add_path({"PATH": driver.get_driver_dir()}) if self.get_load().concurrency and self.get_load().concurrency > 1: msg = 'Selenium supports concurrency in cloud provisioning mode only\n' msg += 'For details look at http://gettaurus.org/docs/Cloud.md' self.log.warning(msg) self.create_runner() self.runner.prepare() self.script = self.runner.script def get_runner_type(self): if "runner" in self.execution: runner = self.execution["runner"] if runner not in SeleniumExecutor.SUPPORTED_RUNNERS: msg = "Runner '%s' is not supported. Supported runners: %s" raise TaurusConfigError(msg % (runner, SeleniumExecutor.SUPPORTED_RUNNERS)) self.log.debug("Using script type: %s", runner) return runner script_name = self.get_script_path() if script_name: return self.detect_script_type(script_name) else: if "requests" in self.get_scenario(): return "nose" else: raise TaurusConfigError("You must specify either script or list of requests to run Selenium") def resource_files(self): self.create_runner() return self.runner.resource_files() def detect_script_type(self, script_name): if not os.path.exists(script_name): raise TaurusConfigError("Script '%s' doesn't exist" % script_name) file_types = set() # gather file extensions and choose script_type according to priority if os.path.isfile(script_name): # regular file received file_types.add(os.path.splitext(script_name)[1].lower()) else: # dir received: check contained files for file_name in get_files_recursive(script_name): file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types or '.jar' in file_types: # todo: next detection logic is duplicated in TestNGTester - can we avoid it? script_dir = get_full_path(self.get_script_path(), step_up=1) if os.path.exists(os.path.join(script_dir, 'testng.xml')) or self.execution.get('testng-xml'): script_type = 'testng' else: script_type = 'junit' elif '.py' in file_types: script_type = 'nose' elif '.rb' in file_types: script_type = 'rspec' elif '.js' in file_types: script_type = 'mocha' elif '.dll' in file_types or '.exe' in file_types: script_type = 'nunit' else: if os.path.isfile(script_name): message = "Unsupported script type: %r" % script_name else: message = "Directory %r doesn't contain supported scripts" % script_name raise TaurusConfigError(message) self.log.debug("Detected script type: %s", script_type) return script_type def startup(self): """ Start runner :return: """ self.start_time = time.time() self.runner.startup() def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() return self.runner.check() def report_test_duration(self): if self.start_time: self.end_time = time.time() self.log.debug("Selenium tests ran for %s seconds", self.end_time - self.start_time) def shutdown(self): """ shutdown test_runner :return: """ self.runner.shutdown() self.report_test_duration() def post_process(self): self.runner.post_process() if os.path.exists("geckodriver.log"): self.engine.existing_artifact("geckodriver.log", True) def has_results(self): return self.runner.has_results() def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.script, self.runner.stdout_file) return self.widget def get_error_diagnostics(self): diagnostics = [] if self.runner: diagnostics.extend(self.runner.get_error_diagnostics()) gecko_logs = ["geckodriver.log", os.path.join(self.engine.artifacts_dir, "geckodriver.log")] for possible_log in gecko_logs: if os.path.exists(possible_log): with open(possible_log) as fds: diagnostics.append("Geckodriver log:\n" + fds.read()) return diagnostics
class SeleniumExecutor(AbstractSeleniumExecutor, WidgetProvider, FileLister, HavingInstallableTools, SelfDiagnosable): """ Selenium executor :type runner: bzt.modules.SubprocessedExecutor """ SUPPORTED_RUNNERS = [ "nose", "junit", "testng", "rspec", "mocha", "nunit", "pytest", "wdio", "robot" ] SELENIUM_TOOLS_DIR = "~/.bzt/selenium-taurus/tools" def __init__(self): super(SeleniumExecutor, self).__init__() self.end_time = None self.runner = None self.script = None self.runner_working_dir = None self.register_reader = True self.webdrivers = [] def add_env(self, env): # compatibility with taurus-cloud self.env.set(env) def get_runner_working_dir(self): if self.runner_working_dir is None: self.runner_working_dir = self.engine.create_artifact( "classes", "") return self.runner_working_dir def subscribe_to_transactions(self, listener): self.runner.subscribe_to_transactions(listener) self.runner.set_source(self) def create_runner(self): runner_type = self.get_runner_type() self.runner = self.engine.instantiate_module(runner_type) self.runner.env = self.env self.runner.parameters = self.parameters self.runner.provisioning = self.provisioning self.runner.execution = copy.deepcopy(self.execution) self.runner.execution['files'] = self.execution.get('files', [], force_set=True) self.runner.execution['executor'] = runner_type self.runner.register_reader = self.register_reader self.runner.settings = self.settings.merge(self.runner.settings) if runner_type == "nose": self.runner.execution["test-mode"] = "selenium" def get_virtual_display(self): pass # for compatibility with taurus server def install_required_tools(self): self.webdrivers = [ self._get_tool(ChromeDriver, config=self.settings.get('chromedriver')), self._get_tool(GeckoDriver, config=self.settings.get('geckodriver')) ] for tool in self.webdrivers: if not tool.check_if_installed(): self.log.info("Installing %s...", tool.tool_name) tool.install() def prepare(self): if self.env is None: self.env = Environment(self.log, self.engine.env.get( )) # for backward compatibility with taurus-server self.install_required_tools() for driver in self.webdrivers: self.env.add_path({"PATH": driver.get_driver_dir()}) if self.get_load().concurrency and self.get_load().concurrency > 1: msg = 'Selenium supports concurrency in cloud provisioning mode only\n' msg += 'For details look at http://gettaurus.org/docs/Cloud.md' self.log.warning(msg) self.create_runner() self.runner.prepare() self.script = self.runner.script def get_runner_type(self): if "runner" in self.execution: runner = self.execution["runner"] if runner not in SeleniumExecutor.SUPPORTED_RUNNERS: msg = "Runner '%s' is not supported. Supported runners: %s" raise TaurusConfigError( msg % (runner, SeleniumExecutor.SUPPORTED_RUNNERS)) self.log.debug("Using script type: %s", runner) return runner script_name = self.get_script_path() if script_name: return self.detect_script_type(script_name) else: if "requests" in self.get_scenario(): return "nose" else: raise TaurusConfigError( "You must specify either script or list of requests to run Selenium" ) def resource_files(self): self.create_runner() return self.runner.resource_files() def detect_script_type(self, script_name): if not os.path.exists(script_name): raise TaurusConfigError("Script '%s' doesn't exist" % script_name) file_types = set() # gather file extensions and choose script_type according to priority if os.path.isfile(script_name): # regular file received file_types.add(os.path.splitext(script_name)[1].lower()) else: # dir received: check contained files for file_name in get_files_recursive(script_name): file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types or '.jar' in file_types: # todo: next detection logic is duplicated in TestNGTester - can we avoid it? script_dir = get_full_path(self.get_script_path(), step_up=1) if os.path.exists(os.path.join( script_dir, 'testng.xml')) or self.execution.get('testng-xml'): script_type = 'testng' else: script_type = 'junit' elif '.py' in file_types: script_type = 'nose' elif '.rb' in file_types: script_type = 'rspec' elif '.js' in file_types: script_type = 'mocha' elif '.dll' in file_types or '.exe' in file_types: script_type = 'nunit' else: if os.path.isfile(script_name): message = "Unsupported script type: %r" % script_name else: message = "Directory %r doesn't contain supported scripts" % script_name raise TaurusConfigError(message) self.log.debug("Detected script type: %s", script_type) return script_type def startup(self): """ Start runner :return: """ self.start_time = time.time() self.runner.startup() def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() return self.runner.check() def report_test_duration(self): if self.start_time: self.end_time = time.time() self.log.debug("Selenium tests ran for %s seconds", self.end_time - self.start_time) def shutdown(self): """ shutdown test_runner :return: """ self.runner.shutdown() self.report_test_duration() def post_process(self): self.runner.post_process() if os.path.exists("geckodriver.log"): self.engine.existing_artifact("geckodriver.log", True) def has_results(self): return self.runner.has_results() def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.script, self.runner.stdout_file) return self.widget def get_error_diagnostics(self): diagnostics = [] if self.runner: diagnostics.extend(self.runner.get_error_diagnostics()) gecko_logs = [ "geckodriver.log", os.path.join(self.engine.artifacts_dir, "geckodriver.log") ] for possible_log in gecko_logs: if os.path.exists(possible_log): with open(possible_log) as fds: diagnostics.append("Geckodriver log:\n" + fds.read()) return diagnostics
class SeleniumExecutor(AbstractSeleniumExecutor, WidgetProvider, FileLister, HavingInstallableTools, SelfDiagnosable): """ Selenium executor :type runner: bzt.modules.SubprocessedExecutor """ SUPPORTED_RUNNERS = ["nose", "junit", "testng", "rspec", "mocha", "nunit", "pytest", "wdio", "robot"] CHROMEDRIVER_DOWNLOAD_LINK = "https://chromedriver.storage.googleapis.com/{version}/chromedriver_{arch}.zip" CHROMEDRIVER_VERSION = "2.33" GECKODRIVER_DOWNLOAD_LINK = "https://github.com/mozilla/geckodriver/releases/download/v{version}/" \ "geckodriver-v{version}-{arch}.{ext}" GECKODRIVER_VERSION = "0.19.0" SELENIUM_TOOLS_DIR = get_full_path("~/.bzt/selenium-taurus/tools") def __init__(self): super(SeleniumExecutor, self).__init__() self.end_time = None self.runner = None self.script = None self.runner_working_dir = None self.register_reader = True self.webdrivers = [] def add_env(self, env): # compatibility with taurus-server self.env.set(env) def get_runner_working_dir(self): if self.runner_working_dir is None: self.runner_working_dir = self.engine.create_artifact("classes", "") return self.runner_working_dir def create_runner(self): runner_type = self.get_runner_type() self.runner = self.engine.instantiate_module(runner_type) self.runner.env = self.env self.runner.parameters = self.parameters self.runner.provisioning = self.provisioning self.runner.execution = copy.deepcopy(self.execution) self.runner.execution['files'] = self.execution.get('files', [], force_set=True) self.runner.execution['executor'] = runner_type self.runner.register_reader = self.register_reader if runner_type == "nose": self.runner.execution["test-mode"] = "selenium" def get_virtual_display(self): pass # for compatibility with taurus server def _get_chromedriver_link(self): settings = self.settings.get('chromedriver') link = settings.get('download-link', SeleniumExecutor.CHROMEDRIVER_DOWNLOAD_LINK) version = settings.get('version', SeleniumExecutor.CHROMEDRIVER_VERSION) if is_windows(): arch = 'win32' # no 64-bit windows builds, :( elif is_mac(): arch = 'mac64' else: arch = 'linux32' if platform_bitness() == 32 else 'linux64' return link.format(version=version, arch=arch) def _get_chromedriver_path(self): base_dir = get_full_path(SeleniumExecutor.SELENIUM_TOOLS_DIR) settings = self.settings.get('chromedriver') version = settings.get('version', SeleniumExecutor.CHROMEDRIVER_VERSION) filename = 'chromedriver.exe' if is_windows() else 'chromedriver' return os.path.join(base_dir, 'chromedriver', version, filename) def _get_geckodriver_link(self): settings = self.settings.get('geckodriver') link = settings.get('download-link', SeleniumExecutor.GECKODRIVER_DOWNLOAD_LINK) version = settings.get('version', SeleniumExecutor.GECKODRIVER_VERSION) if is_windows(): arch = 'win64' # no 32-bit windows builds, :( ext = 'zip' elif is_mac(): arch = 'macos' ext = 'tar.gz' else: arch = 'linux32' if platform_bitness() == 32 else 'linux64' ext = 'tar.gz' return link.format(version=version, arch=arch, ext=ext) def _get_geckodriver_path(self): base_dir = get_full_path(SeleniumExecutor.SELENIUM_TOOLS_DIR) settings = self.settings.get('geckodriver') version = settings.get('version', SeleniumExecutor.GECKODRIVER_VERSION) filename = 'geckodriver.exe' if is_windows() else 'geckodriver' return os.path.join(base_dir, 'geckodriver', version, filename) def install_required_tools(self): chromedriver_path = self._get_chromedriver_path() chromedriver_link = self._get_chromedriver_link() geckodriver_path = self._get_geckodriver_path() geckodriver_link = self._get_geckodriver_link() self.webdrivers = [ChromeDriver(chromedriver_path, self.log, chromedriver_link), GeckoDriver(geckodriver_path, self.log, geckodriver_link)] for tool in self.webdrivers: if not tool.check_if_installed(): self.log.info("Installing %s...", tool.tool_name) tool.install() def prepare(self): if self.env is None: self.env = Environment(self.log, self.engine.env.get()) # for backward compatibility with taurus-server self.install_required_tools() for driver in self.webdrivers: self.env.add_path({"PATH": driver.get_driver_dir()}) if self.get_load().concurrency and self.get_load().concurrency > 1: msg = 'Selenium supports concurrency in cloud provisioning mode only\n' msg += 'For details look at http://gettaurus.org/docs/Cloud.md' self.log.warning(msg) self.create_runner() self.runner.prepare() self.script = self.runner.script def get_runner_type(self): if "runner" in self.execution: runner = self.execution["runner"] if runner not in SeleniumExecutor.SUPPORTED_RUNNERS: msg = "Runner '%s' is not supported. Supported runners: %s" raise TaurusConfigError(msg % (runner, SeleniumExecutor.SUPPORTED_RUNNERS)) self.log.debug("Using script type: %s", runner) return runner script_name = self.get_script_path() if script_name: return self.detect_script_type(script_name) else: if "requests" in self.get_scenario(): return "nose" else: raise TaurusConfigError("You must specify either script or list of requests to run Selenium") def resource_files(self): self.create_runner() return self.runner.resource_files() def detect_script_type(self, script_name): if not os.path.exists(script_name): raise TaurusConfigError("Script '%s' doesn't exist" % script_name) file_types = set() # gather file extensions and choose script_type according to priority if os.path.isfile(script_name): # regular file received file_types.add(os.path.splitext(script_name)[1].lower()) else: # dir received: check contained files for file_name in get_files_recursive(script_name): file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types or '.jar' in file_types: # todo: next detection logic is duplicated in TestNGTester - can we avoid it? script_dir = get_full_path(self.get_script_path(), step_up=1) if os.path.exists(os.path.join(script_dir, 'testng.xml')) or self.execution.get('testng-xml'): script_type = 'testng' else: script_type = 'junit' elif '.py' in file_types: script_type = 'nose' elif '.rb' in file_types: script_type = 'rspec' elif '.js' in file_types: script_type = 'mocha' elif '.dll' in file_types or '.exe' in file_types: script_type = 'nunit' else: if os.path.isfile(script_name): message = "Unsupported script type: %r" % script_name else: message = "Directory %r doesn't contain supported scripts" % script_name raise TaurusConfigError(message) self.log.debug("Detected script type: %s", script_type) return script_type def startup(self): """ Start runner :return: """ self.start_time = time.time() self.runner.startup() def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() return self.runner.check() def report_test_duration(self): if self.start_time: self.end_time = time.time() self.log.debug("Selenium tests ran for %s seconds", self.end_time - self.start_time) def shutdown(self): """ shutdown test_runner :return: """ self.runner.shutdown() self.report_test_duration() def post_process(self): self.runner.post_process() if os.path.exists("geckodriver.log"): self.engine.existing_artifact("geckodriver.log", True) def has_results(self): return self.runner.has_results() def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.script, self.runner.stdout_file) return self.widget def get_error_diagnostics(self): diagnostics = [] if self.runner: diagnostics.extend(self.runner.get_error_diagnostics()) gecko_logs = ["geckodriver.log", os.path.join(self.engine.artifacts_dir, "geckodriver.log")] for possible_log in gecko_logs: if os.path.exists(possible_log): with open(possible_log) as fds: diagnostics.append("Geckodriver log:\n" + fds.read()) return diagnostics
class AppiumLoader(Service): def __init__(self): super(AppiumLoader, self).__init__() self.env = Environment(log=self.log) self.appium_process = None self.tool_path = '' self.tools_dir = "~/.bzt/selenium-taurus/appium-server" self.default_path = None self.startup_timeout = None self.addr = '' self.port = '' self.stdout = None self.stderr = None self.appium_python = None self.appium_server = None def prepare(self): self.startup_timeout = self.settings.get('timeout', 30) self.addr = self.settings.get('addr', '127.0.0.1') self.port = self.settings.get('port', 4723) self.tool_path = self.settings.get('path', 'appium') self.tools_dir = get_full_path( self.settings.get("tools-dir", self.tools_dir)) self.default_path = os.path.join(self.tools_dir, "node_modules/.bin/appium") self.env.add_path( {"NODE_PATH": os.path.join(self.tools_dir, "node_modules")}) self.install_required_tools() def install_required_tools(self): node = Node(env=self.env, log=self.log) npm = NPM(env=self.env, log=self.log) self.appium_python = AppiumPython(engine=self.engine, settings=self.settings, log=self.log) self.appium_server = AppiumServer(path=self.tool_path, def_path=self.default_path, tools_dir=self.tools_dir, node_tool=node, npm_tool=npm) required_tools = [ node, npm, JavaVM(log=self.log), self.appium_python, self.appium_server ] for tool in required_tools: if not tool.check_if_installed(): tool.install() def startup(self): self.log.debug('Starting Appium...') self.stdout = open( os.path.join(self.engine.artifacts_dir, 'appium.out'), 'wt') self.stderr = open( os.path.join(self.engine.artifacts_dir, 'appium.err'), 'wt') self.appium_process = shell_exec( [self.appium_server.tool_path, "--log-no-colors"], stdout=self.stdout, stderr=self.stderr) start_time = time.time() while not self.tool_is_started(): time.sleep(1) if time.time() - start_time > self.startup_timeout: raise ToolError("Appium cannot be loaded") self.log.info('Appium was started successfully') def tool_is_started(self): try: response = urlopen("http://%s:%s%s" % (self.addr, self.port, '/wd/hub/sessions')) resp_str = response.read() if not isinstance(resp_str, str): resp_str = resp_str.decode() return isinstance(json.loads(resp_str), dict) except (URLError, ValueError): return False def shutdown(self): if self.appium_process: self.log.debug('Stopping appium...') shutdown_process(self.appium_process, self.log) if not self.stdout.closed: self.stdout.close() if not self.stderr.closed: self.stderr.close() _file = self.stdout.name if not os.stat(_file).st_size: os.remove(_file) _file = self.stderr.name if not os.stat(_file).st_size: os.remove(_file) def post_process(self): self.appium_python.post_process()