File: test_browser.py

package info (click to toggle)
cockpit 355-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 311,568 kB
  • sloc: javascript: 774,787; python: 40,655; ansic: 35,157; cpp: 11,141; sh: 3,512; makefile: 580; xml: 261
file content (122 lines) | stat: -rw-r--r-- 3,996 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import contextlib
import glob
import os
import re
import subprocess
from collections.abc import AsyncIterator

import lcov
import pytest
from js_coverage import CoverageReport
from webdriver_bidi import ChromiumBidi
from yarl import URL

SRCDIR = os.path.realpath(f'{__file__}/../../..')
BUILDDIR = os.environ.get('abs_builddir', SRCDIR)

SKIP = {
    'base1/test-dbus-address.html',
}

XFAIL = {
    'base1/test-websocket.html',
}


@contextlib.asynccontextmanager
async def spawn_test_server() -> AsyncIterator[URL]:  # noqa:RUF029
    if 'COVERAGE_RCFILE' in os.environ:
        coverage = ['coverage', 'run', '--parallel-mode', '--module']
    else:
        coverage = []

    # pass the address through a separate fd, so that we can see g_debug() messages (which go to stdout)
    addr_r, addr_w = os.pipe()
    try:
        server = subprocess.Popen(
            [f'{BUILDDIR}/test-server', 'python3', '-m', *coverage, 'cockpit.bridge'],
            env={**os.environ, 'TEST_SERVER_ADDRESS_FD': f'{addr_w}'},
            stdin=subprocess.DEVNULL, pass_fds=(addr_w,), close_fds=True
        )
    except FileNotFoundError:
        pytest.skip('No test-server')
    os.close(addr_w)
    address = os.read(addr_r, 1000).decode()
    os.close(addr_r)

    try:
        yield URL(address)
    finally:
        server.kill()
        server.wait()


@pytest.mark.asyncio
@pytest.mark.parametrize('html', glob.glob('**/test-*.html', root_dir=f'{SRCDIR}/qunit', recursive=True))
async def test_browser(coverage_report: CoverageReport, html: str) -> None:
    if html in SKIP:
        pytest.skip()
    elif html in XFAIL:
        pytest.xfail()

    async with (
        spawn_test_server() as base_url,
        ChromiumBidi(headless=os.environ.get('TEST_SHOW_BROWSER', '0') == '0') as browser
    ):
        await browser.cdp("Profiler.enable")
        await browser.cdp("Profiler.startPreciseCoverage", callCount=False, detailed=True)

        await browser.bidi(
            'browsingContext.navigate',
            context=browser.context,
            url=str(base_url / 'qunit' / html),
            wait='complete'
        )

        ignore_resource_errors = False
        error_message = None

        async for message in browser.logs:
            if message.type == 'console':
                if message.text == 'cockpittest-tap-done':
                    break
                elif message.text == 'cockpittest-tap-error':
                    error_message = message.text
                    break
                elif message.text == 'cockpittest-tap-expect-resource-error':
                    ignore_resource_errors = True
                    continue
                elif message.text.startswith('not ok'):
                    error_message = message.text

            elif message.type == 'warning':
                print('WARNING', message.text)

            else:
                print('OTHER', message.type, message.args, message.text)

                # fail on browser level errors
                if ignore_resource_errors and "Failed to load resource" in message.text:
                    continue

                error_message = message.text
                break
        else:
            pytest.fail("Didn't receive qunit end message")

        if error_message is not None:
            pytest.fail(f'Test failed: {error_message}')

        coverage = await browser.cdp("Profiler.takePreciseCoverage")
        lcov.write_lcov(coverage['result']['result'], outlabel=re.sub(r'[^A-Za-z0-9]+', '-', html))
        coverage_report(coverage['result'])


# run test-timeformat.ts in different time zones: west/UTC/east
@pytest.mark.asyncio
@pytest.mark.parametrize('tz', ['America/Toronto', 'Europe/London', 'UTC', 'Europe/Berlin', 'Australia/Sydney'])
async def test_timeformat_timezones(
    coverage_report: CoverageReport, tz: str, monkeypatch: pytest.MonkeyPatch
) -> None:
    monkeypatch.setenv('TZ', tz)
    await test_browser(coverage_report, 'base1/test-timeformat.html')