| Interoperability Test Case Descriptions |
| ======================================= |
| |
| Client and server use |
| [test.proto](../src/proto/grpc/testing/test.proto) |
| and the [gRPC over HTTP/2 v2 protocol](./PROTOCOL-HTTP2.md). |
| |
| Client |
| ------ |
| |
| Clients implement test cases that test certain functionally. Each client is |
| provided the test case it is expected to run as a command-line parameter. Names |
| should be lowercase and without spaces. |
| |
| Clients should accept these arguments: |
| * --server_host=HOSTNAME |
| * The server host to connect to. For example, "localhost" or "127.0.0.1" |
| * --server_host_override=HOSTNAME |
| * The server host to claim to be connecting to, for use in TLS and HTTP/2 |
| :authority header. If unspecified, the value of --server_host will be |
| used |
| * --server_port=PORT |
| * The server port to connect to. For example, "8080" |
| * --test_case=TESTCASE |
| * The name of the test case to execute. For example, "empty_unary" |
| * --use_tls=BOOLEAN |
| * Whether to use a plaintext or encrypted connection |
| * --use_test_ca=BOOLEAN |
| * Whether to replace platform root CAs with |
| [ca.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/ca.pem) |
| as the CA root |
| * --default_service_account=ACCOUNT_EMAIL |
| * Email of the GCE default service account. |
| * --oauth_scope=SCOPE |
| * OAuth scope. For example, "https://www.googleapis.com/auth/xapi.zoo" |
| * --service_account_key_file=PATH |
| * The path to the service account JSON key file generated from GCE developer |
| console. |
| * --service_config_json=SERVICE_CONFIG_JSON |
| * Disables service config lookups and sets the provided string as the |
| default service config. |
| * --additional_metadata=ADDITIONAL_METADATA |
| * Additional metadata to send in each request, as a semicolon-separated list |
| of key:value pairs. The first key/value pair is separated by the first colon. |
| The second key/value pair is separated by the next colon *following* the |
| next semi-colon thereafter, and so on. For example: |
| - `abc-key:abc-value;foo-key:foo-value` |
| - Key/value pairs: `abc-key`/`abc-value`, `foo-key`/`foo-value`. |
| - `abc-key:abc:value;foo-key:foo:value` |
| - Key/value pairs: `abc-key`/`abc:value`, `foo-key`/`foo:value`. |
| |
| Keys must be ASCII only (no `-bin` headers allowed). Values may contain |
| any character except semi-colons. |
| |
| Clients must support TLS with ALPN. Clients must not disable certificate |
| checking. |
| |
| ### empty_unary |
| |
| This test verifies that implementations support zero-size messages. Ideally, |
| client implementations would verify that the request and response were zero |
| bytes serialized, but this is generally prohibitive to perform, so is not |
| required. |
| |
| Server features: |
| * [EmptyCall][] |
| |
| Procedure: |
| 1. Client calls EmptyCall with the default Empty message |
| |
| Client asserts: |
| * call was successful |
| * response is non-null |
| |
| *It may be possible to use UnaryCall instead of EmptyCall, but it is harder to |
| ensure that the proto serialized to zero bytes.* |
| |
| ### cacheable_unary |
| |
| This test verifies that gRPC requests marked as cacheable use GET verb instead |
| of POST, and that server sets appropriate cache control headers for the response |
| to be cached by a proxy. This test requires that the server is behind |
| a caching proxy. Use of current timestamp in the request prevents accidental |
| cache matches left over from previous tests. |
| |
| Server features: |
| * [CacheableUnaryCall][] |
| |
| Procedure: |
| 1. Client calls CacheableUnaryCall with `SimpleRequest` request with payload |
| set to current timestamp. Timestamp format is irrelevant, and resolution is |
| in nanoseconds. |
| Client adds a `x-user-ip` header with value `1.2.3.4` to the request. |
| This is done since some proxys such as GFE will not cache requests from |
| localhost. |
| Client marks the request as cacheable by setting the cacheable flag in the |
| request context. Longer term this should be driven by the method option |
| specified in the proto file itself. |
| 2. Client calls CacheableUnaryCall again immediately with the same request and |
| configuration as the previous call. |
| |
| Client asserts: |
| * Both calls were successful |
| * The payload body of both responses is the same. |
| |
| ### large_unary |
| |
| This test verifies unary calls succeed in sending messages, and touches on flow |
| control (even if compression is enabled on the channel). |
| |
| Server features: |
| * [UnaryCall][] |
| |
| Procedure: |
| 1. Client calls UnaryCall with: |
| |
| ``` |
| { |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * response payload body is 314159 bytes in size |
| * clients are free to assert that the response payload body contents are zero |
| and comparing the entire response message against a golden response |
| |
| ### client_compressed_unary |
| |
| This test verifies the client can compress unary messages by sending two unary |
| calls, for compressed and uncompressed payloads. It also sends an initial |
| probing request to verify whether the server supports the [CompressedRequest][] |
| feature by checking if the probing call fails with an `INVALID_ARGUMENT` status. |
| |
| Server features: |
| * [UnaryCall][] |
| * [CompressedRequest][] |
| |
| Procedure: |
| 1. Client calls UnaryCall with the feature probe, an *uncompressed* message: |
| ``` |
| { |
| expect_compressed:{ |
| value: true |
| } |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| 1. Client calls UnaryCall with the *compressed* message: |
| |
| ``` |
| { |
| expect_compressed:{ |
| value: true |
| } |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| 1. Client calls UnaryCall with the *uncompressed* message: |
| |
| ``` |
| { |
| expect_compressed:{ |
| value: false |
| } |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| Client asserts: |
| * First call failed with `INVALID_ARGUMENT` status. |
| * Subsequent calls were successful. |
| * Response payload body is 314159 bytes in size. |
| * Clients are free to assert that the response payload body contents are |
| zeros and comparing the entire response message against a golden response. |
| |
| |
| ### server_compressed_unary |
| |
| This test verifies the server can compress unary messages. It sends two unary |
| requests, expecting the server's response to be compressed or not according to |
| the `response_compressed` boolean. |
| |
| Whether compression was actually performed is determined by the compression bit |
| in the response's message flags. *Note that some languages may not have access |
| to the message flags, in which case the client will be unable to verify that |
| the `response_compressed` boolean is obeyed by the server*. |
| |
| |
| Server features: |
| * [UnaryCall][] |
| * [CompressedResponse][] |
| |
| Procedure: |
| 1. Client calls UnaryCall with `SimpleRequest`: |
| |
| ``` |
| { |
| response_compressed:{ |
| value: true |
| } |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| ``` |
| { |
| response_compressed:{ |
| value: false |
| } |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| Client asserts: |
| * call was successful |
| * if supported by the implementation, when `response_compressed` is true, |
| the response MUST have the compressed message flag set. |
| * if supported by the implementation, when `response_compressed` is false, |
| the response MUST NOT have the compressed message flag set. |
| * response payload body is 314159 bytes in size in both cases. |
| * clients are free to assert that the response payload body contents are |
| zero and comparing the entire response message against a golden response |
| |
| |
| ### client_streaming |
| |
| This test verifies that client-only streaming succeeds. |
| |
| Server features: |
| * [StreamingInputCall][] |
| |
| Procedure: |
| 1. Client calls StreamingInputCall |
| 2. Client sends: |
| |
| ``` |
| { |
| payload:{ |
| body: 27182 bytes of zeros |
| } |
| } |
| ``` |
| |
| 3. Client then sends: |
| |
| ``` |
| { |
| payload:{ |
| body: 8 bytes of zeros |
| } |
| } |
| ``` |
| |
| 4. Client then sends: |
| |
| ``` |
| { |
| payload:{ |
| body: 1828 bytes of zeros |
| } |
| } |
| ``` |
| |
| 5. Client then sends: |
| |
| ``` |
| { |
| payload:{ |
| body: 45904 bytes of zeros |
| } |
| } |
| ``` |
| |
| 6. Client half-closes |
| |
| Client asserts: |
| * call was successful |
| * response aggregated_payload_size is 74922 |
| |
| |
| ### client_compressed_streaming |
| |
| This test verifies the client can compress requests on per-message basis by |
| performing a two-request streaming call. It also sends an initial probing |
| request to verify whether the server supports the [CompressedRequest][] feature |
| by checking if the probing call fails with an `INVALID_ARGUMENT` status. |
| |
| Procedure: |
| 1. Client calls `StreamingInputCall` and sends the following feature-probing |
| *uncompressed* `StreamingInputCallRequest` message |
| |
| ``` |
| { |
| expect_compressed:{ |
| value: true |
| } |
| payload:{ |
| body: 27182 bytes of zeros |
| } |
| } |
| ``` |
| If the call does not fail with `INVALID_ARGUMENT`, the test fails. |
| Otherwise, we continue. |
| |
| 1. Client calls `StreamingInputCall` again, sending the *compressed* message |
| |
| ``` |
| { |
| expect_compressed:{ |
| value: true |
| } |
| payload:{ |
| body: 27182 bytes of zeros |
| } |
| } |
| ``` |
| |
| 1. And finally, the *uncompressed* message |
| ``` |
| { |
| expect_compressed:{ |
| value: false |
| } |
| payload:{ |
| body: 45904 bytes of zeros |
| } |
| } |
| ``` |
| |
| 1. Client half-closes |
| |
| Client asserts: |
| * First call fails with `INVALID_ARGUMENT`. |
| * Next calls succeeds. |
| * Response aggregated payload size is 73086. |
| |
| |
| ### server_streaming |
| |
| This test verifies that server-only streaming succeeds. |
| |
| Server features: |
| * [StreamingOutputCall][] |
| |
| Procedure: |
| 1. Client calls StreamingOutputCall with `StreamingOutputCallRequest`: |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 31415 |
| } |
| response_parameters:{ |
| size: 9 |
| } |
| response_parameters:{ |
| size: 2653 |
| } |
| response_parameters:{ |
| size: 58979 |
| } |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * exactly four responses |
| * response payload bodies are sized (in order): 31415, 9, 2653, 58979 |
| * clients are free to assert that the response payload body contents are zero |
| and comparing the entire response messages against golden responses |
| |
| ### server_compressed_streaming |
| |
| This test verifies that the server can compress streaming messages and disable |
| compression on individual messages, expecting the server's response to be |
| compressed or not according to the `response_compressed` boolean. |
| |
| Whether compression was actually performed is determined by the compression bit |
| in the response's message flags. *Note that some languages may not have access |
| to the message flags, in which case the client will be unable to verify that the |
| `response_compressed` boolean is obeyed by the server*. |
| |
| Server features: |
| * [StreamingOutputCall][] |
| * [CompressedResponse][] |
| |
| |
| Procedure: |
| 1. Client calls StreamingOutputCall with `StreamingOutputCallRequest`: |
| |
| ``` |
| { |
| response_parameters:{ |
| compressed: { |
| value: true |
| } |
| size: 31415 |
| } |
| response_parameters:{ |
| compressed: { |
| value: false |
| } |
| size: 92653 |
| } |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * exactly two responses |
| * if supported by the implementation, when `response_compressed` is false, |
| the response's messages MUST NOT have the compressed message flag set. |
| * if supported by the implementation, when `response_compressed` is true, |
| the response's messages MUST have the compressed message flag set. |
| * response payload bodies are sized (in order): 31415, 92653 |
| * clients are free to assert that the response payload body contents are |
| zero and comparing the entire response messages against golden responses |
| |
| ### ping_pong |
| |
| This test verifies that full duplex bidi is supported. |
| |
| Server features: |
| * [FullDuplexCall][] |
| |
| Procedure: |
| 1. Client calls FullDuplexCall with: |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 31415 |
| } |
| payload:{ |
| body: 27182 bytes of zeros |
| } |
| } |
| ``` |
| |
| 2. After getting a reply, it sends: |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 9 |
| } |
| payload:{ |
| body: 8 bytes of zeros |
| } |
| } |
| ``` |
| |
| 3. After getting a reply, it sends: |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 2653 |
| } |
| payload:{ |
| body: 1828 bytes of zeros |
| } |
| } |
| ``` |
| |
| 4. After getting a reply, it sends: |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 58979 |
| } |
| payload:{ |
| body: 45904 bytes of zeros |
| } |
| } |
| ``` |
| |
| 5. After getting a reply, client half-closes |
| |
| Client asserts: |
| * call was successful |
| * exactly four responses |
| * response payload bodies are sized (in order): 31415, 9, 2653, 58979 |
| * clients are free to assert that the response payload body contents are zero |
| and comparing the entire response messages against golden responses |
| |
| ### empty_stream |
| |
| This test verifies that streams support having zero-messages in both |
| directions. |
| |
| Server features: |
| * [FullDuplexCall][] |
| |
| Procedure: |
| 1. Client calls FullDuplexCall and then half-closes |
| |
| Client asserts: |
| * call was successful |
| * exactly zero responses |
| |
| ### compute_engine_creds |
| |
| This test is only for cloud-to-prod path. |
| |
| This test verifies unary calls succeed in sending messages while using Service |
| Credentials from GCE metadata server. The client instance needs to be created |
| with desired oauth scope. |
| |
| The test uses `--default_service_account` with GCE service account email and |
| `--oauth_scope` with the OAuth scope to use. For testing against |
| grpc-test.sandbox.googleapis.com, "https://www.googleapis.com/auth/xapi.zoo" |
| should |
| be passed in as `--oauth_scope`. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Authenticated Username][] |
| * [Echo OAuth Scope][] |
| |
| Procedure: |
| 1. Client configures channel to use GCECredentials |
| 2. Client calls UnaryCall on the channel with: |
| |
| ``` |
| { |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| fill_username: true |
| fill_oauth_scope: true |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * received SimpleResponse.username equals the value of |
| `--default_service_account` flag |
| * received SimpleResponse.oauth_scope is in `--oauth_scope` |
| * response payload body is 314159 bytes in size |
| * clients are free to assert that the response payload body contents are zero |
| and comparing the entire response message against a golden response |
| |
| ### jwt_token_creds |
| |
| This test is only for cloud-to-prod path. |
| |
| This test verifies unary calls succeed in sending messages while using JWT |
| token (created by the project's key file) |
| |
| Test caller should set flag `--service_account_key_file` with the |
| path to json key file downloaded from |
| https://console.developers.google.com. Alternately, if using a |
| usable auth implementation, she may specify the file location in the environment |
| variable GOOGLE_APPLICATION_CREDENTIALS. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Authenticated Username][] |
| * [Echo OAuth Scope][] |
| |
| Procedure: |
| 1. Client configures the channel to use JWTTokenCredentials |
| 2. Client calls UnaryCall with: |
| |
| ``` |
| { |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| fill_username: true |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * received SimpleResponse.username is not empty and is in the json key file used |
| by the auth library. The client can optionally check the username matches the |
| email address in the key file or equals the value of `--default_service_account` |
| flag. |
| * response payload body is 314159 bytes in size |
| * clients are free to assert that the response payload body contents are zero |
| and comparing the entire response message against a golden response |
| |
| ### oauth2_auth_token |
| |
| This test is only for cloud-to-prod path and some implementations may run |
| in GCE only. |
| |
| This test verifies unary calls succeed in sending messages using an OAuth2 token |
| that is obtained out of band. For the purpose of the test, the OAuth2 token is |
| actually obtained from a service account credentials or GCE credentials via the |
| language-specific authorization library. |
| |
| The difference between this test and the other auth tests is that it |
| first uses the authorization library to obtain an authorization token. |
| |
| The test |
| - uses the flag `--service_account_key_file` with the path to a json key file |
| downloaded from https://console.developers.google.com. Alternately, if using a |
| usable auth implementation, it may specify the file location in the environment |
| variable GOOGLE_APPLICATION_CREDENTIALS, *OR* if GCE credentials is used to |
| fetch the token, `--default_service_account` can be used to pass in GCE service |
| account email. |
| - uses the flag `--oauth_scope` for the oauth scope. For testing against |
| grpc-test.sandbox.googleapis.com, "https://www.googleapis.com/auth/xapi.zoo" |
| should be passed as the `--oauth_scope`. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Authenticated Username][] |
| * [Echo OAuth Scope][] |
| |
| Procedure: |
| 1. Client uses the auth library to obtain an authorization token |
| 2. Client configures the channel to use AccessTokenCredentials with the access |
| token obtained in step 1 |
| 3. Client calls UnaryCall with the following message |
| |
| ``` |
| { |
| fill_username: true |
| fill_oauth_scope: true |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * received SimpleResponse.username is valid. Depending on whether a service |
| account key file or GCE credentials was used, client should check against the |
| json key file or GCE default service account email. |
| * received SimpleResponse.oauth_scope is in `--oauth_scope` |
| |
| ### per_rpc_creds |
| |
| Similar to the other auth tests, this test is only for cloud-to-prod path. |
| |
| This test verifies unary calls succeed in sending messages using a JWT or a |
| service account credentials set on the RPC. |
| |
| The test |
| - uses the flag `--service_account_key_file` with the path to a json key file |
| downloaded from https://console.developers.google.com. Alternately, if using a |
| usable auth implementation, it may specify the file location in the environment |
| variable GOOGLE_APPLICATION_CREDENTIALS |
| - optionally uses the flag `--oauth_scope` for the oauth scope if implementer |
| wishes to use service account credential instead of JWT credential. For testing |
| against grpc-test.sandbox.googleapis.com, oauth scope |
| "https://www.googleapis.com/auth/xapi.zoo" should be used. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Authenticated Username][] |
| * [Echo OAuth Scope][] |
| |
| Procedure: |
| 1. Client configures the channel with just SSL credentials |
| 2. Client calls UnaryCall, setting per-call credentials to |
| JWTTokenCredentials. The request is the following message |
| |
| ``` |
| { |
| fill_username: true |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * received SimpleResponse.username is not empty and is in the json key file used |
| by the auth library. The client can optionally check the username matches the |
| email address in the key file. |
| |
| ### google_default_credentials |
| |
| Similar to the other auth tests, this test should only be run against prod |
| servers. Different from some of the other auth tests however, this test |
| may be also run from outside of GCP. |
| |
| This test verifies unary calls succeed when the client uses |
| GoogleDefaultCredentials. The path to a service account key file in the |
| GOOGLE_APPLICATION_CREDENTIALS environment variable may or may not be |
| provided by the test runner. For example, the test runner might set |
| this environment when outside of GCP but keep it unset when on GCP. |
| |
| The test uses `--default_service_account` with GCE service account email. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Authenticated Username][] |
| |
| Procedure: |
| 1. Client configures the channel to use GoogleDefaultCredentials |
| * Note: the term `GoogleDefaultCredentials` within the context |
| of this test description refers to an API which encapsulates |
| both "transport credentials" and "call credentials" and which |
| is capable of transport creds auto-selection (including ALTS). |
| Similar APIs involving only auto-selection of OAuth mechanisms |
| might work for this test but aren't the intended subjects. |
| 2. Client calls UnaryCall with: |
| |
| ``` |
| { |
| fill_username: true |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * received SimpleResponse.username matches the value of |
| `--default_service_account` |
| |
| ### compute_engine_channel_credentials |
| |
| Similar to the other auth tests, this test should only be run against prod |
| servers. Note that this test may only be ran on GCP. |
| |
| This test verifies unary calls succeed when the client uses |
| ComputeEngineChannelCredentials. All that is needed by the test environment |
| is for the client to be running on GCP. |
| |
| The test uses `--default_service_account` with GCE service account email. This |
| email must identify the default service account of the GCP VM that the test |
| is running on. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Authenticated Username][] |
| |
| Procedure: |
| 1. Client configures the channel to use ComputeEngineChannelCredentials |
| * Note: the term `ComputeEngineChannelCredentials` within the context |
| of this test description refers to an API which encapsulates |
| both "transport credentials" and "call credentials" and which |
| is capable of transport creds auto-selection (including ALTS). |
| The exact name of the API may vary per language. |
| 2. Client calls UnaryCall with: |
| |
| ``` |
| { |
| fill_username: true |
| } |
| ``` |
| |
| Client asserts: |
| * call was successful |
| * received SimpleResponse.username matches the value of |
| `--default_service_account` |
| |
| ### custom_metadata |
| |
| This test verifies that custom metadata in either binary or ascii format can be |
| sent as initial-metadata by the client and as both initial- and trailing-metadata |
| by the server. |
| |
| Server features: |
| * [UnaryCall][] |
| * [FullDuplexCall][] |
| * [Echo Metadata][] |
| |
| Procedure: |
| 1. The client attaches custom metadata with the following keys and values: |
| |
| ``` |
| key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value" |
| key: "x-grpc-test-echo-trailing-bin", value: 0xababab |
| ``` |
| |
| to a UnaryCall with request: |
| |
| ``` |
| { |
| response_size: 314159 |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| 2. The client attaches custom metadata with the following keys and values: |
| |
| ``` |
| key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value" |
| key: "x-grpc-test-echo-trailing-bin", value: 0xababab |
| ``` |
| |
| to a FullDuplexCall with request: |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 314159 |
| } |
| payload:{ |
| body: 271828 bytes of zeros |
| } |
| } |
| ``` |
| |
| and then half-closes |
| |
| Client asserts: |
| * call was successful |
| * metadata with key `"x-grpc-test-echo-initial"` and value |
| `"test_initial_metadata_value"`is received in the initial metadata for calls |
| in Procedure steps 1 and 2. |
| * metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is |
| received in the trailing metadata for calls in Procedure steps 1 and 2. |
| |
| |
| |
| ### status_code_and_message |
| |
| This test verifies unary calls succeed in sending messages, and propagate back |
| status code and message sent along with the messages. |
| |
| Server features: |
| * [UnaryCall][] |
| * [FullDuplexCall][] |
| * [Echo Status][] |
| |
| Procedure: |
| 1. Client calls UnaryCall with: |
| |
| ``` |
| { |
| response_status:{ |
| code: 2 |
| message: "test status message" |
| } |
| } |
| ``` |
| |
| 2. Client calls FullDuplexCall with: |
| |
| ``` |
| { |
| response_status:{ |
| code: 2 |
| message: "test status message" |
| } |
| } |
| ``` |
| |
| and then half-closes |
| |
| |
| Client asserts: |
| * received status code is the same as the sent code for both Procedure steps 1 |
| and 2 |
| * received status message is the same as the sent message for both Procedure |
| steps 1 and 2 |
| |
| ### special_status_message |
| |
| This test verifies Unicode and whitespace is correctly processed in status |
| message. "\t" is horizontal tab. "\r" is carriage return. "\n" is line feed. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Echo Status][] |
| |
| Procedure: |
| 1. Client calls UnaryCall with: |
| |
| ``` |
| { |
| response_status:{ |
| code: 2 |
| message: "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n" |
| } |
| } |
| ``` |
| |
| Client asserts: |
| * received status code is the same as the sent code for Procedure step 1 |
| * received status message is the same as the sent message for Procedure step 1, |
| including all whitespace characters |
| |
| ### unimplemented_method |
| |
| This test verifies that calling an unimplemented RPC method returns the |
| UNIMPLEMENTED status code. |
| |
| Server features: |
| N/A |
| |
| Procedure: |
| * Client calls `grpc.testing.TestService/UnimplementedCall` with an empty |
| request (defined as `grpc.testing.Empty`): |
| |
| ``` |
| { |
| } |
| ``` |
| |
| Client asserts: |
| * received status code is 12 (UNIMPLEMENTED) |
| |
| ### unimplemented_service |
| |
| This test verifies calling an unimplemented server returns the UNIMPLEMENTED |
| status code. |
| |
| Server features: |
| N/A |
| |
| Procedure: |
| * Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an |
| empty request (defined as `grpc.testing.Empty`) |
| |
| Client asserts: |
| * received status code is 12 (UNIMPLEMENTED) |
| |
| ### cancel_after_begin |
| |
| This test verifies that a request can be cancelled after metadata has been sent |
| but before payloads are sent. |
| |
| Server features: |
| * [StreamingInputCall][] |
| |
| Procedure: |
| 1. Client starts StreamingInputCall |
| 2. Client immediately cancels request |
| |
| Client asserts: |
| * Call completed with status CANCELLED |
| |
| ### cancel_after_first_response |
| |
| This test verifies that a request can be cancelled after receiving a message |
| from the server. |
| |
| Server features: |
| * [FullDuplexCall][] |
| |
| Procedure: |
| 1. Client starts FullDuplexCall with |
| |
| ``` |
| { |
| response_parameters:{ |
| size: 31415 |
| } |
| payload:{ |
| body: 27182 bytes of zeros |
| } |
| } |
| ``` |
| |
| 2. After receiving a response, client cancels request |
| |
| Client asserts: |
| * Call completed with status CANCELLED |
| |
| ### timeout_on_sleeping_server |
| |
| This test verifies that an RPC request whose lifetime exceeds its configured |
| timeout value will end with the DeadlineExceeded status. |
| |
| Server features: |
| * [FullDuplexCall][] |
| |
| Procedure: |
| 1. Client calls FullDuplexCall with the following request and sets its timeout |
| to 1ms |
| |
| ``` |
| { |
| payload:{ |
| body: 27182 bytes of zeros |
| } |
| } |
| ``` |
| |
| 2. Client waits |
| |
| Client asserts: |
| * Call completed with status DEADLINE_EXCEEDED. |
| |
| ### rpc_soak |
| |
| The client performs many large_unary RPCs in sequence over the same channel. |
| The client records the latency and status of each RPC in some data structure. |
| If the test ever consumes `soak_overall_timeout_seconds` seconds and still hasn't |
| completed `soak_iterations` RPCs, then the test should discontinue sending RPCs |
| as soon as possible. After performing all RPCs, the test should examine |
| previously recorded RPC latency and status results in a second pass and fail if |
| either: |
| |
| a) not all `soak_iterations` RPCs were completed |
| |
| b) the sum of RPCs that either completed with a non-OK status or exceeded |
| `max_acceptable_per_rpc_latency_ms` exceeds `soak_max_failures` |
| |
| Implementations should use a timer with sub-millisecond precision to measure |
| latency. Also, implementations should avoid setting RPC deadlines and should |
| instead wait for each RPC to complete. Doing so provides more data for |
| debugging in case of failure. For example, if RPC deadlines are set to |
| `soak_per_iteration_max_acceptable_latency_ms` and one of the RPCs hits that |
| deadline, it's not clear if the RPC was late by a millisecond or a minute. |
| |
| In order to make it easy to analyze results, implementations should log the |
| results of each iteration (i.e. RPC) in a format the matches the following |
| regexes: |
| |
| - Upon success: |
| - `soak iteration: \d+ elapsed_ms: \d+ peer: \S+ succeeded` |
| |
| - Upon failure: |
| - `soak iteration: \d+ elapsed_ms: \d+ peer: \S+ failed:` |
| |
| This test must be configurable via a few different command line flags: |
| |
| * `soak_iterations`: Controls the number of RPCs to perform. This should |
| default to 10. |
| |
| * `soak_max_failures`: An inclusive upper limit on the number of RPC failures |
| that should be tolerated (i.e. after which the test process should |
| still exit 0). A failure is considered to be either a non-OK status or an RPC |
| whose latency exceeds `soak_per_iteration_max_acceptable_latency_ms`. This |
| should default to 0. |
| |
| * `soak_per_iteration_max_acceptable_latency_ms`: An upper limit on the latency |
| of a single RPC in order for that RPC to be considered successful. This |
| should default to 1000. |
| |
| * `soak_overall_timeout_seconds`: The overall number of seconds after which |
| the test should stop and fail if `soak_iterations` have not yet been |
| completed. This should default to |
| `soak_per_iteration_max_acceptable_latency_ms` * `soak_iterations`. |
| |
| * `soak_min_time_ms_between_rpcs`: The minimum time in milliseconds between |
| consecutive RPCs. Useful for limiting QPS. |
| |
| The following is optional but encouraged to improve debuggability: |
| |
| * Implementations should log the number of milliseconds that each RPC takes. |
| Additionally, implementations should use a histogram of RPC latencies |
| to log interesting latency percentiles at the end of the test (e.g. median, |
| 90th, and max latency percentiles). |
| |
| ### channel_soak |
| |
| Similar to rpc_soak, but this time each RPC is performed on a new channel. The |
| channel is created just before each RPC and is destroyed just after. |
| |
| This test is configured with the same command line flags that the rpc_soak test |
| is configured with, with only one semantic difference: when measuring an RPCs |
| latency to see if it exceeds `soak_per_iteration_max_acceptable_latency_ms` or |
| not, the creation of the channel should be included in that |
| latency measurement, but the teardown of that channel should **not** be |
| included in that latency measurement (channel teardown semantics differ widely |
| between languages). This latency measurement should also be the value that is |
| logged and recorded in the latency histogram. |
| |
| |
| ### orca_per_rpc |
| [orca_per_rpc]: #orca_per_rpc |
| |
| The client verifies that a custom LB policy, which is integrated with ORCA APIs, |
| will receive per-query metric reports from the backend. |
| |
| The client will register the custom LB policy named |
| `test_backend_metrics_load_balancer`, which using ORCA APIs already installed a |
| per-query report listener. The interop-testing client will run with a service |
| config to select the load balancing config (using argument |
| `--service_config_json`), so that it effectively uses this newly registered |
| custom LB policy. A load report reference can be passed from the call to the LB |
| policy through, e.g. CallOptions, to receive metric reports. The LB policy will |
| fill in the reference with the latest load report from the report listener. |
| This way, together with server behaviors we can verify the expected metric |
| reports are received. |
| |
| Server features: |
| * [UnaryCall][] |
| * [Backend Metrics Report][] |
| |
| Procedures: |
| * The client sends a unary request: |
| ``` |
| { |
| orca_per_rpc_report:{ |
| cpu_utilization: 0.8210 |
| memory_utilization: 0.5847 |
| request_cost: { |
| cost: 3456.32 |
| } |
| utilization: { |
| util: 0.30499 |
| } |
| } |
| } |
| ``` |
| |
| The call carries a reference to receive the load report, e.g. using CallOptions. |
| The reference is passed to the custom LB policy as part of the |
| `OrcaPerRequestReportListener` API. |
| |
| Client asserts: |
| * The call is successful. |
| * The per-query load report reference contains a metrics report that is |
| identical to the metrics data sent in the request shown above. |
| |
| ### orca_oob |
| |
| The client verifies that a custom LB policy, which is integrated with ORCA APIs, |
| will receive out-of-band metric reports from the backend. |
| |
| The client will register the custom LB policy named |
| `test_backend_metrics_load_balancer`. It has similar and additional functions as |
| described in the [orca_per_rpc][] test. We use ORCA APIs to install an |
| out-of-band report listener (configure load report interval to be 1s) in the LB |
| policy. The interop-testing client will run with a service config to select the |
| load balancing config(using argument `--service_config_json`), so that it |
| effectively uses this newly registered custom LB policy. A load report reference |
| can be passed from the call to the LB policy through, e.g. CallOptions, to |
| receive metric reports. The test framework will fill in the reference with the |
| latest load report from the report listener. This way, together with server |
| behaviors we can verify the expected metric reports are received. |
| |
| Server features: |
| * [UnaryCall][] |
| * [FullDuplexCall][] |
| * [Backend Metrics Report][] |
| |
| Procedures: |
| 1. Client starts a full duplex call and sends: |
| ``` |
| { |
| orca_oob_report:{ |
| cpu_utilization: 0.8210 |
| memory_utilization: 0.5847 |
| utilization: { |
| util: 0.30499 |
| } |
| } |
| response_parameters:{ |
| size: 1 |
| } |
| } |
| ``` |
| 2. After getting a response, client waits up to 10 seconds (or a total of 30s |
| for the entire test case) to receive an OOB load report that matches the |
| requested load report in step 1. To wait for load report, client may inject a |
| callback to the custom LB policy, or poll the result by doing empty unary call |
| that carries a reference, e.g. using CallOptions, that will be filled in by the |
| custom LB policy as part of the `OrcaOobReportListener` API. |
| 3. Then client sends: |
| ``` |
| { |
| orca_oob_report:{ |
| cpu_utilization: 0.29309 |
| memory_utilization: 0.2 |
| utilization: { |
| util: 0.2039 |
| } |
| } |
| response_parameters:{ |
| size: 1 |
| } |
| } |
| ``` |
| 4. After getting a response, client waits up to 10 seconds (or a total of 30s |
| for the entire test case) to receive an OOB load report that matches the |
| requested load report in step 3. Similar to step 2. |
| 5. Client half closes the stream, and asserts the streaming call is successful. |
| |
| ### Experimental Tests |
| |
| These tests are not yet standardized, and are not yet implemented in all |
| languages. Therefore they are not part of our interop matrix. |
| |
| #### long_lived_channel |
| |
| The client performs a number of large_unary RPCs over a single long-lived |
| channel with a fixed but configurable interval between each RPC. |
| |
| #### concurrent_large_unary |
| |
| Status: TODO |
| |
| Client performs 1000 large_unary tests in parallel on the same channel. |
| |
| #### Flow control. Pushback at client for large messages (TODO: fix name) |
| |
| Status: TODO |
| |
| This test verifies that a client sending faster than a server can drain sees |
| pushback (i.e., attempts to send succeed only after appropriate delays). |
| |
| ### TODO Tests |
| |
| #### High priority: |
| |
| Propagation of status code and message (yangg) |
| |
| Multiple thousand simultaneous calls on same Channel (ctiller) |
| |
| Metadata: client headers, server headers + trailers, binary+ascii |
| |
| #### Normal priority: |
| |
| Cancel before start (ctiller) |
| |
| Cancel after sent first message (ctiller) |
| |
| Cancel after received headers (ctiller) |
| |
| Timeout but completed before expire (zhaoq) |
| |
| Multiple thousand simultaneous calls timeout on same Channel (ctiller) |
| |
| #### Lower priority: |
| |
| Flow control. Pushback at client for large messages (abhishek) |
| |
| Flow control. Pushback at server for large messages (abhishek) |
| |
| Going over max concurrent streams doesn't fail (client controls itself) |
| (abhishek) |
| |
| RPC method not implemented (yangg) |
| |
| Multiple thousand simultaneous calls on different Channels (ctiller) |
| |
| Failed TLS hostname verification (ejona?) |
| |
| Large amount of headers to cause CONTINUATIONs; 63K of 'X's, all in one header. |
| |
| #### To priorize: |
| |
| Start streaming RPC but don't send any requests, server responds |
| |
| ### Postponed Tests |
| |
| Resilience to buggy servers: These tests would verify that a client application |
| isn't affected negatively by the responses put on the wire by a buggy server |
| (e.g. the client library won't make the application crash). |
| |
| Reconnect after transport failure |
| |
| Reconnect backoff |
| |
| Fuzz testing |
| |
| |
| Server |
| ------ |
| |
| Servers implement various named features for clients to test with. Server |
| features are orthogonal. If a server implements a feature, it is always |
| available for clients. Names are simple descriptions for developer |
| communication and tracking. |
| |
| Servers should accept these arguments: |
| |
| * --port=PORT |
| |
| * The port to listen on. For example, "8080" |
| |
| * --use_tls=BOOLEAN |
| |
| * Whether to use a plaintext or encrypted connection |
| |
| Servers must support TLS with ALPN. They should use |
| [server1.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/server1.pem) |
| for their certificate. |
| |
| ### EmptyCall |
| [EmptyCall]: #emptycall |
| |
| Server implements EmptyCall which immediately returns the empty message. |
| |
| ### UnaryCall |
| [UnaryCall]: #unarycall |
| |
| Server implements UnaryCall which immediately returns a SimpleResponse with a |
| payload body of size `SimpleRequest.response_size` bytes and type as appropriate |
| for the `SimpleRequest.response_type`. If the server does not support the |
| `response_type`, then it should fail the RPC with `INVALID_ARGUMENT`. |
| |
| ### CacheableUnaryCall |
| [CacheableUnaryCall]: #cacheableunarycall |
| |
| Server gets the default SimpleRequest proto as the request. The content of the |
| request is ignored. It returns the SimpleResponse proto with the payload set |
| to current timestamp. The timestamp is an integer representing current time |
| with nanosecond resolution. This integer is formatted as ASCII decimal in the |
| response. The format is not really important as long as the response payload |
| is different for each request. In addition it adds |
| 1. cache control headers such that the response can be cached by proxies in |
| the response path. Server should be behind a caching proxy for this test |
| to pass. Currently we set the max-age to 60 seconds. |
| |
| ### CompressedResponse |
| [CompressedResponse]: #compressedresponse |
| |
| When the client sets `response_compressed` to true, the server's response is |
| sent back compressed. Note that `response_compressed` is present on both |
| `SimpleRequest` (unary) and `StreamingOutputCallRequest` (streaming). |
| |
| ### CompressedRequest |
| [CompressedRequest]: #compressedrequest |
| |
| When the client sets `expect_compressed` to true, the server expects the client |
| request to be compressed. If it's not, it fails the RPC with `INVALID_ARGUMENT`. |
| Note that `response_compressed` is present on both `SimpleRequest` (unary) and |
| `StreamingOutputCallRequest` (streaming). |
| |
| ### StreamingInputCall |
| [StreamingInputCall]: #streaminginputcall |
| |
| Server implements StreamingInputCall which upon half close immediately returns |
| a StreamingInputCallResponse where aggregated_payload_size is the sum of all |
| request payload bodies received. |
| |
| ### StreamingOutputCall |
| [StreamingOutputCall]: #streamingoutputcall |
| |
| Server implements StreamingOutputCall by replying, in order, with one |
| StreamingOutputCallResponse for each ResponseParameters in |
| StreamingOutputCallRequest. Each StreamingOutputCallResponse should have a |
| payload body of size ResponseParameters.size bytes, as specified by its |
| respective ResponseParameters. After sending all responses, it closes with OK. |
| |
| ### FullDuplexCall |
| [FullDuplexCall]: #fullduplexcall |
| |
| Server implements FullDuplexCall by replying, in order, with one |
| StreamingOutputCallResponse for each ResponseParameters in each |
| StreamingOutputCallRequest. Each StreamingOutputCallResponse should have a |
| payload body of size ResponseParameters.size bytes, as specified by its |
| respective ResponseParameters. After receiving half close and sending all |
| responses, it closes with OK. |
| |
| ### Echo Status |
| [Echo Status]: #echo-status |
| When the client sends a response_status in the request payload, the server closes |
| the stream with the status code and message contained within said response_status. |
| The server will not process any further messages on the stream sent by the client. |
| This can be used by clients to verify correct handling of different status codes and |
| associated status messages end-to-end. |
| |
| ### Echo Metadata |
| [Echo Metadata]: #echo-metadata |
| When the client sends metadata with the key `"x-grpc-test-echo-initial"` with its |
| request, the server sends back exactly this key and the corresponding value back to |
| the client as part of initial metadata. When the client sends metadata with the key |
| `"x-grpc-test-echo-trailing-bin"` with its request, the server sends back exactly this |
| key and the corresponding value back to the client as trailing metadata. |
| |
| ### Observe ResponseParameters.interval_us |
| [Observe ResponseParameters.interval_us]: #observe-responseparametersinterval_us |
| |
| In StreamingOutputCall and FullDuplexCall, server delays sending a |
| StreamingOutputCallResponse by the ResponseParameters' `interval_us` for that |
| particular response, relative to the last response sent. That is, `interval_us` |
| acts like a sleep *before* sending the response and accumulates from one |
| response to the next. |
| |
| Interaction with flow control is unspecified. |
| |
| ### Echo Auth Information |
| |
| Status: Pending |
| |
| #### Echo Authenticated Username |
| [Echo Authenticated Username]: #echo-authenticated-username |
| |
| If a SimpleRequest has fill_username=true and that request was successfully |
| authenticated, then the SimpleResponse should have username filled with the |
| canonical form of the authenticated source. The canonical form is dependent on |
| the authentication method, but is likely to be a base 10 integer identifier or |
| an email address. |
| |
| #### Echo OAuth scope |
| [Echo OAuth Scope]: #echo-oauth-scope |
| |
| If a SimpleRequest has `fill_oauth_scope=true` and that request was successfully |
| authenticated via OAuth, then the SimpleResponse should have oauth_scope filled |
| with the scope of the method being invoked. |
| |
| Although a general server-side feature, most test servers won't implement this |
| feature. The TLS server `grpc-test.sandbox.googleapis.com:443` supports this |
| feature. It requires at least the OAuth scope |
| `https://www.googleapis.com/auth/xapi.zoo` for authentication to succeed. |
| |
| Discussion: |
| |
| Ideally, this would be communicated via metadata and not in the |
| request/response, but we want to use this test in code paths that don't yet |
| fully communicate metadata. |
| |
| ### Backend metrics report |
| [Backend Metrics Report]: #backend-metrics-report |
| |
| Server reports backend metrics data in both per-query and out-of-band cases, |
| echoing metrics data from the unary or fullDuplex call. |
| |
| Using ORCA APIs we install the per-query metrics reporting server interceptor, |
| so that it can attach metrics per RPC. We also register the `OpenRCAService` |
| implementation to the server, so that it can report metrics periodically. |
| The minimum report interval in the ORCA service is set to 1 sec. |
| |
| If `SimpleRequest.orca_per_rpc_report` is set in unary call, the server will add |
| the metric data from `orca_per_rpc_report` to the RPC using the language's |
| CallMetricRecorder. |
| |
| If `SimpleRequest.orca_oob_report` is set in fullDuplexCall call, the server |
| will first clear all the previous metrics data, and then add utilization metrics |
| from `orca_oob_report` to the `OpenRCAService`. |
| The server implementation should use a lock or similar mechanism to allow only |
| one client to control the server's out-of-band reports until the end of the RPC. |