mirror of https://github.com/grpc/grpc-web.git
				
				
				
			Refactor interop tests to be automated
This commit is contained in:
		
							parent
							
								
									ea88b10600
								
							
						
					
					
						commit
						17fbe35265
					
				
							
								
								
									
										15
									
								
								advanced.yml
								
								
								
								
							
							
						
						
									
										15
									
								
								advanced.yml
								
								
								
								
							|  | @ -30,6 +30,15 @@ services: | ||||||
|     image: grpcweb/node-server |     image: grpcweb/node-server | ||||||
|     ports: |     ports: | ||||||
|       - "9090:9090" |       - "9090:9090" | ||||||
|  |   node-interop-server: | ||||||
|  |     build: | ||||||
|  |       context: ./ | ||||||
|  |       dockerfile: ./net/grpc/gateway/docker/node_interop_server/Dockerfile | ||||||
|  |     depends_on: | ||||||
|  |       - common | ||||||
|  |     image: grpcweb/node-interop-server | ||||||
|  |     ports: | ||||||
|  |       - "7074:7074" | ||||||
|   envoy: |   envoy: | ||||||
|     build: |     build: | ||||||
|       context: ./ |       context: ./ | ||||||
|  | @ -95,12 +104,12 @@ services: | ||||||
|     image: grpcweb/binary-client |     image: grpcweb/binary-client | ||||||
|     ports: |     ports: | ||||||
|       - "8081:8081" |       - "8081:8081" | ||||||
|   interop: |   interop-client: | ||||||
|     build: |     build: | ||||||
|       context: ./ |       context: ./ | ||||||
|       dockerfile: ./net/grpc/gateway/docker/interop/Dockerfile |       dockerfile: ./net/grpc/gateway/docker/interop_client/Dockerfile | ||||||
|     depends_on: |     depends_on: | ||||||
|       - prereqs |       - prereqs | ||||||
|     image: grpcweb/interop |     image: grpcweb/interop-client | ||||||
|     ports: |     ports: | ||||||
|       - "8081:8081" |       - "8081:8081" | ||||||
|  |  | ||||||
|  | @ -0,0 +1,37 @@ | ||||||
|  | # Copyright 2018 Google LLC | ||||||
|  | # | ||||||
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | # you may not use this file except in compliance with the License. | ||||||
|  | # You may obtain a copy of the License at | ||||||
|  | # | ||||||
|  | #     https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | # | ||||||
|  | # Unless required by applicable law or agreed to in writing, software | ||||||
|  | # distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | # See the License for the specific language governing permissions and | ||||||
|  | # limitations under the License. | ||||||
|  | 
 | ||||||
|  | FROM grpcweb/common | ||||||
|  | 
 | ||||||
|  | WORKDIR /github/grpc-node | ||||||
|  | 
 | ||||||
|  | RUN git clone https://github.com/grpc/grpc-node . && \ | ||||||
|  |   git submodule update --init --recursive | ||||||
|  | 
 | ||||||
|  | RUN cd packages/grpc-native-core && \ | ||||||
|  |   npm install --build-from-source --unsafe-perm && \ | ||||||
|  |   npm link | ||||||
|  | 
 | ||||||
|  | RUN cd packages/proto-loader && \ | ||||||
|  |   npm install @types/mocha && \ | ||||||
|  |   npm install --unsafe-perm | ||||||
|  | 
 | ||||||
|  | WORKDIR /github/grpc-node/test | ||||||
|  | 
 | ||||||
|  | RUN npm install node-pre-gyp && \ | ||||||
|  |   npm install && \ | ||||||
|  |   npm link grpc | ||||||
|  | 
 | ||||||
|  | EXPOSE 7074 | ||||||
|  | CMD ["node", "--require", "./fixtures/native_native", "./interop/interop_server.js", "--port=7074"] | ||||||
|  | @ -21,6 +21,14 @@ cd "${REPO_DIR}" | ||||||
| ./scripts/init_submodules.sh | ./scripts/init_submodules.sh | ||||||
| make clean | make clean | ||||||
| 
 | 
 | ||||||
|  | # These programs need to be already installed | ||||||
|  | progs=(docker docker-compose npm curl) | ||||||
|  | for p in "${progs[@]}" | ||||||
|  | do | ||||||
|  |   command -v "$p" > /dev/null 2>&1 || \ | ||||||
|  |     { echo >&2 "$p is required but not installed. Aborting."; exit 1; } | ||||||
|  | done | ||||||
|  | 
 | ||||||
| # Lint bazel files. | # Lint bazel files. | ||||||
| BUILDIFIER_VERSION=1.0.0 | BUILDIFIER_VERSION=1.0.0 | ||||||
| BUILDIFIER_SUFFIX="" | BUILDIFIER_SUFFIX="" | ||||||
|  | @ -33,17 +41,6 @@ chmod +x "./buildifier" | ||||||
| ./buildifier --mode=check --lint=warn --warnings=all -r bazel javascript net | ./buildifier --mode=check --lint=warn --warnings=all -r bazel javascript net | ||||||
| rm ./buildifier | rm ./buildifier | ||||||
| 
 | 
 | ||||||
| # These programs need to be already installed |  | ||||||
| progs=(docker docker-compose npm curl) |  | ||||||
| for p in "${progs[@]}" |  | ||||||
| do |  | ||||||
|   command -v "$p" > /dev/null 2>&1 || \ |  | ||||||
|     { echo >&2 "$p is required but not installed. Aborting."; exit 1; } |  | ||||||
| done |  | ||||||
| 
 |  | ||||||
| # Build all relevant docker images. They should all build successfully. |  | ||||||
| docker-compose -f advanced.yml build |  | ||||||
| 
 |  | ||||||
| # Run all bazel unit tests | # Run all bazel unit tests | ||||||
| BAZEL_VERSION=2.2.0 | BAZEL_VERSION=2.2.0 | ||||||
| BAZEL_OS="linux" | BAZEL_OS="linux" | ||||||
|  | @ -60,12 +57,19 @@ $HOME/bin/bazel test \ | ||||||
|   //javascript/net/grpc/web/... \ |   //javascript/net/grpc/web/... \ | ||||||
|   //net/grpc/gateway/examples/... |   //net/grpc/gateway/examples/... | ||||||
| 
 | 
 | ||||||
|  | # Build the protoc plugin | ||||||
|  | make plugin | ||||||
|  | 
 | ||||||
| # Build the grpc-web npm package | # Build the grpc-web npm package | ||||||
| cd packages/grpc-web && \ | cd packages/grpc-web && \ | ||||||
|   npm install && \ |   npm install && \ | ||||||
|   npm run build && \ |   npm run build && \ | ||||||
|  |   npm link && \ | ||||||
|   cd ../.. |   cd ../.. | ||||||
| 
 | 
 | ||||||
|  | # Build all relevant docker images. They should all build successfully. | ||||||
|  | docker-compose -f advanced.yml build | ||||||
|  | 
 | ||||||
| # Bring up the Echo server and the Envoy proxy (in background). | # Bring up the Echo server and the Envoy proxy (in background). | ||||||
| # The 'sleep' seems necessary for the docker containers to be fully up | # The 'sleep' seems necessary for the docker containers to be fully up | ||||||
| # and listening before we test the with curl requests | # and listening before we test the with curl requests | ||||||
|  | @ -80,3 +84,26 @@ docker-compose down | ||||||
| # Run unit tests from npm package | # Run unit tests from npm package | ||||||
| docker run --rm grpcweb/prereqs /bin/bash \ | docker run --rm grpcweb/prereqs /bin/bash \ | ||||||
|   /github/grpc-web/scripts/docker-run-tests.sh |   /github/grpc-web/scripts/docker-run-tests.sh | ||||||
|  | 
 | ||||||
|  | # Run interop tests | ||||||
|  | pid1=$(docker run -d -v $(pwd)/test/interop/envoy.yaml:/etc/envoy/envoy.yaml:ro \ | ||||||
|  |   --network=host -p 8080:8080 envoyproxy/envoy:v1.14.1) | ||||||
|  | pid2=$(docker run -d --network=host -p 7074:7074 grpcweb/node-interop-server) | ||||||
|  | 
 | ||||||
|  | cd test/interop && \ | ||||||
|  |   npm install && \ | ||||||
|  |   npm link grpc-web && \ | ||||||
|  |   protoc -I=../.. src/proto/grpc/testing/test.proto \ | ||||||
|  |   src/proto/grpc/testing/empty.proto \ | ||||||
|  |   src/proto/grpc/testing/messages.proto \ | ||||||
|  |   --plugin=protoc-gen-grpc-web=$(pwd)/../../javascript/net/grpc/web/protoc-gen-grpc-web \ | ||||||
|  |   --js_out=import_style=commonjs:. \ | ||||||
|  |   --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. && \ | ||||||
|  |   npm test && \ | ||||||
|  |   cd ../.. | ||||||
|  | 
 | ||||||
|  | # Clean up | ||||||
|  | docker rm -f $pid1 | ||||||
|  | docker rm -f $pid2 | ||||||
|  | git clean -f -d -x | ||||||
|  | echo 'Completed' | ||||||
|  |  | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | node_modules/ | ||||||
|  | package-lock.json | ||||||
|  | src/ | ||||||
|  | @ -9,14 +9,20 @@ for details about gRPC interop tests in general and the list of test cases. | ||||||
| Run interop tests | Run interop tests | ||||||
| ----------------- | ----------------- | ||||||
| 
 | 
 | ||||||
|  | ### Build some docker images | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | $ cd grpc-web | ||||||
|  | $ docker-compose -f advanced.yml build common prereqs node-interop-server interop-client | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ### Run the Node interop server | ### Run the Node interop server | ||||||
| 
 | 
 | ||||||
| An interop server implemented in Node is hosted in the `grpc/grpc-node` repo. | An interop server implemented in Node is hosted in the `grpc/grpc-node` repo. | ||||||
| There might be a bit of set up you need to do before running the command below. |  | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
| $ cd grpc-node/test | $ docker run -d --network=host -p 7074:7074 grpcweb/node-interop-server | ||||||
| $ node --require ./fixtures/native_native interop/interop_server.js --port=7074 |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -26,19 +32,25 @@ An `envoy.yaml` file is provided in this directory to direct traffic for these | ||||||
| tests. | tests. | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
| $ cd grpc-web | $ docker run -d -v $(pwd)/test/interop/envoy.yaml:/etc/envoy/envoy.yaml:ro \ | ||||||
| $ docker run -it --rm -v $(pwd)/test/interop/envoy.yaml:/etc/envoy/envoy.yaml:ro \ |   --network=host -p 8080:8080 envoyproxy/envoy:v1.14.1 | ||||||
|   --network=host -p 8080:8080 envoyproxy/envoy:latest |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### Run the gRPC-Web browser client | ### Run the gRPC-Web browser client | ||||||
| 
 | 
 | ||||||
|  | You can either run the interop client as `npm test`, like this: | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
| $ cd grpc-web | $ cd test/interop | ||||||
| $ docker-compose -f advanced.yml build common prereqs interop | $ npm install | ||||||
| $ docker-compose -f advanced.yml up interop | $ npm test | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Or from the browser: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | $ docker-compose -f advanced.yml up interop-client | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Open up the browser and go to `http://localhost:8081/index.html` and open up | Open up the browser and go to `http://localhost:8081/index.html` and open up | ||||||
|  |  | ||||||
|  | @ -25,226 +25,185 @@ const {SimpleRequest, | ||||||
|          require('./src/proto/grpc/testing/messages_pb.js'); |          require('./src/proto/grpc/testing/messages_pb.js'); | ||||||
| const {TestServiceClient} = | const {TestServiceClient} = | ||||||
|   require('./src/proto/grpc/testing/test_grpc_web_pb.js'); |   require('./src/proto/grpc/testing/test_grpc_web_pb.js'); | ||||||
|  | var assert = require('assert'); | ||||||
| const grpc = {}; | const grpc = {}; | ||||||
| grpc.web = require('grpc-web'); | grpc.web = require('grpc-web'); | ||||||
| 
 | 
 | ||||||
| var testService = new TestServiceClient( | const SERVER_HOST = 'http://localhost:8080'; | ||||||
|   'http://'+window.location.hostname+':8080', null, null); |  | ||||||
| 
 | 
 | ||||||
| function doEmptyUnary() { | function multiDone(done, count) { | ||||||
|   return new Promise((resolve, reject) => { |   return function() { | ||||||
|     testService.emptyCall(new Empty(), null, (err, response) => { |     count -= 1; | ||||||
|       if (err) { |     if (count <= 0) { | ||||||
|         reject('EmptyUnary failed: Received unexpected error "'+ |       done(); | ||||||
|                err.message+'"'); |     } | ||||||
|         return; |   }; | ||||||
|       } else { | } | ||||||
|         if (!(response instanceof Empty)) { | 
 | ||||||
|           reject('EmptyUnary failed: Response not of Empty type'); | function doEmptyUnary(done) { | ||||||
|           return; |   var testService = new TestServiceClient(SERVER_HOST, null, null); | ||||||
|         } |   testService.emptyCall(new Empty(), null, (err, response) => { | ||||||
|         resolve('EmptyUnary: passed'); |     assert.ifError(err); | ||||||
|       } |     assert(response instanceof Empty); | ||||||
|     }); |     done(); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function doLargeUnary() { | function doLargeUnary(done) { | ||||||
|   return new Promise((resolve, reject) => { |   var testService = new TestServiceClient(SERVER_HOST, null, null); | ||||||
|     var req = new SimpleRequest(); |   var req = new SimpleRequest(); | ||||||
|     var size = 314159; |   var size = 314159; | ||||||
| 
 | 
 | ||||||
|     var payload = new Payload(); |   var payload = new Payload(); | ||||||
|     payload.setBody('0'.repeat(271828)); |   payload.setBody('0'.repeat(271828)); | ||||||
| 
 | 
 | ||||||
|     req.setPayload(payload); |   req.setPayload(payload); | ||||||
|     req.setResponseSize(size); |   req.setResponseSize(size); | ||||||
| 
 | 
 | ||||||
|     testService.unaryCall(req, null, (err, response) => { |   testService.unaryCall(req, null, (err, response) => { | ||||||
|       if (err) { |     assert.ifError(err); | ||||||
|         reject('LargeUnary failed: Received unexpected error "'+ |     assert.equal(response.getPayload().getBody().length, size); | ||||||
|                err.message+'"'); |     done(); | ||||||
|         return; |  | ||||||
|       } else { |  | ||||||
|         if (response.getPayload().getBody().length != size) { |  | ||||||
|           rejecet('LargeUnary failed: Received incorrect size payload'); |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|         resolve('LargeUnary: passed'); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function doServerStreaming() { | function doServerStreaming(done) { | ||||||
|   return new Promise((resolve, reject) => { |   var testService = new TestServiceClient(SERVER_HOST, null, null); | ||||||
|     var sizes = [31415, 9, 2653, 58979]; |   var sizes = [31415, 9, 2653, 58979]; | ||||||
| 
 | 
 | ||||||
|     var responseParams = sizes.map((size, idx) => { |   var responseParams = sizes.map((size, idx) => { | ||||||
|       var param = new ResponseParameters(); |     var param = new ResponseParameters(); | ||||||
|       param.setSize(size); |     param.setSize(size); | ||||||
|       param.setIntervalUs(idx * 10); |     param.setIntervalUs(idx * 10); | ||||||
|       return param; |     return param; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   var req = new StreamingOutputCallRequest(); | ||||||
|  |   req.setResponseParametersList(responseParams); | ||||||
|  | 
 | ||||||
|  |   var stream = testService.streamingOutputCall(req); | ||||||
|  | 
 | ||||||
|  |   done = multiDone(done, sizes.length); | ||||||
|  |   var numCallbacks = 0; | ||||||
|  |   stream.on('data', (response) => { | ||||||
|  |     assert.equal(response.getPayload().getBody().length, sizes[numCallbacks]); | ||||||
|  |     numCallbacks++; | ||||||
|  |     done(); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function doCustomMetadata(done) { | ||||||
|  |   var testService = new TestServiceClient(SERVER_HOST, null, null); | ||||||
|  |   done = multiDone(done, 3); | ||||||
|  | 
 | ||||||
|  |   var req = new SimpleRequest(); | ||||||
|  |   const size = 314159; | ||||||
|  |   const ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; | ||||||
|  |   const ECHO_INITIAL_VALUE = 'test_initial_metadata_value'; | ||||||
|  |   const ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; | ||||||
|  |   const ECHO_TRAILING_VALUE = 0xababab; | ||||||
|  | 
 | ||||||
|  |   var payload = new Payload(); | ||||||
|  |   payload.setBody('0'.repeat(271828)); | ||||||
|  | 
 | ||||||
|  |   req.setPayload(payload); | ||||||
|  |   req.setResponseSize(size); | ||||||
|  | 
 | ||||||
|  |   var call = testService.unaryCall(req, { | ||||||
|  |     [ECHO_INITIAL_KEY]: ECHO_INITIAL_VALUE, | ||||||
|  |     [ECHO_TRAILING_KEY]: ECHO_TRAILING_VALUE | ||||||
|  |   }, (err, response) => { | ||||||
|  |     assert.ifError(err); | ||||||
|  |     assert.equal(response.getPayload().getBody().length, size); | ||||||
|  |     done(); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   call.on('metadata', (metadata) => { | ||||||
|  |     assert(ECHO_INITIAL_KEY in metadata); | ||||||
|  |     assert.equal(metadata[ECHO_INITIAL_KEY], ECHO_INITIAL_VALUE); | ||||||
|  |     done(); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   call.on('status', (status) => { | ||||||
|  |     assert('metadata' in status); | ||||||
|  |     assert(ECHO_TRAILING_KEY in status.metadata); | ||||||
|  |     assert.equal(status.metadata[ECHO_TRAILING_KEY], ECHO_TRAILING_VALUE); | ||||||
|  |     done(); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function doStatusCodeAndMessage(done) { | ||||||
|  |   var testService = new TestServiceClient(SERVER_HOST, null, null); | ||||||
|  |   var req = new SimpleRequest(); | ||||||
|  | 
 | ||||||
|  |   const TEST_STATUS_MESSAGE = 'test status message'; | ||||||
|  |   const echoStatus = new EchoStatus(); | ||||||
|  |   echoStatus.setCode(2); | ||||||
|  |   echoStatus.setMessage(TEST_STATUS_MESSAGE); | ||||||
|  | 
 | ||||||
|  |   req.setResponseStatus(echoStatus); | ||||||
|  | 
 | ||||||
|  |   testService.unaryCall(req, {}, (err, response) => { | ||||||
|  |     assert(err); | ||||||
|  |     assert('code' in err); | ||||||
|  |     assert('message' in err); | ||||||
|  |     assert.equal(err.code, 2); | ||||||
|  |     assert.equal(err.message, TEST_STATUS_MESSAGE); | ||||||
|  |     done(); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function doUnimplementedMethod(done) { | ||||||
|  |   var testService = new TestServiceClient(SERVER_HOST, null, null); | ||||||
|  |   testService.unimplementedCall(new Empty(), {}, (err, response) => { | ||||||
|  |     assert(err); | ||||||
|  |     assert('code' in err); | ||||||
|  |     assert.equal(err.code, 12); | ||||||
|  |     done(); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | var testCases = { | ||||||
|  |   'empty_unary': doEmptyUnary, | ||||||
|  |   'large_unary': doLargeUnary, | ||||||
|  |   'server_streaming': doServerStreaming, | ||||||
|  |   'custom_metadata': doCustomMetadata, | ||||||
|  |   'status_code_and_message': doStatusCodeAndMessage, | ||||||
|  |   'unimplemented_method': doUnimplementedMethod | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | if (typeof window === 'undefined') { | ||||||
|  |   console.log('Running from Node...'); | ||||||
|  | 
 | ||||||
|  |   // Fill in XHR runtime
 | ||||||
|  |   global.XMLHttpRequest = require("xhr2"); | ||||||
|  | 
 | ||||||
|  |   describe('grpc-web interop tests', function() { | ||||||
|  |     Object.keys(testCases).forEach((testCase) => { | ||||||
|  |       it('should pass '+testCase, testCases[testCase]); | ||||||
|     }); |     }); | ||||||
|  |   }); | ||||||
|  | } else { | ||||||
|  |   console.log('Running from browser...'); | ||||||
| 
 | 
 | ||||||
|     var req = new StreamingOutputCallRequest(); |   Object.keys(testCases).forEach((testCase) => { | ||||||
|     req.setResponseParametersList(responseParams); |     var test = testCases[testCase]; | ||||||
| 
 | 
 | ||||||
|     var stream = testService.streamingOutputCall(req); |     var doneCalled = false; | ||||||
| 
 |     test((err) => { | ||||||
|     var numCallbacks = 0; |       if (err) { | ||||||
|     stream.on('data', (response) => { |         throw err; | ||||||
|       if (response.getPayload().getBody().length != sizes[numCallbacks]) { |       } else { | ||||||
|         reject('ServerStreaming failed: Received incorrect size payload'); |         doneCalled = true; | ||||||
|         return; |         console.log(testCase+': passed'); | ||||||
|       } |       } | ||||||
|       numCallbacks++; |  | ||||||
|     }); |     }); | ||||||
|     // TODO(stanleycheung): is there a better way to do this?
 | 
 | ||||||
|     setTimeout(() => { |     setTimeout(() => { | ||||||
|       if (numCallbacks != sizes.length) { |       if (!doneCalled) { | ||||||
|         reject('ServerStreaming failed: data callback called '+ |         throw testCase+': failed. Not all done() are called'; | ||||||
|                numCallbacks+' times. Should be '+sizes.length); |  | ||||||
|         return; |  | ||||||
|       } |       } | ||||||
|       resolve('ServerStreaming: passed'); |     }, 500); | ||||||
|     }, 200); |  | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| function doCustomMetadata() { |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     var req = new SimpleRequest(); |  | ||||||
|     const size = 314159; |  | ||||||
|     const ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; |  | ||||||
|     const ECHO_INITIAL_VALUE = 'test_initial_metadata_value'; |  | ||||||
|     const ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; |  | ||||||
|     const ECHO_TRAILING_VALUE = 0xababab; |  | ||||||
| 
 |  | ||||||
|     var payload = new Payload(); |  | ||||||
|     payload.setBody('0'.repeat(271828)); |  | ||||||
| 
 |  | ||||||
|     req.setPayload(payload); |  | ||||||
|     req.setResponseSize(size); |  | ||||||
| 
 |  | ||||||
|     var call = testService.unaryCall(req, { |  | ||||||
|       [ECHO_INITIAL_KEY]: ECHO_INITIAL_VALUE, |  | ||||||
|       [ECHO_TRAILING_KEY]: ECHO_TRAILING_VALUE |  | ||||||
|     }, (err, response) => { |  | ||||||
|       if (err) { |  | ||||||
|         reject('CustomMetadata failed: Received unexpected error "'+ |  | ||||||
|                err.message+'"'); |  | ||||||
|         return; |  | ||||||
|       } else { |  | ||||||
|         if (response.getPayload().getBody().length != size) { |  | ||||||
|           rejecet('CustomMetadata failed: Received incorrect size payload'); |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|     var metadataCallbackVerified = false; |  | ||||||
|     var statusCallbackVerified = false; |  | ||||||
|     call.on('metadata', (metadata) => { |  | ||||||
|       if (!(ECHO_INITIAL_KEY in metadata)) { |  | ||||||
|         reject('CustomMetadata failed: initial metadata does not '+ |  | ||||||
|                'contain '+ECHO_INITIAL_KEY); |  | ||||||
|       } else if (metadata[ECHO_INITIAL_KEY] != ECHO_INITIAL_VALUE) { |  | ||||||
|         reject('CustomMetadata failed: initial metadata value for '+ |  | ||||||
|                ECHO_INITIAL_KEY+' is incorrect'); |  | ||||||
|       } else { |  | ||||||
|         metadataCallbackVerified = true; |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|     call.on('status', (status) => { |  | ||||||
|       if (!('metadata' in status)) { |  | ||||||
|         reject('CustomMetadata failed: status callback does not '+ |  | ||||||
|                'contain metadata'); |  | ||||||
|       } else if (!(ECHO_TRAILING_KEY in status.metadata)) { |  | ||||||
|         reject('CustomMetadata failed: trailing metadata does not '+ |  | ||||||
|                'contain '+ECHO_TRAILING_KEY); |  | ||||||
|       } else if (status.metadata[ECHO_TRAILING_KEY] != ECHO_TRAILING_VALUE) { |  | ||||||
|         reject('CustomMetadata failed: trailing metadata value for '+ |  | ||||||
|                ECHO_TRAILING_KEY+' is incorrect'); |  | ||||||
|       } else { |  | ||||||
|         statusCallbackVerified = true; |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|     setTimeout(() => { |  | ||||||
|       if (!metadataCallbackVerified || !statusCallbackVerified) { |  | ||||||
|         reject('CustomMetadata failed: some callback failed to verify'); |  | ||||||
|       } |  | ||||||
|       resolve('CustomMetadta passed'); |  | ||||||
|     }, 200); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function doStatusCodeAndMessage() { |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     var req = new SimpleRequest(); |  | ||||||
| 
 |  | ||||||
|     const TEST_STATUS_MESSAGE = 'test status message'; |  | ||||||
|     const echoStatus = new EchoStatus(); |  | ||||||
|     echoStatus.setCode(2); |  | ||||||
|     echoStatus.setMessage(TEST_STATUS_MESSAGE); |  | ||||||
|      |  | ||||||
|     req.setResponseStatus(echoStatus); |  | ||||||
| 
 |  | ||||||
|     testService.unaryCall(req, {}, (err, response) => { |  | ||||||
|       if (err) { |  | ||||||
|         if (!('code' in err)) { |  | ||||||
|           reject('StatusCodeAndMessage failed: status callback does not '+ |  | ||||||
|                  'contain code'); |  | ||||||
|         } else if (!('message' in err)) { |  | ||||||
|           reject('StatusCodeAndMessage failed: status callback does not '+ |  | ||||||
|                  'contain message'); |  | ||||||
|         } else if (err.code != 2) { |  | ||||||
|           reject('StatusCodeAndMessage failed: status code is not 2, is '+ |  | ||||||
|                  err.code); |  | ||||||
|         } else if (err.message != TEST_STATUS_MESSAGE) { |  | ||||||
|           reject('StatusCodeAndMessage failed: status mesage is not '+ |  | ||||||
|                  TEST_STATUS_MESSAGE+', is '+err.message); |  | ||||||
|         } else { |  | ||||||
|           resolve('StatusCodeAndMessage passed'); |  | ||||||
|         } |  | ||||||
|       } else { |  | ||||||
|         reject('StatusCodeAndMessage failed: should not have received a '+ |  | ||||||
|                'proper response'); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function doUnimplementedMethod() { |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     testService.unimplementedCall(new Empty(), {}, (err, response) => { |  | ||||||
|       if (err) { |  | ||||||
|         if (!('code' in err)) { |  | ||||||
|           reject('UnimplementedMethod failed: status callback does not '+ |  | ||||||
|                  'contain code'); |  | ||||||
|         } else if (!('message' in err)) { |  | ||||||
|           reject('UnimplementedMethod failed: status callback does not '+ |  | ||||||
|                  'contain message'); |  | ||||||
|         } else if (err.code != 12) { |  | ||||||
|           reject('UnimplementedMethod failed: status code is not 12'+ |  | ||||||
|                  '(UNIMPLEMENTED), is '+ err.code); |  | ||||||
|         } else { |  | ||||||
|           resolve('UnimplementedMethod passed'); |  | ||||||
|         } |  | ||||||
|       } else { |  | ||||||
|         reject('UnimplementedMethod failed: should not have received a '+ |  | ||||||
|                'proper respoonse'); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|        |  | ||||||
| 
 |  | ||||||
| var testCases = [doEmptyUnary, doLargeUnary, doServerStreaming, |  | ||||||
|                  doCustomMetadata, doStatusCodeAndMessage, |  | ||||||
|                  doUnimplementedMethod]; |  | ||||||
| 
 |  | ||||||
| testCases.reduce((promiseChain, currentTask) => { |  | ||||||
|   return promiseChain.then(() => { |  | ||||||
|     return currentTask().then(console.log); |  | ||||||
|   }).catch(console.error); |  | ||||||
| }, Promise.resolve()); |  | ||||||
|  |  | ||||||
|  | @ -3,13 +3,17 @@ | ||||||
|   "version": "0.1.0", |   "version": "0.1.0", | ||||||
|   "description": "gRPC-Web Interop Test Client", |   "description": "gRPC-Web Interop Test Client", | ||||||
|   "license": "Apache-2.0", |   "license": "Apache-2.0", | ||||||
|  |   "scripts": { | ||||||
|  |     "test": "mocha -b --timeout 500 client.js" | ||||||
|  |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "google-protobuf": "^3.6.1", |     "google-protobuf": "~3.11.4", | ||||||
|     "grpc-web": "^1.0.0" |     "grpc-web": "~1.0.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "browserify": "^16.2.2", |     "mocha": "~7.1.1", | ||||||
|     "webpack": "^4.16.5", |     "webpack": "~4.43.0", | ||||||
|     "webpack-cli": "^3.1.0" |     "webpack-cli": "~3.3.11", | ||||||
|  |     "xhr2": "~0.2.0" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue