Skip to content

Conversation

@glbrntt
Copy link
Collaborator

@glbrntt glbrntt commented Jun 24, 2020

Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This pull request is the first of a series to introduce generated test
clients. It adds 'fake response streams', which allow the user to act as
the server for a single RPC. The stream comes in unary and streaming
varieties and is backed by an EmbeddedChannel.

Later PRs will connect these streaming objects to call objects and
provide code generation so that users can more readily make fake streams
for their test clients.

Result:

We're on the road to generated test clients.


This change is Reviewable

@glbrntt glbrntt added kind/enhancement Improvements to existing feature. nio 🆕 semver/minor Adds new public API. labels Jun 24, 2020
@glbrntt glbrntt requested a review from MrMage June 24, 2020 14:08
@glbrntt glbrntt added this to the 1.0.0 milestone Jun 24, 2020
///
/// `sendError` may be used to terminate an RPC without providing a response. As for `sendMessage`,
/// the `trailingMetadata` defaults to being empty.
public class FakeUnaryResponse<Request: GRPCPayload, Response: GRPCPayload>: FakeResponseStream<Request, Response> {

Choose a reason for hiding this comment

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

Making this type public means that this can be used in prod frameworks/apps depending on gRPC as well, not only their test targets. Is that the intended behaviour?
Do correct me if I'm wrong, but I would expect the test-only types to be internal and hence only accessible from (unit) test targets with @testable import GRPC.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think it's sensible for consumers of a framework to use @testable imports: it blurs the line between what is and is not acceptable for the consumer to use. Changing internal code only requires a SemVer patch change which could lead the consumer being broken in unexpected ways between updates. Making this public provides the right SemVer guarantees.

Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

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

I have a few minor notes but this looks really good.

/// - response: The message to send.
/// - initialMetadata: The initial metadata to send. By default the metadata will be empty.
/// - trailingMetadata: The trailing metadata to send. By default the metadata will be empty.
/// - status: The status to send. By default this have status code '.ok'.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit

Suggested change
/// - status: The status to send. By default this have status code '.ok'.
/// - status: The status to send. By default this is status code '.ok'.

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 great overall!

Reviewed 1 of 3 files at r1.
Reviewable status: 1 of 3 files reviewed, 6 unresolved discussions (waiting on @davidpasztor, @glbrntt, @Lukasa, and @MrMage)


Sources/GRPC/FakeResponseStream.swift, line 231 at r1 (raw file):

  ///   - trailingMetadata: The trailing metadata to send. By default the metadata will be empty.
  ///   - status: The status to send. By default this have status code '.ok'.
  public func sendMessage(

Love this "convenience method"! I wonder whether we should even provide a convenience initializer with this? I.e.

FakeUnaryResponse(responseMessage)


Sources/GRPC/FakeResponseStream.swift, line 281 at r1 (raw file):

/// Like `sendEnd`, `trailingMetadata` is empty by default.
public class FakeStreamingResponse<Request: GRPCPayload, Response: GRPCPayload>: FakeResponseStream<Request, Response> {
  public override init() {

Same here — how about a convenience initializer for the "happy case" of just returning a bunch of messages?

Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This pull request is the first of a series to introduce generated test
clients. It adds 'fake response streams', which allow the user to act as
the server for a single RPC. The stream comes in unary and streaming
varieties and is backed by an EmbeddedChannel.

Later PRs will connect these streaming objects to call objects and
provide code generation so that users can more readily make fake streams
for their test clients.

Result:

We're on the road to generated test clients.
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: 1 of 3 files reviewed, 6 unresolved discussions (waiting on @davidpasztor, @glbrntt, @Lukasa, and @MrMage)


Sources/GRPC/FakeResponseStream.swift, line 231 at r1 (raw file):

Previously, MrMage (Daniel Alm) wrote…

Love this "convenience method"! I wonder whether we should even provide a convenience initializer with this? I.e.

FakeUnaryResponse(responseMessage)

Possibly, but I think we should address this when we add the generated code (as that will be how users will create these the majority of the time) since we'll need to generate a function for each convenience init as well.

@glbrntt glbrntt force-pushed the gb-test-client-fake-responses branch from b213865 to efb1851 Compare June 25, 2020 12:16
@glbrntt glbrntt requested a review from Lukasa June 26, 2020 07:23
@Lukasa Lukasa merged commit efb67a3 into grpc:master Jun 26, 2020
@glbrntt glbrntt deleted the gb-test-client-fake-responses branch June 29, 2020 11:01
glbrntt added a commit to glbrntt/grpc-swift that referenced this pull request Jun 29, 2020
Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This is a continuation of the work started in grpc#855.

- This change addes a 'FakeChannel' this is the glue that binds the Call
  objects with the 'fake responses' added in the aforementioned pull
  request.
- Also adds a 'write capturing' handler which forwards request parts to
  a handler provided on the fake response.
- Appropriate internal initializers on each of the call types.

Result:

- Users can manually create 'test' RPCs.
@glbrntt glbrntt mentioned this pull request Jun 29, 2020
glbrntt added a commit that referenced this pull request Jun 30, 2020
Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This is a continuation of the work started in #855.

- This change addes a 'FakeChannel' this is the glue that binds the Call
  objects with the 'fake responses' added in the aforementioned pull
  request.
- Also adds a 'write capturing' handler which forwards request parts to
  a handler provided on the fake response.
- Appropriate internal initializers on each of the call types.

Result:

- Users can manually create 'test' RPCs.
glbrntt added a commit to glbrntt/grpc-swift that referenced this pull request Jul 1, 2020
Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This builds on work in grpc#855, grpc#864, and grpc#865.

This pull request introduces code generation for the test clients. It
provides type-safe wrappers and convenience methods on top of
`FakeChannel` and a code-gen option to enable 'TestClient' generation.

It also removes an `init` requirement on the `GRPCClient` protocol.

Result:

Users can generate test clients.
glbrntt added a commit to glbrntt/grpc-swift that referenced this pull request Jul 1, 2020
Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This builds on work in grpc#855, grpc#864, and grpc#865.

This pull request introduces code generation for the test clients. It
provides type-safe wrappers and convenience methods on top of
`FakeChannel` and a code-gen option to enable 'TestClient' generation.

It also removes an `init` requirement on the `GRPCClient` protocol.

Result:

Users can generate test clients.
glbrntt added a commit to glbrntt/grpc-swift that referenced this pull request Jul 2, 2020
Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This builds on work in grpc#855, grpc#864, and grpc#865.

This pull request introduces code generation for the test clients. It
provides type-safe wrappers and convenience methods on top of
`FakeChannel` and a code-gen option to enable 'TestClient' generation.

It also removes an `init` requirement on the `GRPCClient` protocol.

Result:

Users can generate test clients.
MrMage pushed a commit that referenced this pull request Jul 3, 2020
* Provide the codegen with an option to generate test clients

Motivation:

When consuming gRPC it is often helpful to be able to write tests that
ensure the client is integrated correctly. At the moment this is only
possible by running a local gRPC server with a custom service handler to
return the responses you would like to test.

Modifications:

This builds on work in #855, #864, and #865.

This pull request introduces code generation for the test clients. It
provides type-safe wrappers and convenience methods on top of
`FakeChannel` and a code-gen option to enable 'TestClient' generation.

It also removes an `init` requirement on the `GRPCClient` protocol.

Result:

Users can generate test clients.

* Regenerate

* fix type, add assertion

* Add "Remaining"
@glbrntt glbrntt mentioned this pull request Jul 3, 2020
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement Improvements to existing feature. 🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants