Skip to content

Conversation

@glbrntt
Copy link
Collaborator

@glbrntt glbrntt commented May 18, 2020

@MrMage this is a draft for the client test stubs. The relevant parts here are:

  • Sources/Examples/Echo/Model/echo.grpc.swift, and
  • Tests/GRPCTests/TestClientExample.swift

Would like your feedback on the general shape of this before I take it any further!


This change is Reviewable

@glbrntt glbrntt marked this pull request as draft May 18, 2020 15:21
Copy link
Collaborator

@MrMage MrMage left a comment

Choose a reason for hiding this comment

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

Looks good overall as far as I can tell without documentation 👍

Reviewed 14 of 14 files at r1.
Reviewable status: all files reviewed, 11 unresolved discussions (waiting on @glbrntt)


Sources/Examples/Echo/Model/echo.grpc.swift, line 145 at r1 (raw file):

    }
  }
  public init() {

super-nit: newline above this?


Sources/GRPC/ClientCalls/BaseClientCall.swift, line 134 at r1 (raw file):

  }

  init(

Document this method? (Also on the other client calls)


Sources/GRPC/ClientCalls/TestResponse.swift, line 19 at r1 (raw file):

import NIO

enum Event<Message: GRPCPayload> {

I would probably also document these two enums


Sources/GRPC/ClientCalls/TestResponse.swift, line 26 at r1 (raw file):

enum EventDelivery<Message: GRPCPayload> {
  case buffered([Event<Message>])
  case callback((Message) -> Void)

I like the idea of passing in blocks to "handle" the request, but I don't quite understand yet how this would work in practice.


Sources/GRPC/ClientCalls/TestResponse.swift, line 58 at r1 (raw file):

  }

  public func sendEnd(status: GRPCStatus = .ok, metadata: HPACKHeaders = [:]) {

rename "metadata" to "trailingMetadata"? (Can be assumed implicitly, but I am a fan of spelling these things out without any room for ambiguity.)


Sources/GRPC/ClientCalls/TestResponse.swift, line 59 at r1 (raw file):

  public func sendEnd(status: GRPCStatus = .ok, metadata: HPACKHeaders = [:]) {
    self.trailingMetadata.succeed(metadata)

Shouldn't these only get fulfilled after all responses have been sent? I.e. "enqueue" these?


Sources/GRPC/ClientCalls/TestResponse.swift, line 153 at r1 (raw file):

    let status = GRPCStatus(
      code: .failedPrecondition,
      message: "Test response must be added before calling the RPC"

How about something like "test response buffer exhausted"?


Sources/GRPC/ClientCalls/TestResponse.swift, line 156 at r1 (raw file):

    )
    call.sendEnd(status: status)
    try! loop.syncShutdownGracefully()

Are we sure that the loop can already be shut down again at this point? I am concerned that when we return call after this line and its properties/loop get used, we get into trouble.


Tests/GRPCTests/TestClientExample.swift, line 31 at r1 (raw file):

    })

    // We should probably (?) just `sendEnd()` anyway after `sendResponse()` is called on unary

Any way we could make this more convenient, at least for unary calls?


Tests/GRPCTests/TestClientExample.swift, line 36 at r1 (raw file):

    let get = client.get(.with {
      $0.text = "This request will be ignored"

Should the client also record the requests sent, so that we can validate that the correct requests got sent?


Tests/GRPCTests/TestClientExample.swift, line 45 at r1 (raw file):

  }

  func testBidirectional() {

I think we should have tests for all 4 modes, but I guess you were already planning to add those later on.


Tests/GRPCTests/TestClientExample.swift, line 61 at r1 (raw file):

    // ... as well as after making the call.
    responseStream.sendResponse(.with { $0.text = "2" })
    XCTAssertEqual(responses, [.with { $0.text = "1" }, .with { $0.text = "2" }])

Same here; could we somehow also validate the sent requests (and maybe even the metadata)?

Copy link
Collaborator Author

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

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

Reviewable status: all files reviewed, 11 unresolved discussions (waiting on @glbrntt and @MrMage)


Sources/GRPC/ClientCalls/TestResponse.swift, line 59 at r1 (raw file):

Previously, MrMage (Daniel Alm) wrote…

Shouldn't these only get fulfilled after all responses have been sent? I.e. "enqueue" these?

Yeah, you're right.


Sources/GRPC/ClientCalls/TestResponse.swift, line 156 at r1 (raw file):

Previously, MrMage (Daniel Alm) wrote…

Are we sure that the loop can already be shut down again at this point? I am concerned that when we return call after this line and its properties/loop get used, we get into trouble.

This is going to change: I think the better approach is initialising the test client with an ELG which we can user here, the lifecycle of the ELG would be the users responsibility.


Tests/GRPCTests/TestClientExample.swift, line 31 at r1 (raw file):

Previously, MrMage (Daniel Alm) wrote…

Any way we could make this more convenient, at least for unary calls?

Yeah, I think unary should probably just have two functions:

// happy path (status is implicitly `.ok`)
sendResponse(_ response: Response, trailingMetadata: HPACKHeaders = [:])

// sad path
error(status: GRPCStatus, trailingMetadata: HPACKHeaders = [:])

Tests/GRPCTests/TestClientExample.swift, line 36 at r1 (raw file):

Previously, MrMage (Daniel Alm) wrote…

Should the client also record the requests sent, so that we can validate that the correct requests got sent?

If you think that's worth doing we can probably just extend the "responseStream" to contain requests as well. Obviously some renaming would be required!


Tests/GRPCTests/TestClientExample.swift, line 61 at r1 (raw file):

Previously, MrMage (Daniel Alm) wrote…

Same here; could we somehow also validate the sent requests (and maybe even the metadata)?

We can probably do the metadata too.

@MrMage MrMage mentioned this pull request May 22, 2020
4 tasks
@davidpasztor
Copy link

@glbrntt is there an update on this one? I have a library dependant on grpc-swift that is waiting for unit tests, which are blocked by not being able to mock gRPC calls. Would be good to know (at least roughly) when this PR is expected to be merged and then released.

@glbrntt
Copy link
Collaborator Author

glbrntt commented Jun 10, 2020

Really sorry for the delay with this @davidpasztor -- a bunch of other things have gotten in the way. In particularl to do this properly meant rewriting a couple of things (#834). Once that's done I can return to this. I'm hoping to have this wrapped up in the next week or two.

@davidpasztor
Copy link

@glbrntt no worries, thanks for tackling this in the first place 👍 Thanks for the update as well, that does sound like a reasonable timeframe.

@glbrntt
Copy link
Collaborator Author

glbrntt commented Jun 10, 2020

@glbrntt no worries, thanks for tackling this in the first place 👍 Thanks for the update as well, that does sound like a reasonable timeframe.

No problem!

@glbrntt glbrntt added nio 🆕 semver/minor Adds new public API. labels Jun 11, 2020
@glbrntt glbrntt added this to the 1.0.0 milestone Jun 16, 2020
@glbrntt
Copy link
Collaborator Author

glbrntt commented Jun 24, 2020

I ended up taking a slightly different approach. The changes will come over a couple of PRs to make it easier to review, the first of which is #855. I'm closing this PR in favour of that.

@glbrntt glbrntt closed this Jun 24, 2020
@glbrntt glbrntt deleted the gb-client-stub branch June 24, 2020 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants