Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add a python version of test-server #20706

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

allisonkarlitskaya
Copy link
Member

@allisonkarlitskaya allisonkarlitskaya commented Jul 4, 2024

very very broken at present, but definitely enough to show promise...

Update: the rationale on this PR has changed a bit, so I'll write about the updated idea here. The main reason for that change is that in the course of getting various qunit tests working with the new server it became clear that part of what the tests are trying to exercise is cockpit-ws itself. That makes sense because although test-server is a separate binary, it uses quite a lot of the same internal implementation as the existing cockpit-ws, so the code that the two of them share gets exercised by the tests.

Moving to a situation where we have a version of test-server in Python which we use to run the tests, but still run the C-based cockpit-ws in production would reduce the meaningfulness of these tests.

The core reason why I started this work remains the same though: after a bunch of recent hacking on cockpit.js (and pkg/lib/cockpit/) I started to want a better developer experience for that. This is also why I developed the coverage stuff.

Specifically: this work makes it possible to run qunit tests without needing to build test-server: just vendor/checkout, ./build.js and pytest -k test-fsinfo.html. The new server is significantly faster to run, as it runs the bridge code in-process (reducing startup times).

There are a few missing features (like missing dbus mock endpoints and so on) vs. the C-based test-server. 5 test files are marked as xfail when running under the new server. There's probably some low-hanging fruit there, but I wanted to get this merged up before it rots too much.

@allisonkarlitskaya allisonkarlitskaya added the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Jul 4, 2024
test/pytest/testserver.py Fixed Show fixed Hide fixed
test/pytest/dbustest.py Fixed Show fixed Hide fixed
test/pytest/testserver.py Fixed Show fixed Hide fixed
@allisonkarlitskaya
Copy link
Member Author

So, I think this PR is a bit misplaced. It seems like a good chunk of our qunit tests are aiming to test specific behaviours of cockpit-ws, so running them under a new test-server.py would mean that they're no longer testing the code that's running in production (the very large chunks of shared code between cockpit-ws and test-server).

The real reason I did this was to help me develop and test new features in the bridge and/or pkg/lib without needing to ./autogen.sh && make && make test-server. For those purposes, this work is already far enough: the testcases like -file and -fsinfo which are clearly aiming to exercise bridge and cockpit.js functionality are working nicely.

So: I think we should merge this soonish, but leave the existing C test-server in place, as it is. We could maybe additionally run some subset of the tests under the Python server to make sure nothing decays, but the main purpose would be for use as a manual development tool.

After that, I think a reasonable next step would be to try to use test-server.py as a basis for a C-compilation-free Cockpit Client...

test/pytest/mockwebserver.py Dismissed Show resolved Hide resolved
test/pytest/mockwebserver.py Dismissed Show dismissed Hide dismissed
test/pytest/webdriver_bidi.py Fixed Show fixed Hide fixed
test/pytest/asyncbridge.py Fixed Show fixed Hide fixed
@allisonkarlitskaya allisonkarlitskaya changed the title wip: port test-server to python test: add a python version of test-server Aug 27, 2024
test/pytest/mockwebserver.py Fixed Show resolved Hide resolved
test/pytest/mockwebserver.py Fixed Show fixed Hide fixed
@allisonkarlitskaya
Copy link
Member Author

E FileNotFoundError: [Errno 2] No such file or directory: 'dbus-daemon'

hmm.

This is roughly a replacement for test-server.  It's an outline for what
a simple cockpit-ws in Python might look like (albeit without any of the
necessary authentication code).  It's already useful enough to run the
majority of the existing QUnit, which means we can now run most unit
tests without needing to build any C code.
Copy link
Member

@martinpitt martinpitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work, thanks! So now pytest-cov runs both scenarios.

The one thing that I'm missing is to document this in HACKING.md. Right now this still says "Run ./test-server". Can you please add that py-only alternative and how to invoke it?

@@ -0,0 +1,49 @@
import os
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this file move to test/pytest/ ? Would be a bit less clutter-y.

['dbus-daemon', f'--config-file={dbus_config}', '--print-pid'], stdout=subprocess.PIPE
)
except FileNotFoundError:
yield None # no dbus-daemon? Don't patch.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO that should hard-fail with the FileNotFoundError. It's actively dangerous if you run an unit test on your production machine (which is common practice), and you don't have dbus-daemon installed (dbus-broker has long been the default in Fedora -- my system doesn't have it installed either).

A test which wants to use this won't work correctly without dbus-daemon -- it should either skip itself or handle the exception.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because it's missing from toxbox...

return

pid = int(dbus_daemon.stdout)
os.environ['DBUS_SESSION_BUS_ADDRESS'] = dbus_addr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We never test the system bus in our tests? ok 😁

(Not actionable, just curious)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually do test the system bus.

The story of this whole thing goes something like so:

  • for the test-server cases we export these mock objects on the user's session bus
  • but if we're running more than one copy of the tests then we're gonna get in trouble because we try to own the same name twice
  • that includes the case where we run the tests in parallel under xdist (ie: pytest -n)
  • so, solution: per-session mock session dbus

There's a wrinkle, though: we need to make sure that we set this environment variable before the first time that systemd_ctypes get used in the process, otherwise it will set up its "default user dbus" shared instance thing before this variable is set. That's why this lives in the toplevel, although it's not like anything in verify/ uses this either...

Some of the other tests already talk to the system D-Bus but don't do anything like owning names on it. I think I did that back in the day because the system bus was more reliably available in our various test environments.

@@ -0,0 +1,492 @@
# This file is part of Cockpit.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has a __main__(), so needs a shebang. (Why didn't our battery of linters not flag that?) GH doesn't show if the file is executable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intent is to run this like spy -m test.pytest.mockwebserver which will hit the __name__ == '__main__' case and doesn't require the #!. If you run it directly then it won't be able to find its relative imports, much less the bits of cockpit it imports.

This could use docs :)

@@ -22,6 +24,14 @@
'base1/test-websocket.html',
}

MOCK_WEBSERVER_XFAIL = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really nice as a TODO list!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-test For doc/workflow changes, or experiments which don't need a full CI run,
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants