class VirtualDisplay(Service, Singletone): """ Selenium executor :type virtual_display: Display """ SHARED_VIRTUAL_DISPLAY = {} def __init__(self): super(VirtualDisplay, self).__init__() self.virtual_display = None def get_virtual_display(self): return self.virtual_display def set_virtual_display(self): if is_windows(): self.log.warning( "Cannot have virtual display on Windows, ignoring") else: if self.engine in VirtualDisplay.SHARED_VIRTUAL_DISPLAY: self.virtual_display = VirtualDisplay.SHARED_VIRTUAL_DISPLAY[ self.engine] else: width = self.parameters.get("width", 1024) height = self.parameters.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() VirtualDisplay.SHARED_VIRTUAL_DISPLAY[ self.engine] = self.virtual_display def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if self.engine in VirtualDisplay.SHARED_VIRTUAL_DISPLAY: del VirtualDisplay.SHARED_VIRTUAL_DISPLAY[self.engine] def startup(self): self.set_virtual_display() def check_virtual_display(self): if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise TaurusInternalException("Virtual display failed: %s" % self.virtual_display.return_code) def check(self): self.check_virtual_display() return False def shutdown(self): self.free_virtual_display()
class VirtualDisplay(Service, Singletone): """ Selenium executor :type virtual_display: Display """ SHARED_VIRTUAL_DISPLAY = None def __init__(self): super(VirtualDisplay, self).__init__() self.virtual_display = None def get_virtual_display(self): return self.virtual_display def set_virtual_display(self): if is_windows(): self.log.warning("Cannot have virtual display on Windows, ignoring") return if VirtualDisplay.SHARED_VIRTUAL_DISPLAY: self.virtual_display = VirtualDisplay.SHARED_VIRTUAL_DISPLAY else: width = self.parameters.get("width", 1024) height = self.parameters.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() VirtualDisplay.SHARED_VIRTUAL_DISPLAY = self.virtual_display self.engine.shared_env.set({'DISPLAY': os.environ['DISPLAY']}) # backward compatibility def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if VirtualDisplay.SHARED_VIRTUAL_DISPLAY: VirtualDisplay.SHARED_VIRTUAL_DISPLAY = None def startup(self): self.set_virtual_display() def check_virtual_display(self): if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise TaurusInternalException("Virtual display failed: %s" % self.virtual_display.return_code) def check(self): self.check_virtual_display() return False def shutdown(self): self.free_virtual_display()
class SeleniumExecutor(ScenarioExecutor, WidgetProvider, FileLister): """ Selenium executor :type virtual_display: Display :type runner: AbstractTestRunner """ SELENIUM_DOWNLOAD_LINK = "http://selenium-release.storage.googleapis.com/{version}/" \ "selenium-server-standalone-{version}.0.jar" SELENIUM_VERSION = "2.53" JUNIT_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=junit/junit/{version}/junit-{version}.jar" JUNIT_VERSION = "4.12" JUNIT_MIRRORS_SOURCE = "http://search.maven.org/solrsearch/select?q=g%3A%22junit%22%20AND%20a%3A%22junit%22%20" \ "AND%20v%3A%22{version}%22&rows=20&wt=json".format(version=JUNIT_VERSION) HAMCREST_DOWNLOAD_LINK = "https://hamcrest.googlecode.com/files/hamcrest-core-1.3.jar" SUPPORTED_TYPES = [".py", ".jar", ".java"] SHARED_VIRTUAL_DISPLAY = {} def __init__(self): super(SeleniumExecutor, self).__init__() self.additional_env = {} self.virtual_display = None self.start_time = None self.end_time = None self.runner = None self.widget = None self.reader = None self.kpi_file = None self.err_jtl = None self.runner_working_dir = None self.scenario = None def set_virtual_display(self): display_conf = self.settings.get("virtual-display") if display_conf: if is_windows(): self.log.warning("Cannot have virtual display on Windows, ignoring") else: if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: self.virtual_display = SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] else: width = display_conf.get("width", 1024) height = display_conf.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] = self.virtual_display def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: del SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] def _get_script_path(self): script = self.scenario.get(Scenario.SCRIPT) if not script: return None return self.engine.find_file(script) def prepare(self): self.set_virtual_display() self.scenario = self.get_scenario() self._verify_script() self.kpi_file = self.engine.create_artifact("selenium_tests_report", ".csv") self.err_jtl = self.engine.create_artifact("selenium_tests_err", ".xml") script_path = self._get_script_path() script_type = self.detect_script_type(script_path) runner_config = BetterDict() if script_type == ".py": runner_class = NoseTester runner_config.merge(self.settings.get("selenium-tools").get("nose")) else: # script_type == ".jar" or script_type == ".java": runner_class = JUnitTester runner_config.merge(self.settings.get("selenium-tools").get("junit")) runner_config['props-file'] = self.engine.create_artifact("customrunner", ".properties") runner_config["script-type"] = script_type if self.runner_working_dir is None: self.runner_working_dir = self.engine.create_artifact(runner_config.get("working-dir", "classes"), "") runner_config["working-dir"] = self.runner_working_dir runner_config.get("artifacts-dir", self.engine.artifacts_dir) runner_config.get("working-dir", self.runner_working_dir) runner_config.get("report-file", self.kpi_file) runner_config.get("err-file", self.err_jtl) runner_config.get("stdout", self.engine.create_artifact("junit", ".out")) runner_config.get("stderr", self.engine.create_artifact("junit", ".err")) self._cp_resource_files(self.runner_working_dir) self.runner = runner_class(runner_config, self) self.runner.prepare() self.reader = JTLReader(self.kpi_file, self.log, self.err_jtl) if isinstance(self.engine.aggregator, ConsolidatingAggregator): self.engine.aggregator.add_underling(self.reader) def _verify_script(self): if not self.scenario.get(Scenario.SCRIPT): if self.scenario.get("requests"): self.scenario[Scenario.SCRIPT] = self.__tests_from_requests() else: raise RuntimeError("Nothing to test, no requests were provided in scenario") def _cp_resource_files(self, runner_working_dir): """ :return: """ script = self._get_script_path() if script is not None: if os.path.isdir(script): shutil.copytree(script, runner_working_dir) else: os.makedirs(runner_working_dir) shutil.copy2(script, runner_working_dir) @staticmethod def detect_script_type(script_path): """ checks if script is java or python if it's folder or single script :param script_path: str :return: """ if not isinstance(script_path, string_types) and not isinstance(script_path, text_type): raise ValueError("Nothing to test, no files were provided in scenario") if not os.path.exists(script_path): raise ValueError("Script %s doesn't exist" % script_path) file_types = set() if os.path.isfile(script_path): # regular file received file_types.add(os.path.splitext(script_path)[1].lower()) else: # dir received: check files for walk_rec in os.walk(script_path): for file_name in walk_rec[2]: file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types: file_ext = '.java' elif '.py' in file_types: file_ext = '.py' elif '.jar' in file_types: file_ext = '.jar' else: raise ValueError("Unsupported script type: %s" % script_path) return file_ext def startup(self): """ Start runner :return: """ self.start_time = time.time() self.runner.env = self.additional_env self.runner.run_tests() def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise RuntimeError("Virtual display failed: %s" % self.virtual_display.return_code) return self.runner.is_finished() def shutdown(self): """ shutdown test_runner :return: """ self.runner.shutdown() 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 post_process(self): self.free_virtual_display() if self.reader and not self.reader.read_records: raise RuntimeWarning("Empty results, most likely Selenium failed") def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.scenario.get(Scenario.SCRIPT), self.runner.settings.get("stdout")) return self.widget def resource_files(self): if not self.scenario: self.scenario = self.get_scenario() if Scenario.SCRIPT not in self.scenario: return [] script_path = self._get_script_path() if os.path.isdir(script_path): files = next(os.walk(script_path)) resources = [os.path.join(files[0], f) for f in files[2]] else: resources = [script_path] return resources def __tests_from_requests(self): filename = self.engine.create_artifact("test_requests", ".py") nose_test = SeleniumScriptBuilder(self.scenario, self.log) if self.virtual_display: nose_test.window_size = self.virtual_display.size nose_test.gen_test_case() nose_test.save(filename) return filename
class SeleniumExecutor(ScenarioExecutor, WidgetProvider, FileLister): """ Selenium executor :type virtual_display: Display :type runner: AbstractTestRunner """ SELENIUM_DOWNLOAD_LINK = "http://selenium-release.storage.googleapis.com/{version}/" \ "selenium-server-standalone-{version}.0.jar" SELENIUM_VERSION = "2.53" JUNIT_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=junit/junit/" \ "{version}/junit-{version}.jar" JUNIT_VERSION = "4.12" JUNIT_MIRRORS_SOURCE = "http://search.maven.org/solrsearch/select?q=g%3A%22junit%22%20AND%20a%3A%22" \ "junit%22%20AND%20v%3A%22{version}%22&rows=20&wt=json".format(version=JUNIT_VERSION) HAMCREST_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=org/hamcrest/hamcrest-core" \ "/1.3/hamcrest-core-1.3.jar" JSON_JAR_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=org/json/json/20160810/json-20160810.jar" SUPPORTED_TYPES = [".py", ".jar", ".java"] SHARED_VIRTUAL_DISPLAY = {} def __init__(self): super(SeleniumExecutor, self).__init__() self.additional_env = {} self.virtual_display = None self.end_time = None self.runner = None self.reader = None self.report_file = None self.runner_working_dir = None self.scenario = None self.script = None self.self_generated_script = False self.generated_methods = BetterDict() def set_virtual_display(self): display_conf = self.settings.get("virtual-display") if display_conf: if is_windows(): self.log.warning( "Cannot have virtual display on Windows, ignoring") else: if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: self.virtual_display = SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[ self.engine] else: width = display_conf.get("width", 1024) height = display_conf.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[ self.engine] = self.virtual_display def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: del SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] def get_script_path(self, scenario=None): if scenario: return super(SeleniumExecutor, self).get_script_path(scenario) else: return self.engine.find_file(self.script) def _create_runner(self, working_dir, report_file): script_path = self.get_script_path() script_type = self.detect_script_type(script_path) runner_config = BetterDict() if script_type == ".py": runner_class = NoseTester runner_config.merge( self.settings.get("selenium-tools").get("nose")) else: # script_type == ".jar" or script_type == ".java": runner_class = JUnitTester runner_config.merge( self.settings.get("selenium-tools").get("junit")) runner_config['props-file'] = self.engine.create_artifact( "customrunner", ".properties") runner_config["script-type"] = script_type runner_config["working-dir"] = working_dir runner_config.get("artifacts-dir", self.engine.artifacts_dir) runner_config.get("report-file", report_file) runner_config.get("stdout", self.engine.create_artifact("junit", ".out")) runner_config.get("stderr", self.engine.create_artifact("junit", ".err")) return runner_class(runner_config, self) def _create_reader(self, report_file): return LoadSamplesReader(report_file, self.log, self.generated_methods) def prepare(self): self.set_virtual_display() self.scenario = self.get_scenario() self._verify_script() self.runner_working_dir = self.engine.create_artifact("classes", "") self.report_file = self.engine.create_artifact("selenium_tests_report", ".ldjson") self.runner = self._create_runner(self.runner_working_dir, self.report_file) self._cp_resource_files(self.runner_working_dir) self.runner.prepare() self.reader = self._create_reader(self.report_file) if isinstance(self.engine.aggregator, ConsolidatingAggregator): self.engine.aggregator.add_underling(self.reader) def _verify_script(self): if Scenario.SCRIPT in self.scenario and self.scenario.get( Scenario.SCRIPT): self.script = self.scenario.get(Scenario.SCRIPT) elif "requests" in self.scenario: self.script = self.__tests_from_requests() self.self_generated_script = True else: raise ValueError( "Nothing to test, no requests were provided in scenario") def _cp_resource_files(self, runner_working_dir): script = self.get_script_path() if os.path.isdir(script): shutil.copytree(script, runner_working_dir) else: os.makedirs(runner_working_dir) if self.self_generated_script: shutil.move(script, runner_working_dir) else: script_type = self.detect_script_type(script) script_name = os.path.basename(script) if script_type == ".py" and not script_name.lower().startswith( 'test'): target_name = 'test_' + script_name msg = "Script '%s' won't be discovered by nosetests, renaming script to %s" self.log.warning(msg, script_name, target_name) else: target_name = script_name target_path = os.path.join(runner_working_dir, target_name) shutil.copy2(script, target_path) @staticmethod def detect_script_type(script_path): if not isinstance(script_path, string_types) and not isinstance( script_path, text_type): raise ValueError( "Nothing to test, no files were provided in scenario") if not os.path.exists(script_path): raise ValueError("Script %s doesn't exist" % script_path) file_types = set() if os.path.isfile(script_path): # regular file received file_types.add(os.path.splitext(script_path)[1].lower()) else: # dir received: check contained files for file_name in get_files_recursive(script_path): file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types: file_ext = '.java' elif '.py' in file_types: file_ext = '.py' elif '.jar' in file_types: file_ext = '.jar' else: raise ValueError("Unsupported script type: %s" % script_path) return file_ext def startup(self): """ Start runner :return: """ self.start_time = time.time() self.runner.env = self.additional_env self.runner.run_tests() def check_virtual_display(self): if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise RuntimeError("Virtual display failed: %s" % self.virtual_display.return_code) def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() self.check_virtual_display() return self.runner.is_finished() 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.free_virtual_display() if self.reader and not self.reader.read_records: raise RuntimeWarning("Empty results, most likely Selenium failed") def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.script, self.runner.settings.get("stdout")) return self.widget def resource_files(self): self.scenario = self.get_scenario() self._verify_script() script_path = self.get_script_path() resources = [] if script_path is not None: resources.append(script_path) return resources def __tests_from_requests(self): filename = self.engine.create_artifact("test_requests", ".py") wdlog = self.engine.create_artifact('webdriver', '.log') nose_test = SeleniumScriptBuilder(self.scenario, self.log, wdlog) if self.virtual_display: nose_test.window_size = self.virtual_display.size self.generated_methods.merge(nose_test.gen_test_case()) nose_test.save(filename) return filename
class SeleniumExecutor(AbstractSeleniumExecutor, WidgetProvider, FileLister): """ Selenium executor :type virtual_display: Display :type runner: SubprocessedExecutor """ SUPPORTED_RUNNERS = ["nose", "junit", "testng", "rspec", "mocha"] def __init__(self): super(SeleniumExecutor, self).__init__() self.additional_env = {} self.virtual_display = None self.end_time = None self.runner = None self.report_file = None self.scenario = None self.script = None self.generated_methods = BetterDict() self.runner_working_dir = None self.register_reader = True def get_virtual_display(self): return self.virtual_display def add_env(self, env): self.additional_env.update(env) def set_virtual_display(self): display_conf = self.settings.get("virtual-display") if display_conf: if is_windows(): self.log.warning("Cannot have virtual display on Windows, ignoring") else: if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: self.virtual_display = SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] else: width = display_conf.get("width", 1024) height = display_conf.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] = self.virtual_display def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: del SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] 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 _get_testng_xml(self): if 'testng-xml' in self.scenario: testng_xml = self.scenario.get('testng-xml') if testng_xml: return testng_xml else: return None # empty value for switch off testng.xml path autodetect script_path = self.get_script_path() if script_path: script_dir = get_full_path(script_path, step_up=1) testng_xml = os.path.join(script_dir, 'testng.xml') if os.path.exists(testng_xml): self.log.info("Detected testng.xml file at %s", testng_xml) self.scenario['testng-xml'] = testng_xml return testng_xml return None def _create_runner(self, report_file): script_type = self.detect_script_type() runner = self.engine.instantiate_module(script_type) runner.parameters = self.parameters runner.provisioning = self.provisioning runner.execution = self.execution runner.execution['executor'] = script_type if script_type == "nose": runner.generated_methods = self.generated_methods runner.execution["test-mode"] = "selenium" elif script_type == "junit": pass elif script_type == "testng": testng_config = self._get_testng_xml() if testng_config: runner.execution['testng-xml'] = self.engine.find_file(testng_config) elif script_type == "rspec": pass elif script_type == "mocha": pass else: raise TaurusConfigError("Unsupported script type: %s" % script_type) runner.execution["report-file"] = report_file # TODO: shouldn't it be the field? return runner def _register_reader(self, report_file): if self.engine.is_functional_mode(): reader = FuncSamplesReader(report_file, self.engine, self.log, self.generated_methods) if isinstance(self.engine.aggregator, FunctionalAggregator): self.engine.aggregator.add_underling(reader) else: reader = LoadSamplesReader(report_file, self.log, self.generated_methods) if isinstance(self.engine.aggregator, ConsolidatingAggregator): self.engine.aggregator.add_underling(reader) return reader def prepare(self): 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.set_virtual_display() self.scenario = self.get_scenario() self.script = self.get_script_path() self.report_file = self.engine.create_artifact("selenium_tests_report", ".ldjson") self.runner = self._create_runner(self.report_file) self.runner.prepare() if isinstance(self.runner, NoseTester): self.script = self.runner._script if self.register_reader: self.reader = self._register_reader(self.report_file) def detect_script_type(self): if not self.script and "requests" in self.scenario: return "nose" if not os.path.exists(self.script): raise TaurusConfigError("Script '%s' doesn't exist" % self.script) 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 file_types = set() if os.path.isfile(self.script): # regular file received file_types.add(os.path.splitext(self.script)[1].lower()) else: # dir received: check contained files for file_name in get_files_recursive(self.script): file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types or '.jar' in file_types: if self._get_testng_xml() is not None: 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' else: raise TaurusConfigError("Unsupported script type: %s" % self.script) 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.env = self.additional_env self.runner.startup() def check_virtual_display(self): if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise TaurusInternalException("Virtual display failed: %s" % self.virtual_display.return_code) def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() self.check_virtual_display() 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): if os.path.exists("geckodriver.log"): self.engine.existing_artifact("geckodriver.log", True) self.free_virtual_display() def has_results(self): if self.reader and self.reader.read_records: return True else: return False def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.script, self.runner._stdout_file) return self.widget def resource_files(self): resources = [] self.scenario = self.get_scenario() script = self.scenario.get(Scenario.SCRIPT, None) if script: resources.append(script) resources.extend(self.scenario.get("additional-classpath", [])) resources.extend(self.settings.get("additional-classpath", [])) testng_config = self._get_testng_xml() if testng_config: resources.append(testng_config) return resources
class SeleniumExecutor(ScenarioExecutor, WidgetProvider, FileLister): """ Selenium executor :type virtual_display: Display :type runner: AbstractTestRunner """ SELENIUM_DOWNLOAD_LINK = "http://selenium-release.storage.googleapis.com/{version}/" \ "selenium-server-standalone-{version}.0.jar" SELENIUM_VERSION = "2.53" JUNIT_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=junit/junit/" \ "{version}/junit-{version}.jar" JUNIT_VERSION = "4.12" JUNIT_MIRRORS_SOURCE = "http://search.maven.org/solrsearch/select?q=g%3A%22junit%22%20AND%20a%3A%22" \ "junit%22%20AND%20v%3A%22{version}%22&rows=20&wt=json".format(version=JUNIT_VERSION) HAMCREST_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=org/hamcrest/hamcrest-core" \ "/1.3/hamcrest-core-1.3.jar" JSON_JAR_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=org/json/json/20160810/json-20160810.jar" SUPPORTED_TYPES = ["python-nose", "java-junit", "ruby-rspec"] SHARED_VIRTUAL_DISPLAY = {} def __init__(self): super(SeleniumExecutor, self).__init__() self.additional_env = {} self.virtual_display = None self.end_time = None self.runner = None self.report_file = None self.scenario = None self.script = None self.self_generated_script = False self.generated_methods = BetterDict() self.runner_working_dir = None def set_virtual_display(self): display_conf = self.settings.get("virtual-display") if display_conf: if is_windows(): self.log.warning("Cannot have virtual display on Windows, ignoring") else: if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: self.virtual_display = SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] else: width = display_conf.get("width", 1024) height = display_conf.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] = self.virtual_display def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: del SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] def get_script_path(self, scenario=None): if scenario: return super(SeleniumExecutor, self).get_script_path(scenario) else: return self.engine.find_file(self.script) 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, report_file): script_path = self.get_script_path() script_type = self.detect_script_type(script_path) runner_config = BetterDict() if script_type == "python-nose": runner_class = NoseTester runner_config.merge(self.settings.get("selenium-tools").get("nose")) elif script_type == "java-junit": runner_class = JUnitTester runner_config.merge(self.settings.get("selenium-tools").get("junit")) runner_config['working-dir'] = self.get_runner_working_dir() runner_config['props-file'] = self.engine.create_artifact("customrunner", ".properties") elif script_type == "ruby-rspec": runner_class = RSpecTester elif script_type == "js-mocha": runner_class = MochaTester else: raise ValueError("Unsupported script type: %s" % script_type) runner_config["script"] = script_path runner_config["script-type"] = script_type runner_config["artifacts-dir"] = self.engine.artifacts_dir runner_config["report-file"] = report_file runner_config["stdout"] = self.engine.create_artifact("selenium", ".out") runner_config["stderr"] = self.engine.create_artifact("selenium", ".err") return runner_class(runner_config, self) def _register_reader(self, report_file): if self.engine.is_functional_mode(): reader = FuncSamplesReader(report_file, self.log, self.generated_methods) if isinstance(self.engine.aggregator, FunctionalAggregator): self.engine.aggregator.add_underling(reader) else: reader = LoadSamplesReader(report_file, self.log, self.generated_methods) if isinstance(self.engine.aggregator, ConsolidatingAggregator): self.engine.aggregator.add_underling(reader) return reader def prepare(self): self.set_virtual_display() self.scenario = self.get_scenario() self.__setup_script() self.report_file = self.engine.create_artifact("selenium_tests_report", ".ldjson") self.runner = self._create_runner(self.report_file) self.runner.prepare() self.reader = self._register_reader(self.report_file) def __setup_script(self): if Scenario.SCRIPT in self.scenario and self.scenario.get(Scenario.SCRIPT): self.script = self.scenario.get(Scenario.SCRIPT) elif "requests" in self.scenario: self.script = self.__tests_from_requests() self.self_generated_script = True else: raise ValueError("Nothing to test, no requests were provided in scenario") def detect_script_type(self, script_path): if not isinstance(script_path, string_types) and not isinstance(script_path, text_type): raise ValueError("Nothing to test, no files were provided in scenario") if not os.path.exists(script_path): raise ValueError("Script %s doesn't exist" % script_path) if "language" in self.execution: lang = self.execution["language"] if lang not in self.SUPPORTED_TYPES: tmpl = "Language '%s' is not supported. Supported languages are: %s" raise ValueError(tmpl % (lang, self.SUPPORTED_TYPES)) self.log.debug("Using script type: %s", lang) return lang file_types = set() if os.path.isfile(script_path): # regular file received file_types.add(os.path.splitext(script_path)[1].lower()) else: # dir received: check contained files for file_name in get_files_recursive(script_path): file_types.add(os.path.splitext(file_name)[1].lower()) if '.java' in file_types or '.jar' in file_types: script_type = 'java-junit' elif '.py' in file_types: script_type = 'python-nose' elif '.rb' in file_types: script_type = 'ruby-rspec' elif '.js' in file_types: script_type = 'js-mocha' else: raise ValueError("Unsupported script type: %s" % script_path) 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.env = self.additional_env self.runner.run_tests() def check_virtual_display(self): if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise RuntimeError("Virtual display failed: %s" % self.virtual_display.return_code) def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() self.check_virtual_display() return self.runner.is_finished() 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.free_virtual_display() def has_results(self): if self.reader and self.reader.read_records: return True else: return False def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.script, self.runner.settings.get("stdout")) return self.widget def resource_files(self): self.scenario = self.get_scenario() self.__setup_script() script_path = self.get_script_path() resources = [] if script_path is not None: resources.append(script_path) return resources def __tests_from_requests(self): filename = self.engine.create_artifact("test_requests", ".py") wdlog = self.engine.create_artifact('webdriver', '.log') nose_test = SeleniumScriptBuilder(self.scenario, self.log, wdlog) if self.virtual_display: nose_test.window_size = self.virtual_display.size self.generated_methods.merge(nose_test.build_source_code()) nose_test.save(filename) return filename
class SeleniumExecutor(AbstractSeleniumExecutor, WidgetProvider, FileLister): """ Selenium executor :type virtual_display: Display :type runner: SubprocessedExecutor """ SUPPORTED_RUNNERS = ["nose", "junit", "testng", "rspec", "mocha"] def __init__(self): super(SeleniumExecutor, self).__init__() self.additional_env = {} self.virtual_display = None self.end_time = None self.runner = None self.script = None self.generated_methods = BetterDict() self.runner_working_dir = None def get_virtual_display(self): return self.virtual_display def add_env(self, env): self.additional_env.update(env) def set_virtual_display(self): display_conf = self.settings.get("virtual-display") if display_conf: if is_windows(): self.log.warning( "Cannot have virtual display on Windows, ignoring") else: if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: self.virtual_display = SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[ self.engine] else: width = display_conf.get("width", 1024) height = display_conf.get("height", 768) self.virtual_display = Display(size=(width, height)) msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[ self.engine] = self.virtual_display def free_virtual_display(self): if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() if self.engine in SeleniumExecutor.SHARED_VIRTUAL_DISPLAY: del SeleniumExecutor.SHARED_VIRTUAL_DISPLAY[self.engine] 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) # todo: deprecated, remove it later self.runner.settings.merge( self.settings.get('selenium-tools').get(runner_type)) self.runner.parameters = self.parameters self.runner.provisioning = self.provisioning self.runner.execution = self.execution self.runner.execution['executor'] = runner_type if runner_type == "nose": self.runner.execution["test-mode"] = "selenium" def prepare(self): 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.set_virtual_display() 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', None): 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' else: raise TaurusConfigError( "Supported script files not found, script detection is failed") 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.env = self.additional_env self.runner.startup() def check_virtual_display(self): if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise TaurusInternalException("Virtual display failed: %s" % self.virtual_display.return_code) def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() self.check_virtual_display() 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): if os.path.exists("geckodriver.log"): self.engine.existing_artifact("geckodriver.log", True) self.free_virtual_display() 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
class SeleniumExecutor(ScenarioExecutor, WidgetProvider, FileLister): """ Selenium executor :type virtual_display: Display """ SELENIUM_DOWNLOAD_LINK = "http://selenium-release.storage.googleapis.com/{version}/" \ "selenium-server-standalone-{version}.0.jar" SELENIUM_VERSION = "2.48" JUNIT_DOWNLOAD_LINK = "http://search.maven.org/remotecontent?filepath=junit/junit/{version}/junit-{version}.jar" JUNIT_VERSION = "4.12" JUNIT_MIRRORS_SOURCE = "http://search.maven.org/solrsearch/select?q=g%3A%22junit%22%20AND%20a%3A%22junit%22%20" \ "AND%20v%3A%22{version}%22&rows=20&wt=json".format(version=JUNIT_VERSION) HAMCREST_DOWNLOAD_LINK = "https://hamcrest.googlecode.com/files/hamcrest-core-1.3.jar" SUPPORTED_TYPES = [".py", ".jar", ".java"] def __init__(self): super(SeleniumExecutor, self).__init__() self.virtual_display = None self.start_time = None self.end_time = None self.runner = None self.widget = None self.reader = None self.kpi_file = None self.err_jtl = None self.runner_working_dir = None self.scenario = None def prepare(self): display_conf = self.settings.get("virtual-display") if display_conf: if is_windows(): self.log.warning("Cannot have virtual display on Windows, ignoring") else: width = display_conf.get("width", 1024) height = display_conf.get("height", 768) self.virtual_display = Display(size=(width, height)) self.scenario = self.get_scenario() self._verify_script() self.kpi_file = self.engine.create_artifact("selenium_tests_report", ".csv") self.err_jtl = self.engine.create_artifact("selenium_tests_err", ".xml") script_type = self.detect_script_type(self.scenario.get(Scenario.SCRIPT)) if script_type == ".py": runner_class = NoseTester runner_config = self.settings.get("selenium-tools").get("nose") elif script_type == ".jar" or script_type == ".java": runner_class = JUnitTester runner_config = self.settings.get("selenium-tools").get("junit") runner_config['props-file'] = self.engine.create_artifact("customrunner", ".properties") else: raise ValueError("Unsupported script type: %s" % script_type) runner_config["script-type"] = script_type self.runner_working_dir = self.engine.create_artifact(runner_config.get("working-dir", "classes"), "") runner_config["working-dir"] = self.runner_working_dir runner_config.get("artifacts-dir", self.engine.artifacts_dir) runner_config.get("working-dir", self.runner_working_dir) runner_config.get("report-file", self.kpi_file) runner_config.get("err-file", self.err_jtl) runner_config.get("stdout", self.engine.create_artifact("junit", ".out")) runner_config.get("stderr", self.engine.create_artifact("junit", ".err")) self._cp_resource_files(self.runner_working_dir) self.runner = runner_class(runner_config, self.scenario, self.get_load(), self.log) self.runner.prepare() self.reader = JTLReader(self.kpi_file, self.log, self.err_jtl) if isinstance(self.engine.aggregator, ConsolidatingAggregator): self.engine.aggregator.add_underling(self.reader) def _verify_script(self): if not self.scenario.get("script"): if self.scenario.get("requests"): self.scenario["script"] = self.__tests_from_requests() else: raise RuntimeError("Nothing to test, no requests were provided in scenario") def _cp_resource_files(self, runner_working_dir): """ :return: """ script = self.scenario.get("script") if Scenario.SCRIPT in self.scenario: if os.path.isdir(script): shutil.copytree(script, runner_working_dir) else: os.makedirs(runner_working_dir) shutil.copy2(script, runner_working_dir) def detect_script_type(self, script_path): """ checks if script is java or python if it's folder or single script :return: """ if not isinstance(script_path, string_types) and not isinstance(script_path, text_type): raise RuntimeError("Nothing to test, no files were provided in scenario") test_files = [] for dir_entry in os.walk(script_path): if dir_entry[2]: for test_file in dir_entry[2]: if os.path.splitext(test_file)[1].lower() in SeleniumExecutor.SUPPORTED_TYPES: test_files.append(test_file) if os.path.isdir(script_path): file_ext = os.path.splitext(test_files[0])[1].lower() else: file_ext = os.path.splitext(script_path)[1] if file_ext not in SeleniumExecutor.SUPPORTED_TYPES: raise RuntimeError("Supported tests types %s was not found" % SeleniumExecutor.SUPPORTED_TYPES) return file_ext def startup(self): """ Start runner :return: """ self.start_time = time.time() if self.virtual_display: msg = "Starting virtual display[%s]: %s" self.log.info(msg, self.virtual_display.size, self.virtual_display.new_display_var) self.virtual_display.start() self.runner.run_tests() def check(self): """ check if test completed :return: """ if self.widget: self.widget.update() if self.virtual_display: if not self.virtual_display.is_alive(): self.log.info("Virtual display out: %s", self.virtual_display.stdout) self.log.warning("Virtual display err: %s", self.virtual_display.stderr) raise RuntimeError("Virtual display failed: %s" % self.virtual_display.return_code) return self.runner.is_finished() def shutdown(self): """ shutdown test_runner :return: """ try: self.runner.shutdown() finally: if self.virtual_display and self.virtual_display.is_alive(): self.virtual_display.stop() 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 post_process(self): if self.reader and not self.reader.read_records: raise RuntimeWarning("Empty results, most likely Selenium failed") def get_widget(self): if not self.widget: self.widget = SeleniumWidget(self.scenario.get("script"), self.runner.settings.get("stdout")) return self.widget def resource_files(self): if not self.scenario: self.scenario = self.get_scenario() if "script" not in self.scenario: return [] script = self.scenario.get("script") script_type = self.detect_script_type(script) if script_type == ".py": runner_config = self.settings.get("selenium-tools").get("nose") elif script_type == ".jar" or script_type == ".java": runner_config = self.settings.get("selenium-tools").get("junit") else: raise ValueError("Unsupported script type: %s" % script_type) if self.runner_working_dir is None: self.runner_working_dir = self.engine.create_artifact(runner_config.get("working-dir", "classes"), "") self._cp_resource_files(self.runner_working_dir) return [os.path.basename(self.runner_working_dir)] def __tests_from_requests(self): filename = self.engine.create_artifact("test_requests", ".py") nose_test = SeleniumScriptBuilder(self.scenario, self.log) if self.virtual_display: nose_test.window_size=self.virtual_display.size nose_test.scenario = self.scenario nose_test.gen_test_case() nose_test.save(filename) return filename