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

Add WebSocketMockServer and tests for WebSocketEngine #5187

Merged
merged 18 commits into from
Aug 18, 2023
Merged

Add WebSocketMockServer and tests for WebSocketEngine #5187

merged 18 commits into from
Aug 18, 2023

Conversation

BoD
Copy link
Contributor

@BoD BoD commented Aug 16, 2023

No description provided.

@BoD BoD requested a review from martinbonnin as a code owner August 16, 2023 10:34
@netlify
Copy link

netlify bot commented Aug 16, 2023

Deploy Preview for apollo-android-docs canceled.

Name Link
🔨 Latest commit 4f8e1f1
🔍 Latest deploy log https://app.netlify.com/sites/apollo-android-docs/deploys/64de5ce50cbc7f0008cf7859


@Test
fun gzipTestKtor() = gzipTest(KtorHttpEngine())
Copy link
Contributor

Choose a reason for hiding this comment

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

Any objection to have 2 test tasks that substitute the engine constructor? Like we do for integration tests and Java vs Kotlin models? I can try in a follow up PR if you're up for it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that would be nice, duplicating all test methods is annoying. Not so sure about how to do it though 😅 so you can go ahead if you have ideas 🙏

class Connect(val sessionId: String, val headers: Map<String, String>) : WebSocketEvent()

@ApolloExperimental
class TextFrame(val sessionId: String, val text: String) : WebSocketEvent()
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming bikeshedding: I thought a Text message was split accross multiple frames and therefore this would need to be called TextMessage (or just Text)? Similarly, WebSocketEvent could be named WebSocketMessage?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In events however you can receive "frames" (which I agree it could make sense to rename "messages"), but also other things that are not really messages (connect, close, error) IMO.

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha 👍

I was expecting an API similar to MockWebserver where we don't have anything like Connect or Error. All we can get is the HTTP request.

Similarly for WebSockets, I would expect to be able to record the initial HTTP handshake request as well as subsequent Close/Ping/Pong control frames (or messages because these messages are always a single frame) and data messages (not individual frames).

Just my 2 cents, feel free to discard.

Copy link
Contributor

@martinbonnin martinbonnin left a comment

Choose a reason for hiding this comment

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

A few comment but LGTM overall. A nice building block for future WebSockets improvements

Comment on lines +22 to 24
* @param readTimeoutMillis The request timeout in milliseconds. The request timeout is the time period required to process an HTTP call: from sending a request to receiving a response.
*/
actual class DefaultHttpEngine constructor(private val connectTimeoutMillis: Long, private val readTimeoutMillis: Long) : HttpEngine {
Copy link
Contributor

Choose a reason for hiding this comment

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

While we're at it, do you mind renaming readTimeoutMillis to requestTimeoutMillis? Ultimately, I'd like us to support readTimeoutMillis because:

  • I think it's a better parameter because it does not depend on the response size
  • requestTimeout can be emulated quite easily using withTimeout while readTimeoutMillis actually requires low-level configuration

Copy link
Contributor

Choose a reason for hiding this comment

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

So all in all it'd be:

  • connectTimeout: the initial TCP handshake timeout
  • readTimeout: the socket timeout on subsequent reads
  • requestTimeout (not very useful): the overall timeout of the request

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think renaming readTimeoutMillis to requestTimeoutMillis is breaking right?

Also, in my tests, readTimeoutMillis didn't seem to work actually 😅 But I'll try again to confirm.

In any case I think it makes sense to add a constructor with the 3 parameters? Give more power to the user.

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 renaming readTimeoutMillis to requestTimeoutMillis is breaking right?

Indeed, source breaking, which unfortunately isn't tracked by kbcv.

In any case I think it makes sense to add a constructor with the 3 parameters? Give more power to the user.

I'd vote for only 2: connectTimeout and readTimeout. requestTimeout belongs in higher layers using withTimeout. That is if readTimeout is working as expected of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just checked and socketTimeout doesn't work on Ktor JS. I'll open an issue. In the meantime we could use socketTimeout for Jvm and Apple, but requestTimeout for JS?

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 so? If you're talking about the expect/actual constructor that takes a simple timeoutMillis parameter then it's fine to map it to socketTimeout on Jvm/Apple and requestTimeout on JS as long as it's properly documented.

Then for overloaded (non-actual) constructors, my preference would go to connectTimeout and readTImeout and leave requestTimeout out of it.

@BoD BoD merged commit 27b4975 into main Aug 18, 2023
8 checks passed
@BoD BoD deleted the engine-test branch August 18, 2023 15:48
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.

2 participants