add graphql websocket subsciption tests#768
Conversation
a0653ed to
8738722
Compare
de961c1 to
3503725
Compare
There was a problem hiding this comment.
LGTM, one question (see comment).
This pushes code coverage in the right direction 👍:
There are still a few gaps:
- Would be good to cover error handling, e.g, GraphQL validation errors.
- Would be good to cover more of the websocket subprocotocol (though note that we will change subprotocol soon)
- Would be good to cover connection termination (as this is something we've had issues with).
| def request_wants_html(self): | ||
| accepted = get_accepted_content_types(self.request) | ||
| accepted_length = len(accepted) | ||
| # the list will be ordered in preferred first - so we have to make | ||
| # sure the most preferred gets the highest number | ||
| html_priority = ( | ||
| accepted_length - accepted.index("text/html") | ||
| if "text/html" in accepted | ||
| else 0 | ||
| ) | ||
| json_priority = ( | ||
| accepted_length - accepted.index("application/json") | ||
| if "application/json" in accepted | ||
| else 0 | ||
| ) | ||
|
|
||
| return html_priority > json_priority | ||
|
|
There was a problem hiding this comment.
[note to reviewers]
This is presumably something we inherited via graphene-tornado that's no longer required - https://github.com/graphql-python/graphene-tornado/blob/e4fa7d7b4c2256fa37f5ad89cbfd4d4bf6fdb606/graphene_tornado/tornado_graphql_handler.py#L379
Can't find any trace of it in Tornado.
There was a problem hiding this comment.
Yes, I used Django as the starting point, and graphene-tornado as the reference (because graphene-django is more up to date)..
Some of the things removed were related to the inbuilt GraphiQL, where we use the UI/Vue version instead.
| def get_accepted_content_types(request: 'HTTPServerRequest') -> list: | ||
| def qualify(x): | ||
| parts = x.split(";", 1) | ||
| if len(parts) == 2: | ||
| match = re.match( | ||
| r"(^|;)q=(0(\.\d{,3})?|1(\.0{,3})?)(;|$)", parts[1]) | ||
| if match: | ||
| return parts[0].strip(), float(match.group(2)) | ||
| return parts[0].strip(), 1 | ||
|
|
||
| raw_content_types = request.headers.get("Accept", "*/*").split(",") | ||
| qualified_content_types = map(qualify, raw_content_types) | ||
| return [ | ||
| x[0] | ||
| for x in sorted( | ||
| qualified_content_types, key=lambda x: x[1], reverse=True) | ||
| ] | ||
|
|
||
|
|
There was a problem hiding this comment.
[note to reviewers]
Unused function.
cylc/uiserver/tests/test_graphql.py
Outdated
| ) | ||
| assert response.code == 200 | ||
|
|
||
| # we should find the two dummy workflows in the response |
There was a problem hiding this comment.
Can only see one workflow in the response below?
There was a problem hiding this comment.
Yeah, this is a weird one.. Both graphene-django and graphene-tornado don't appear to be built to handle an actual batched response (or list of queries)...
I may have to change the code to "fix" this in accordance to the accepted behavior..
There was a problem hiding this comment.
I more meant that the test code below doesn't seem to match the comment?
There was a problem hiding this comment.
Ah, sorry, probably a copy paste thing..
I would put this PR in draft mode, but I wanted the tests to run.
| response = json.loads(await ws.read_message()) | ||
|
|
||
| assert response == { | ||
| 'id': sub_id, | ||
| 'type': 'data', | ||
| 'payload': { | ||
| 'data': { | ||
| 'workflows': [ | ||
| { | ||
| 'id': '~me/foo', | ||
| 'status': 'stopped' | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Would be good to test that the subscription can yield more than one result, i.e:
for _ in range(3):
assert json.loads(await ws.read_message()) == { ...
# poke UIS subscriptions as though something changed to make them yield again
await do_something()Not sure what do_something is though?
Yes, this is a work in process, I'll keep expanding the tests here (hopefully until 85% project coverage at min) |
3503725 to
e1c4e1f
Compare
| response = strip_null(response) | ||
|
|
||
| result = self.json_encode(response) | ||
| result = self.json_encode(response) |
There was a problem hiding this comment.
No need to wrap json.dumps/encode in this try/except.. see:
https://github.com/graphql-python/graphene-django/blob/f02ea337a23df06d166d463d6f92cb7505fbb435/graphene_django/views.py#L215
response should always be JSON serializable..
1627744 to
5710e81
Compare
|
83% project coverage 🥇 Ping me when you want a review. |
Just need to bump up the websocket/subscription side of things first. |
aa4cf1c to
a212c89
Compare
|
@oliver-sanders - I think this will do for now, there's some more that could be done with the subscription handler.. But we might as well get this in as a first step for people to build on. |
Adds an integration test for testing the graphql subscriptions via websocket connection.
Check List
CONTRIBUTING.mdand added my name as a Code Contributor.setup.cfg(andconda-environment.ymlif present).?.?.xbranch.