Blazemeter / taurus
Showing 6 of 89 files from the diff.
Other files ignored by Codecov
requirements.txt has changed.
Dockerfile has changed.

@@ -16,14 +16,15 @@
Loading
16 16
limitations under the License.
17 17
"""
18 18
import os
19 +
import shutil
19 20
from math import ceil
20 21
21 22
from bzt import ToolError
22 23
from bzt.engine import ScenarioExecutor
23 24
from bzt.modules.aggregator import ConsolidatingAggregator, ResultsReader
24 25
from bzt.modules.console import ExecutorWidget
25 -
from bzt.modules.services import PythonTool
26 -
from bzt.utils import unicode_decode, CALL_PROBLEMS
26 +
from bzt.modules.services import RequiredTool
27 +
from bzt.utils import unicode_decode
27 28
from bzt.utils import shutdown_process, dehumanize_time, get_full_path, LDJSONReader
28 29
29 30
@@ -51,8 +52,7 @@
Loading
51 52
            self.engine.aggregator.add_underling(self.reader)
52 53
53 54
    def install_required_tools(self):
54 -
        self.molotov = self._get_tool(Molotov, engine=self.engine, settings=self.settings,
55 -
                                      path=self.settings.get('path', None))
55 +
        self.molotov = self._get_tool(Molotov, path=self.settings.get('path', None))
56 56
        if not self.molotov.check_if_installed():
57 57
            self.molotov.install()
58 58
@@ -113,10 +113,6 @@
Loading
113 113
    def shutdown(self):
114 114
        shutdown_process(self.process, self.log)
115 115
116 -
    def post_process(self):
117 -
        self.molotov.post_process()
118 -
        super(MolotovExecutor, self).post_process()
119 -
120 116
    def get_error_diagnostics(self):
121 117
        diagnostics = []
122 118
        if self.stdout is not None:
@@ -135,11 +131,10 @@
Loading
135 131
        return [self.get_script_path(required=True)]
136 132
137 133
138 -
class Molotov(PythonTool):
139 -
    def __init__(self, engine, settings, path, **kwargs):
140 -
        super(Molotov, self).__init__(packages=["molotov"], engine=engine, settings=settings, **kwargs)
141 -
        self.tool_path = os.path.join(self.tool_path, "bin", self.tool_name.lower())
142 -
        self.user_tool_path = path
134 +
class Molotov(RequiredTool):
135 +
    def __init__(self, path=None, **kwargs):
136 +
        super(Molotov, self).__init__(installable=False, **kwargs)
137 +
        self.tool_path = path or shutil.which(self.tool_name.lower())
143 138
144 139
145 140
class MolotovReportReader(ResultsReader):

@@ -116,7 +116,8 @@
Loading
116 116
117 117
class Robot(PythonTool):
118 118
    def __init__(self, engine, settings, **kwargs):
119 -
        super(Robot, self).__init__(packages=["robotframework", "apiritif"], engine=engine, settings=settings, **kwargs)
119 +
        robot_packages = ["robotframework", "apiritif", "robotframework-seleniumlibrary"]
120 +
        super(Robot, self).__init__(packages=robot_packages, engine=engine, settings=settings, **kwargs)
120 121
121 122
122 123
class TaurusRobotRunner(RequiredTool):

@@ -18,13 +18,15 @@
Loading
18 18
import time
19 19
from abc import abstractmethod
20 20
21 +
from webdriver_manager.chrome import ChromeDriverManager
22 +
from webdriver_manager.firefox import GeckoDriverManager
21 23
from urwid import Text, Pile
24 +
from requests.exceptions import ConnectionError
22 25
23 26
from bzt import TaurusConfigError, ToolError
24 27
from bzt.modules import ReportableExecutor
25 28
from bzt.modules.console import PrioritizedWidget
26 -
from bzt.utils import get_files_recursive, get_full_path, RequiredTool, unzip, untar
27 -
from bzt.utils import is_windows, is_mac, platform_bitness
29 +
from bzt.utils import get_files_recursive, get_full_path, RequiredTool, is_windows
28 30
29 31
30 32
class AbstractSeleniumExecutor(ReportableExecutor):
@@ -83,8 +85,8 @@
Loading
83 85
        pass  # for compatibility with taurus server
84 86
85 87
    def install_required_tools(self):
86 -
        self.webdrivers = [self._get_tool(ChromeDriver, config=self.settings.get('chromedriver')),
87 -
                           self._get_tool(GeckoDriver, config=self.settings.get('geckodriver'))]
88 +
        self.webdrivers = [self._get_tool(ChromeDriver, tool_path=self.settings.get('chromedriver').get('path')),
89 +
                           self._get_tool(GeckoDriver, tool_path=self.settings.get('geckodriver').get('path'))]
88 90
89 91
        for tool in self.webdrivers:
90 92
            if not tool.check_if_installed():
@@ -254,108 +256,64 @@
Loading
254 256
255 257
256 258
class ChromeDriver(RequiredTool):
257 -
    DOWNLOAD_LINK = "https://chromedriver.storage.googleapis.com/{version}/chromedriver_{arch}.zip"
258 -
    VERSION = "93.0.4577.63"
259 259
260 -
    def __init__(self, config=None, **kwargs):
261 -
        settings = config or {}
262 -
        version = str(settings.get('version', self.VERSION))
260 +
    def __init__(self, tool_path="", log=None, **kwargs):
261 +
        self.webdriver_manager = None
262 +
        self.log = log
263 263
        base_dir = get_full_path(SeleniumExecutor.SELENIUM_TOOLS_DIR)
264 264
        filename = 'chromedriver.exe' if is_windows() else 'chromedriver'
265 -
        tool_path = os.path.join(base_dir, 'chromedriver', version, filename)
266 -
267 -
        link = settings.get('download-link', self.DOWNLOAD_LINK)
268 -
269 -
        if is_windows():
270 -
            arch = 'win32'  # no 64-bit windows builds, :(
271 -
        elif is_mac():
272 -
            arch = 'mac64'
273 -
        else:
274 -
            arch = 'linux32' if platform_bitness() == 32 else 'linux64'
275 -
        link = link.format(version=version, arch=arch)
276 -
277 -
        super(ChromeDriver, self).__init__(tool_path=tool_path, version=version, download_link=link, **kwargs)
278 -
279 -
    def check_if_installed(self):
280 -
        return os.path.exists(self.tool_path)
265 +
        if not tool_path:
266 +
            try:
267 +
                self.webdriver_manager = ChromeDriverManager(path=base_dir, print_first_line=False)
268 +
                tool_path = os.path.join(base_dir,
269 +
                                         'drivers/chromedriver',
270 +
                                         self.webdriver_manager.driver.get_os_type(),
271 +
                                         f'{self.webdriver_manager.driver.get_version()}',
272 +
                                         filename)
273 +
            except (ValueError, ConnectionError) as err:
274 +
                tool_path = os.path.join(base_dir, 'drivers/chromedriver', filename)
275 +
                self.log.warning(err)
276 +
        super().__init__(tool_path=tool_path, installable=False, mandatory=False, **kwargs)
281 277
282 278
    def get_driver_dir(self):
283 279
        return get_full_path(self.tool_path, step_up=1)
284 280
285 281
    def install(self):
286 -
        dest = self.get_driver_dir()
287 -
        if not os.path.exists(dest):
288 -
            os.makedirs(dest)
282 +
        if self.webdriver_manager:
283 +
            self.log.info(f"Will install {self.tool_name} into {self.tool_path}")
289 284
290 -
        self.log.info("Will install %s into %s", self.tool_name, dest)
291 -
        dist = self._download(use_link=True)
292 -
        try:
293 -
            self.log.info("Unzipping %s to %s", dist, dest)
294 -
            unzip(dist, dest)
295 -
        finally:
296 -
            os.remove(dist)
297 -
298 -
        if not is_windows():
299 -
            os.chmod(self.tool_path, 0o755)
300 -
301 -
        if not self.check_if_installed():
302 -
            raise ToolError("Unable to find %s after installation!" % self.tool_name)
285 +
            self.webdriver_manager.install()
286 +
        else:
287 +
            super().install()
303 288
304 289
305 290
class GeckoDriver(RequiredTool):
306 -
    DOWNLOAD_LINK = \
307 -
        "https://github.com/mozilla/geckodriver/releases/download/v{version}/geckodriver-v{version}-{arch}.{ext}"
308 -
    VERSION = "0.29.1"
309 291
310 -
    def __init__(self, config=None, **kwargs):
311 -
        settings = config or {}
312 -
        version = str(settings.get('version', self.VERSION))
292 +
    def __init__(self, tool_path="", log=None, **kwargs):
293 +
        self.webdriver_manager = None
294 +
        self.log = log
313 295
        base_dir = get_full_path(SeleniumExecutor.SELENIUM_TOOLS_DIR)
314 296
        filename = 'geckodriver.exe' if is_windows() else 'geckodriver'
315 -
        tool_path = os.path.join(base_dir, 'geckodriver', version, filename)
316 -
317 -
        link = settings.get('download-link', self.DOWNLOAD_LINK)
318 -
319 -
        if is_windows():
320 -
            arch = 'win64'  # no 32-bit windows builds, :(
321 -
            ext = 'zip'
322 -
        elif is_mac():
323 -
            arch = 'macos'
324 -
            ext = 'tar.gz'
325 -
        else:
326 -
            arch = 'linux32' if platform_bitness() == 32 else 'linux64'
327 -
            ext = 'tar.gz'
328 -
        link = link.format(version=version, arch=arch, ext=ext)
329 -
330 -
        super(GeckoDriver, self).__init__(tool_path=tool_path, version=version, download_link=link, **kwargs)
331 -
332 -
    def check_if_installed(self):
333 -
        return os.path.exists(self.tool_path)
297 +
        if not tool_path:
298 +
            try:
299 +
                self.webdriver_manager = GeckoDriverManager(path=base_dir, print_first_line=False)
300 +
                tool_path = os.path.join(base_dir,
301 +
                                         'drivers/geckodriver',
302 +
                                         self.webdriver_manager.driver.get_os_type(),
303 +
                                         f'{self.webdriver_manager.driver.get_version()}',
304 +
                                         filename)
305 +
            except (ValueError, ConnectionError) as err:
306 +
                tool_path = os.path.join(base_dir, 'drivers/geckodriver', filename)
307 +
                self.log.warning(err)
308 +
        super().__init__(tool_path=tool_path, installable=False, mandatory=False, **kwargs)
334 309
335 310
    def get_driver_dir(self):
336 311
        return get_full_path(self.tool_path, step_up=1)
337 312
338 313
    def install(self):
339 -
        dest = self.get_driver_dir()
340 -
        if not os.path.exists(dest):
341 -
            os.makedirs(dest)
342 -
343 -
        self.log.info("Will install %s into %s", self.tool_name, dest)
344 -
        dist = self._download(use_link=True)
345 -
        try:
346 -
            if self.download_link.endswith('.zip'):
347 -
                self.log.info("Unzipping %s to %s", dist, dest)
348 -
                unzip(dist, dest)
349 -
            else:
350 -
                self.log.info("Untaring %s to %s", dist, dest)
351 -
                untar(dist, dest)
352 -
        finally:
353 -
            os.remove(dist)
354 -
355 -
        if not is_windows():
356 -
            os.chmod(self.tool_path, 0o755)
314 +
        if self.webdriver_manager:
315 +
            self.log.info(f"Will install {self.tool_name} into {self.tool_path}")
357 316
358 -
        if not self.check_if_installed():
359 -
            raise ToolError("Unable to find %s after installation!" % self.tool_name)
360 -
361 -
        # TODO: check for compatible browser versions?
317 +
            self.webdriver_manager.install()
318 +
        else:
319 +
            super().install()

@@ -81,6 +81,7 @@
Loading
81 81
        self.packages = self.parameters.get("packages", self.packages)
82 82
        if not self.packages:
83 83
            return
84 +
        self.versions = self.parameters.get("versions", self.versions)
84 85
85 86
        # install into artifacts dir if temp, otherwise into .bzt
86 87
        self.temp = self.settings.get("temp", self.temp)
@@ -122,13 +123,14 @@
Loading
122 123
            return
123 124
        if "Successfully installed" in out:
124 125
            self.log.info(out.split("\n")[-2])
125 -
            if "WARNING" in err:
126 -
                for warning in err.split("\n"):
127 -
                    if warning.startswith('WARNING'):
128 -
                        self.log.warning(" ".join(warning.split(" ")[1:]))
129 -
        else:
130 -
            self.log.error("pip-installer stderr:\n%s" % err)
126 +
            for err_line in err.split("\n"):
127 +
                if err_line.startswith('WARNING'):
128 +
                    self.log.warning(" ".join(err_line.split(" ")[1:]))
129 +
                if err_line.startswith('ERROR'):
130 +
                    self.log.error(" ".join(err_line.split(" ")[1:]))
131 131
        self.log.debug("pip-installer stdout: \n%s" % out)
132 +
        if err:
133 +
            self.log.debug("pip-installer stderr:\n%s" % err)
132 134
133 135
    def post_process(self):
134 136
        # might be forbidden on win as tool still work
@@ -142,13 +144,12 @@
Loading
142 144
    def __init__(self, packages, engine, settings, **kwargs):
143 145
        tool_path = engine.temp_pythonpath
144 146
        super(PythonTool, self).__init__(tool_path=tool_path, **kwargs)
145 -
146 -
        temp_flag = settings.get("temp", True)
147 147
        version = settings.get("version", None)
148 -
        self.installer = PipInstaller(packages=packages, temp_flag=temp_flag)
148 +
        self.installer = PipInstaller(temp_flag=False)
149 149
        self.installer.engine = engine
150 +
        self.installer.parameters = BetterDict.from_dict({'packages': packages})
150 151
        if version:
151 -
            self.installer.versions[packages[0]] = version
152 +
            self.installer.parameters["versions"] = {packages[0]: version}
152 153
153 154
    def check_if_installed(self):
154 155
        self.log.debug(f"Checking {self.tool_name}.")
@@ -233,7 +234,6 @@
Loading
233 234
            return
234 235
235 236
        self.log.info("Checking installation needs for: %s", mod_name)
236 -
        mod.settings.get("temp", default=False, force_set=True)
237 237
        mod.install_required_tools()
238 238
        self.log.info("Module is fine: %s", mod_name)
239 239

@@ -27,7 +27,7 @@
Loading
27 27
28 28
from bzt.utils import numeric_types, Environment, RequiredTool, PIPE, SoapUIScriptConverter
29 29
from bzt.utils import to_json, BetterDict, ensure_is_dict, dehumanize_time
30 -
30 +
from bzt.environment_helpers import expand_envs_with_os
31 31
from .dicts import Scenario
32 32
from .names import EXEC, SCENARIO
33 33
from .templates import HavingInstallableTools
@@ -428,7 +428,7 @@
Loading
428 428
429 429
    def prepare(self):
430 430
        super(ScenarioExecutor, self).prepare()
431 -
        self.env.set(self.execution.get("env"))
431 +
        self.env.set(expand_envs_with_os(self.execution.get("env")))
432 432
433 433
    def get_widget(self):
434 434
        """

@@ -259,7 +259,7 @@
Loading
259 259
260 260
261 261
class Apiritif(PythonTool):
262 -
    VERSION = "0.9.8"
262 +
    VERSION = "1.0.0"
263 263
264 264
    def __init__(self, engine, settings, **kwargs):
265 265
        if not settings.get("version", None):
Files Coverage
bzt 90.33%
Project Totals (69 files) 90.33%
9537.2
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
1
codecov:
2
  notify:
3
    require_ci_to_pass: yes
4

5
coverage:
6
  round: up
7

8
ignore:
9
  - bzt/resources
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading