Add two-user integration tests for chat-module#24
Conversation
…er removal; update CI to forward CLI output through pytest logs.
…o specific CLI rewrite SHA to support containerized daemons.
…t_arg` helper for consistent argument access.
… and remove redundant logic
|
|
||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.12" |
There was a problem hiding this comment.
since it's a new job, why not go with newer python ex 3.14?
There was a problem hiding this comment.
Bumped to 3.14. Done together with logos-integration-test-framework (PR #4 there) which now covers 3.11/3.12/3.13/3.14.
| # Once framework's pyproject.toml repins to a SHA that includes the | ||
| # `network=` kwarg, this whole block can become plain `pip install -r ...`. | ||
| pip install --no-deps -r requirements.txt | ||
| pip install pytest>=8.0 |
There was a problem hiding this comment.
why not add pytest instead requirements.txt ?
There was a problem hiding this comment.
Resolved by upstream re-pin: now that logos-integration-test-framework master tracks logoscore@master pip resolution is no longer in conflict.
The workaround (pip install --no-deps -r requirements.txt && pip install pytest>=8.0) is gone. CI now runs plain pip install -r requirements.txt.
| @@ -0,0 +1,150 @@ | |||
| from __future__ import annotations | |||
There was a problem hiding this comment.
I would put this file into a dedicated libs/helper folder to not be mixed with other root files
|
|
||
| from _helpers import ChatUser, setup_chat_user | ||
|
|
||
| FIXTURES_DIR = Path(__file__).parent / "fixtures" |
There was a problem hiding this comment.
can we move all constants to a separate/dedicated file?
There was a problem hiding this comment.
and thus have all other constants in this file as well
There was a problem hiding this comment.
Done — moved to tests/e2e/_constants.py
| try: | ||
| (log_dir / f"{container_name}.log").write_text(_docker_logs(container_name)) | ||
| except OSError: | ||
| pass |
| rest_host_port = pick_free_port() | ||
|
|
||
| cmd = [ | ||
| "docker", "run", "-d", "--name", container_name, |
There was a problem hiding this comment.
any reason to not use python docker sdk?
There was a problem hiding this comment.
subprocess.run(["docker", ...]) mirrors how LogoscoreDockerDaemon itself drives docker internally (also subprocess-based). Made it for consistency.
Also these docker calls are simple, SDK looks like overhead to me. It's easy to debug and we don't add one more dependency.
If calls become more complex we can switch any moment. WDYT?
| config_a = _read_fixture("chat-a.json").replace("__BOOTSTRAP_ENR__", nwaku_bootstrap) | ||
| config_b = _read_fixture("chat-b.json").replace("__BOOTSTRAP_ENR__", nwaku_bootstrap) | ||
|
|
||
| alice_name = f"logoscore-alice-{uuid.uuid4().hex[:8]}" |
There was a problem hiding this comment.
node_a and node_b or similar is better and more consistent
There was a problem hiding this comment.
now it's saro/raya :)
daemon was chosen over node because LogoscoreDockerDaemon is a logoscore daemon process, while in our setup there's also a separate waku node. I thought it's a bit confusing.
| a.client, | ||
| "newPrivateConversation", | ||
| b.intro_bundle, | ||
| hex_encode("hello-from-A-1"), |
There was a problem hiding this comment.
hello-from-A-1 should be a reusable var so you can assert against it at line 73
| convo_id_a = extract_convo_id( | ||
| parse_json_field(wait_event(nc_a, "chatNewConversation", timeout=20.0), 0) | ||
| ) | ||
| convo_id_b = extract_convo_id( |
There was a problem hiding this comment.
convo_id_b differs from convo_id_a ? I would expect them to match and in that case to add an extra assert convo_id_b == convo_id_a
There was a problem hiding this comment.
They're different by design, libchat uses X3DH, where Initiator and Responder gets different local conversation ids
| assert extract_message_content(parse_json_field(first_msg, 0)) == "hello-from-A-1" | ||
|
|
||
| # B → A reply | ||
| with subscribe(a.client, MODULE, "chatNewMessage") as nm_a: |
There was a problem hiding this comment.
those blocks b->a / a->b have a lot in common, could we refactor them into a reusable function to make the test shorter and more readable?
Also I see the CI job is failing, is there a bug / issue? |
|
|
||
|
|
||
| @pytest.fixture(scope="module") | ||
| def chat_users( |
There was a problem hiding this comment.
This fixture looks very specific to test_two_users_can_chat. Like, if we'll want a test with 3 users and then with 5 users, we'll implement 2 more fixtures? 😄
I think such fixture should build 1 user only. And then alice/bob fixtures can be created ad-hoc.
| alice_name = f"logoscore-alice-{uuid.uuid4().hex[:8]}" | ||
| bob_name = f"logoscore-bob-{uuid.uuid4().hex[:8]}" |
There was a problem hiding this comment.
Up to you, but we tend not use classic Alice/Bob/Charlie here, because it's not exactly the right case to use it. We use Saro/Raya/Pax: https://github.com/logos-messaging/specs/blob/master/informational/chat_cast.md
| @@ -0,0 +1,139 @@ | |||
| # logos-chat-module integration tests | |||
There was a problem hiding this comment.
Wouldn't it not count as e2e tests, rather than integration? 🤔
| ┌──────────── docker network "logoschat-it-<uuid>" ────────────┐ | ||
| │ │ | ||
| │ ┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ │ | ||
| │ │ nwaku-bootstrap │ │ logoscore- │ │ logoscore- │ │ | ||
| │ │ 172.30.0.10:60000 │ alice │ │ bob │ │ | ||
| │ │ deterministic │ │ port=60002 │ │ port=60003 │ │ | ||
| │ │ ENR │ │ staticPeers= │ │ staticPeers= │ │ | ||
| │ │ │ │ [bootENR] │ │ [bootENR] │ │ | ||
| │ └─────────────────┘ └──────────────┘ └──────────────┘ │ | ||
| └──────────────────────────────────────────────────────────────┘ | ||
| ▲ │ │ | ||
| │ /vac/waku/relay/2.0.0 ─────────┘ | ||
| │ | ||
| pubsub: /waku/2/rs/2/1 |
There was a problem hiding this comment.
suggestion: replace with a mermaid diagram? (up to you)
| config_a = _read_fixture("chat-a.json").replace("__BOOTSTRAP_ENR__", nwaku_bootstrap) | ||
| config_b = _read_fixture("chat-b.json").replace("__BOOTSTRAP_ENR__", nwaku_bootstrap) |
There was a problem hiding this comment.
Why do we need static JSON files? Can we generate them on the fly?
This would be essential for further scaling of the tests
…and migrate to dynamic config generation
…accordingly in e2e tests
Was flaky cause of a regression in module-builder's codegen path. Should be fixed now. |
…h `parse_event` and `parse_push_payload` for improved clarity and consistency.
…matting consistency.
…daemon version to prevent RPC/transport handshake issues.
87ea9ff to
1095a14
Compare
fbarbu15
left a comment
There was a problem hiding this comment.
LGTM, but I still see the CI job failing
d1fe25f to
87ea9ff
Compare
…olve event-loop starvation issues.
This change defers every Why this is needed. Every libchat callback is invoked synchronously from inside a libchat C API call ( Plugin semantics are unchanged: each Evidence.
Scope. This is a plugin-local mitigation. The same anti-pattern is latent in any module that emits Qt events synchronously from inside a |
|
@at0m1x19 is it ready to merge? |
@igor-sirotin it’s ready from my point of view. Before the merge, I think it’s worth taking a look at the latest commit together with this for someone who ones this repo. |
Adds end-to-end integration test for two-user chat (
test_two_users_chat) plus theintegration-testsCI job.tests/integration/:pytest harness (conftest.py,_helpers.py,test_two_users_chat.py) + fixtures (deterministic nodekey + chat configs with placeholder ENR resolved at runtime)..github/workflows/ci.yml: newintegration-testsjob (ubuntu-only,needs: build-and-test, uploads container logs on failure).