summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--tests/conftest.py2
-rw-r--r--tests/integration/conftest.py22
-rw-r--r--tests/integration/quteprocess.py36
4 files changed, 57 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 1916d4505..e1db4729d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,5 @@ __pycache__
/.cache
/.testmondata
/.hypothesis
+/prof
TODO
diff --git a/tests/conftest.py b/tests/conftest.py
index c6fe8ffc1..29e383996 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -151,6 +151,8 @@ def pytest_addoption(parser):
help='Disable xvfb in tests.')
parser.addoption('--qute-delay', action='store', default=0, type=int,
help="Delay between qutebrowser commands.")
+ parser.addoption('--qute-profile-subprocs', action='store_true',
+ default=False, help="Run cProfile for subprocesses.")
def pytest_configure(config):
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index 5ce524bbb..7bd684daa 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -21,6 +21,28 @@
"""Things needed for integration testing."""
+import os
+import shutil
+import pstats
+
from webserver import httpbin, httpbin_after_test, ssl_server
from quteprocess import quteproc_process, quteproc, quteproc_new
from testprocess import pytest_runtest_makereport
+
+
+def pytest_configure(config):
+ """Remove old profile files."""
+ if config.getoption('--qute-profile-subprocs'):
+ try:
+ shutil.rmtree('prof')
+ except FileNotFoundError:
+ pass
+
+
+def pytest_unconfigure(config):
+ """Combine profiles."""
+ if config.getoption('--qute-profile-subprocs'):
+ stats = pstats.Stats()
+ for fn in os.listdir('prof'):
+ stats.add(os.path.join('prof', fn))
+ stats.dump_stats(os.path.join('prof', 'combined.pstats'))
diff --git a/tests/integration/quteprocess.py b/tests/integration/quteprocess.py
index d27424c53..21f811193 100644
--- a/tests/integration/quteprocess.py
+++ b/tests/integration/quteprocess.py
@@ -28,6 +28,7 @@ import datetime
import logging
import tempfile
import contextlib
+import itertools
import yaml
import pytest
@@ -39,6 +40,9 @@ from qutebrowser.utils import log, utils
from helpers import utils as testutils
+instance_counter = itertools.count()
+
+
def is_ignored_qt_message(message):
"""Check if the message is listed in qt_log_ignore."""
# pylint: disable=no-member
@@ -124,6 +128,9 @@ class QuteProc(testprocess.Process):
basedir: The base directory for this instance.
_focus_ready: Whether the main window got focused.
_load_ready: Whether the about:blank page got loaded.
+ _profile: If True, do profiling of the subprocesses.
+ _instance_id: An unique ID for this QuteProc instance
+ _run_counter: A counter to get an unique ID for each run.
Signals:
got_error: Emitted when there was an error log line.
@@ -134,14 +141,17 @@ class QuteProc(testprocess.Process):
KEYS = ['timestamp', 'loglevel', 'category', 'module', 'function', 'line',
'message']
- def __init__(self, httpbin, delay, parent=None):
+ def __init__(self, httpbin, delay, *, profile=False, parent=None):
super().__init__(parent)
+ self._profile = profile
self._delay = delay
self._httpbin = httpbin
self._ipc_socket = None
self.basedir = None
self._focus_ready = False
self._load_ready = False
+ self._instance_id = next(instance_counter)
+ self._run_counter = itertools.count()
def _is_ready(self, what):
"""Called by _parse_line if loading/focusing is done.
@@ -201,12 +211,28 @@ class QuteProc(testprocess.Process):
def _executable_args(self):
if hasattr(sys, 'frozen'):
+ if self._profile:
+ raise Exception("Can't profile with sys.frozen!")
executable = os.path.join(os.path.dirname(sys.executable),
'qutebrowser')
args = []
else:
executable = sys.executable
- args = ['-m', 'qutebrowser']
+ if self._profile:
+ profile_dir = os.path.join(os.getcwd(), 'prof')
+ profile_id = '{}_{}'.format(self._instance_id,
+ next(self._run_counter))
+ profile_file = os.path.join(profile_dir,
+ '{}.pstats'.format(profile_id))
+ try:
+ os.mkdir(profile_dir)
+ except FileExistsError:
+ pass
+ args = [os.path.join('scripts', 'dev', 'run_profile.py'),
+ '--profile-tool', 'none',
+ '--profile-file', profile_file]
+ else:
+ args = ['-m', 'qutebrowser']
return executable, args
def _default_args(self):
@@ -397,7 +423,8 @@ class QuteProc(testprocess.Process):
def quteproc_process(qapp, httpbin, request):
"""Fixture for qutebrowser process which is started once per file."""
delay = request.config.getoption('--qute-delay')
- proc = QuteProc(httpbin, delay)
+ profile = request.config.getoption('--qute-profile-subprocs')
+ proc = QuteProc(httpbin, delay, profile=profile)
proc.start()
yield proc
proc.terminate()
@@ -416,7 +443,8 @@ def quteproc(quteproc_process, httpbin, request):
def quteproc_new(qapp, httpbin, request):
"""Per-test qutebrowser process to test invocations."""
delay = request.config.getoption('--qute-delay')
- proc = QuteProc(httpbin, delay)
+ profile = request.config.getoption('--qute-profile-subprocs')
+ proc = QuteProc(httpbin, delay, profile=profile)
request.node._quteproc_log = proc.captured_log
# Not calling before_test here as that would start the process
yield proc