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

pytest: Add grpc based CLN client to test grpc coverage #5362

Merged
merged 18 commits into from
Jul 21, 2022

Conversation

cdecker
Copy link
Member

@cdecker cdecker commented Jun 30, 2022

The goal here is to extend test coverage to the grpc interface. We can do so by adding a new LightningGrpc class and swapping out the LightningRpc class if configured to do so. Swapping out then means that instead of talking directly to the JSON-RPC:

CLN -- JSON-RPC -- LightningRpc -- pytest
\_____CLN_____/    \_______pytest_______/

we now take a bit of a detour:

CLN -- JSON-RPC -- cln-rpc -- rpc2grpc converters -- grpc interface -- python grpc client -- python grpc2json converter -- pytest
\_____CLN_____/    \___________cln-grpc-plugin____________________/    \__________________________pytest________________________/

It's a bit roundabout, but it allows us to test all of the components along the way without having to change the tests themselves, and after all they should expose the same functionality.

To opt-in to the grpc testing for now you have to set an environment variable CLN_TEST_GRPC=1, and the LightningNode will swap out the RPC implementation.

Caveat: the conversion is sometimes lossy, i.e., some fields aren't converted (yet), and some RPC methods aren't implemented (and some may never be). Hence some tests will simply not be possible to run at the moment, but I am working on extending coverage, both method-wise as well as field-wise, just be warned that some

@cdecker cdecker force-pushed the cln-grpc-testing branch 4 times, most recently from 7c172ce to f990dfd Compare July 4, 2022 11:48
@niftynei niftynei added this to the v22.10 milestone Jul 11, 2022
@cdecker cdecker force-pushed the cln-grpc-testing branch 6 times, most recently from 1aa273f to 7e93891 Compare July 13, 2022 15:48
@niftynei niftynei modified the milestones: v22.10, v0.12 Jul 13, 2022
@cdecker cdecker marked this pull request as ready for review July 15, 2022 06:57
Copy link
Contributor

@rustyrussell rustyrussell left a comment

Choose a reason for hiding this comment

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

One cut & paste bug, and some questions about our lack of test coverage which allowed these schema issues to slip through CI!

But other than that, looks good!

Comment on lines 5 to 7
"required": [
"psbt"
],
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is wrong!

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, we clearly don't test this properly. Why did it pass CI?

Copy link
Member Author

Choose a reason for hiding this comment

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

Curious indeed, so I went digging a bit:

# We only check payloads which are dicts, which is what we
# usually use: there are some cases which tests [] params,
# which we ignore.
if schemas and schemas[0] and isinstance(payload, dict) and self.check_request_schemas:

The payload is None in this case, hence falsifying the third clause, and we skip schema validation. Even if we did check the schema, we'd run into this:

# Tell the daemon to stop
try:
# May fail if the process already died
self.rpc.stop()
except Exception:
pass

So we might want to relax that if statement and only catch a specific error type instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will fix up the schema though ^^

Comment on lines 43 to 47
},
"mindepth": {
"description": "Number of confirmations required before we consider the channel active",
"type": "u32"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

THis implies we never tested this parameter (or at least, never as a named parameter!).

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 issue here is that the fundchannel.request.json file is new from this PR (the fundchannel.schema.json is the one that was tested).

When I backfilled it early in the PR we didn't have the zeroconf PR merged yet, hence why we needed to add it only later. And indeed CI and make pytest surfaced this lack of parameter in the first version of the JSON schema, hence why I added it here.

TL;DR: Things are working as expected, and we even verified that a missing param does trigger CI warnings.

@cdecker
Copy link
Member Author

cdecker commented Jul 19, 2022

Rebased and removed copy-pasta.

We were overriding the name right when loading, which is bad since in
some languages we use the method name as tag in the requests, thus
renaming causes us to call something that isn't defined.

Changelog-Fixed: cln-rpc: Fixed a naming mismatch for `ConnectPeer` causing `connectpeer` to be called on the JSON-RPC
These may eventually end up in pyln-client, as they allow talking to
the GRPC interface exposed by cln-grpc, however for now they are used
for testing only. Once we have sufficient API and test coverage we can
move them and leave imports in their place.
To test the grpc interface we'll want to emulate the JSON-RPC
interface as best we can, hence when talking to the grpc interface we
want to convert back into a parsed JSON format as LightningRpc would
have returned it. This is just the simplest way of closing the loop
here:

```
  pyln-testing --grpc-> cln-grpc --grpc2json
     ^                                  |
     |                                  v
     |                               JSON-RPC
     |                                  |
    TEST                                v
     ^                                 CLN
     |                                  |
     |                                  v
  pyln-testing <-grpc2py-- cln-grpc <- json2grpc
```
This allows us to re-use existing tests (assuming the call and fields
are covered by `cln-rpc` and `cln-grpc`) to test the full roundtrip
from test over the grpc interface to the json-rpc interface and back
again.

You can switch to the grpc interface by setting the `CLN_TEST_GRPC`
environment variable to 1, but for now only very few shims are
implemented (due to the non-generated nature of LightningRpc).
The CLN API is rather strict about the fact that we should skip
providing a field whenever it is empty. Checking for `is_none` would
still include empty arrays.

Changelog-Fixed cln-rpc: Optional empty arrays will no longer be serialized in requests
This is usually a signal that lightningd is shutting down, so notify
any instance that is waiting on `plugin.join()`.

Changelog-Fixed: cln-plugin: Fixed an issue where plugins would hang indefinitely despite `lightningd` closing the connection
We'll need this when testing the grpc interface in pyln-testing,
otherwise tests just slowly die and wither.
These are the most used methods in tests, so we can start getting our
test coverage up.
It's being skipped in grpc so we don't have it later anyway.
This was likely missed during the zeroconf PR.

Changelog-None
@rustyrussell
Copy link
Contributor

Ack 0741499

@rustyrussell rustyrussell merged commit 76d0548 into ElementsProject:master Jul 21, 2022
@cdecker cdecker deleted the cln-grpc-testing branch July 20, 2023 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants