mirror of https://github.com/grpc/grpc-dart.git
Add a simple end-to-end gRPC-web test (#354)
We did not have any before which allowed for regressions like #306 to slip through. Unfortunately we can't test gRPC-web implementation in pure Dart because we don't have a server side implementation of the protocol. Instead we add a dependency on the third party gRPC-web proxy (grpcwebproxy by Improbable Engineering - the choice made purely based on the simplicity of installation) which forwards all request gRPC server (written in Dart).
This commit is contained in:
parent
e2f3d74087
commit
2957ec003f
|
@ -8,6 +8,8 @@ addons:
|
|||
# The Chrome addon does not work on windows
|
||||
before_install:
|
||||
- if [ $TRAVIS_OS_NAME = windows ]; then choco install googlechrome ; fi
|
||||
- ./tool/install-grpcwebproxy.sh
|
||||
- export PATH="$PATH:/tmp/grpcwebproxy"
|
||||
|
||||
# Run against both the dev and stable channel.
|
||||
dart:
|
||||
|
|
|
@ -37,18 +37,22 @@ pub get
|
|||
pub run test
|
||||
```
|
||||
|
||||
gRPC-web tests require [`grpcwebproxy`](
|
||||
https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy) by
|
||||
Improbable Engineering to be available in the PATH. Pre-built binaries are [available](https://github.com/improbable-eng/grpc-web/releases).
|
||||
|
||||
## Guidelines for Pull Requests
|
||||
|
||||
How to get your contributions merged smoothly and quickly.
|
||||
|
||||
|
||||
- Create **small PRs** that are narrowly focused on **addressing a single
|
||||
concern**.
|
||||
concern**.
|
||||
|
||||
- For speculative changes, consider opening an issue and discussing it first.
|
||||
|
||||
|
||||
- Provide a good **PR description** as a record of **what** change is being made
|
||||
and **why** it was made. Link to a github issue if it exists.
|
||||
|
||||
|
||||
- Unless your PR is trivial, you should expect there will be review comments
|
||||
that you'll need to address before merging. We expect you to be reasonably
|
||||
responsive to those comments, otherwise the PR will be closed after 2-3 weeks of
|
||||
|
@ -60,6 +64,6 @@ can't really merge your change).
|
|||
- **All tests need to be passing** before your change can be merged. We
|
||||
recommend you **run tests locally** before creating your PR to catch breakages
|
||||
early on.
|
||||
|
||||
|
||||
- Exceptions to the rules can be made if there's a compelling reason for doing
|
||||
so.
|
||||
|
|
|
@ -23,3 +23,4 @@ dev_dependencies:
|
|||
build_web_compilers: ^2.1.1
|
||||
mockito: ^4.1.0
|
||||
test: ^1.6.4
|
||||
stream_channel: ^2.0.0
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:stream_channel/stream_channel.dart';
|
||||
|
||||
import 'src/generated/echo.pbgrpc.dart';
|
||||
|
||||
/// Controls verbosity of output during the test. Flip to [true] for easier
|
||||
/// debugging.
|
||||
const verbose = false;
|
||||
|
||||
class EchoService extends EchoServiceBase {
|
||||
@override
|
||||
Future<EchoResponse> echo(ServiceCall call, EchoRequest request) async {
|
||||
return EchoResponse()..message = request.message;
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<ServerStreamingEchoResponse> serverStreamingEcho(
|
||||
ServiceCall call, ServerStreamingEchoRequest request) async* {
|
||||
for (var i = 0; i < request.messageCount; i++) {
|
||||
yield ServerStreamingEchoResponse()..message = request.message;
|
||||
if (i < request.messageCount - 1) {
|
||||
await Future.delayed(Duration(milliseconds: request.messageInterval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hybridMain(StreamChannel channel) async {
|
||||
// Spawn a gRPC server.
|
||||
final server = Server([EchoService()]);
|
||||
await server.serve(port: 0);
|
||||
_info('grpc server listening on ${server.port}');
|
||||
|
||||
// Spawn a proxy that would translate gRPC-web protocol into gRPC protocol
|
||||
// for us. We use grpcwebproxy by Improbable Engineering. See CONTRIBUTING.md
|
||||
// for setup.
|
||||
Process proxy;
|
||||
try {
|
||||
proxy =
|
||||
await Process.start('grpcwebproxy${Platform.isWindows ? '.exe' : ''}', [
|
||||
'--backend_addr',
|
||||
'localhost:${server.port}',
|
||||
'--run_tls_server=false',
|
||||
'--server_http_debug_port',
|
||||
'0',
|
||||
'--allow_all_origins',
|
||||
]);
|
||||
} catch (e) {
|
||||
print('''
|
||||
Failed to start grpcwebproxy: $e.
|
||||
|
||||
Make sure that grpcwebproxy is available in the PATH see CONTRIBUTING.md
|
||||
if you are running tests locally.
|
||||
''');
|
||||
channel.sink.add(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse output of the proxy process looking for a port it selected.
|
||||
final portRe = RegExp(r'listening for http on: .*:(\d+)');
|
||||
|
||||
proxy.stderr
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter())
|
||||
.listen((line) {
|
||||
_info('grpcwebproxy|stderr] $line');
|
||||
});
|
||||
|
||||
proxy.stdout
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter())
|
||||
.listen((line) {
|
||||
_info('grpcwebproxy|stdout] $line');
|
||||
final m = portRe.firstMatch(line);
|
||||
if (m != null) {
|
||||
final port = int.parse(m[1]);
|
||||
channel.sink.add(port);
|
||||
}
|
||||
});
|
||||
|
||||
proxy.exitCode.then((value) => _info('proxy quit with ${value}'));
|
||||
}
|
||||
|
||||
void _info(String line) {
|
||||
if (verbose) {
|
||||
print(line);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
@TestOn('browser')
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'package:grpc/grpc_web.dart';
|
||||
|
||||
import 'src/generated/echo.pbgrpc.dart';
|
||||
|
||||
/// Starts gRPC server and a gRPC-web proxy (see grpc_web_server.dart for
|
||||
/// implementation.
|
||||
///
|
||||
/// Returns uri which can be used to talk to using gRPC-web channel.
|
||||
///
|
||||
/// Note: server will be shut down when the test which spawned it finishes
|
||||
/// running.
|
||||
Future<Uri> startServer() async {
|
||||
// Spawn the server code on the server side, it will send us back port
|
||||
// number we should be talking to.
|
||||
final serverChannel = spawnHybridUri('grpc_web_server.dart');
|
||||
final port = await serverChannel.stream.first;
|
||||
|
||||
// Note: we would like to test https as well, but we can't easily do it
|
||||
// because browsers like chrome don't trust self-signed certificates by
|
||||
// default.
|
||||
return Uri.parse('http://localhost:$port');
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Test verifies that gRPC-web echo example works by talking to a gRPC
|
||||
// server (written in Dart) via gRPC-web protocol through a third party
|
||||
// gRPC-web proxy.
|
||||
test('gRPC-web echo test', () async {
|
||||
final serverUri = await startServer();
|
||||
final channel = GrpcWebClientChannel.xhr(serverUri);
|
||||
final service = EchoServiceClient(channel);
|
||||
|
||||
const testMessage = 'hello from gRPC-web';
|
||||
|
||||
// First test a simple echo request.
|
||||
final response = await service.echo(EchoRequest()..message = testMessage);
|
||||
expect(response.message, equals(testMessage));
|
||||
|
||||
// Now test that streaming requests also works by asking echo server
|
||||
// to send us a number of messages every 100 ms. Check that we receive
|
||||
// them fast enough (if streaming is broken we will receive all of them
|
||||
// in one go).
|
||||
final sw = Stopwatch()..start();
|
||||
final timings = await service
|
||||
.serverStreamingEcho(ServerStreamingEchoRequest()
|
||||
..message = testMessage
|
||||
..messageCount = 20
|
||||
..messageInterval = 100)
|
||||
.map((response) {
|
||||
expect(response.message, equals(testMessage));
|
||||
final timing = sw.elapsedMilliseconds;
|
||||
sw.reset();
|
||||
return timing;
|
||||
}).toList();
|
||||
final maxDelay = timings.reduce(math.max);
|
||||
expect(maxDelay, lessThan(500));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: echo.proto
|
||||
//
|
||||
// @dart = 2.3
|
||||
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
class EchoRequest extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo('EchoRequest', package: const $pb.PackageName('grpc.gateway.testing'), createEmptyInstance: create)
|
||||
..aOS(1, 'message')
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
EchoRequest._() : super();
|
||||
factory EchoRequest() => create();
|
||||
factory EchoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory EchoRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
EchoRequest clone() => EchoRequest()..mergeFromMessage(this);
|
||||
EchoRequest copyWith(void Function(EchoRequest) updates) => super.copyWith((message) => updates(message as EchoRequest));
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static EchoRequest create() => EchoRequest._();
|
||||
EchoRequest createEmptyInstance() => create();
|
||||
static $pb.PbList<EchoRequest> createRepeated() => $pb.PbList<EchoRequest>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static EchoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EchoRequest>(create);
|
||||
static EchoRequest _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get message => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set message($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasMessage() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearMessage() => clearField(1);
|
||||
}
|
||||
|
||||
class EchoResponse extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo('EchoResponse', package: const $pb.PackageName('grpc.gateway.testing'), createEmptyInstance: create)
|
||||
..aOS(1, 'message')
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
EchoResponse._() : super();
|
||||
factory EchoResponse() => create();
|
||||
factory EchoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory EchoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
EchoResponse clone() => EchoResponse()..mergeFromMessage(this);
|
||||
EchoResponse copyWith(void Function(EchoResponse) updates) => super.copyWith((message) => updates(message as EchoResponse));
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static EchoResponse create() => EchoResponse._();
|
||||
EchoResponse createEmptyInstance() => create();
|
||||
static $pb.PbList<EchoResponse> createRepeated() => $pb.PbList<EchoResponse>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static EchoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EchoResponse>(create);
|
||||
static EchoResponse _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get message => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set message($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasMessage() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearMessage() => clearField(1);
|
||||
}
|
||||
|
||||
class ServerStreamingEchoRequest extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo('ServerStreamingEchoRequest', package: const $pb.PackageName('grpc.gateway.testing'), createEmptyInstance: create)
|
||||
..aOS(1, 'message')
|
||||
..a<$core.int>(2, 'messageCount', $pb.PbFieldType.O3)
|
||||
..a<$core.int>(3, 'messageInterval', $pb.PbFieldType.O3)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
ServerStreamingEchoRequest._() : super();
|
||||
factory ServerStreamingEchoRequest() => create();
|
||||
factory ServerStreamingEchoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory ServerStreamingEchoRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
ServerStreamingEchoRequest clone() => ServerStreamingEchoRequest()..mergeFromMessage(this);
|
||||
ServerStreamingEchoRequest copyWith(void Function(ServerStreamingEchoRequest) updates) => super.copyWith((message) => updates(message as ServerStreamingEchoRequest));
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ServerStreamingEchoRequest create() => ServerStreamingEchoRequest._();
|
||||
ServerStreamingEchoRequest createEmptyInstance() => create();
|
||||
static $pb.PbList<ServerStreamingEchoRequest> createRepeated() => $pb.PbList<ServerStreamingEchoRequest>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ServerStreamingEchoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ServerStreamingEchoRequest>(create);
|
||||
static ServerStreamingEchoRequest _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get message => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set message($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasMessage() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearMessage() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.int get messageCount => $_getIZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set messageCount($core.int v) { $_setSignedInt32(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasMessageCount() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearMessageCount() => clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.int get messageInterval => $_getIZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set messageInterval($core.int v) { $_setSignedInt32(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasMessageInterval() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearMessageInterval() => clearField(3);
|
||||
}
|
||||
|
||||
class ServerStreamingEchoResponse extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo('ServerStreamingEchoResponse', package: const $pb.PackageName('grpc.gateway.testing'), createEmptyInstance: create)
|
||||
..aOS(1, 'message')
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
ServerStreamingEchoResponse._() : super();
|
||||
factory ServerStreamingEchoResponse() => create();
|
||||
factory ServerStreamingEchoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory ServerStreamingEchoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
ServerStreamingEchoResponse clone() => ServerStreamingEchoResponse()..mergeFromMessage(this);
|
||||
ServerStreamingEchoResponse copyWith(void Function(ServerStreamingEchoResponse) updates) => super.copyWith((message) => updates(message as ServerStreamingEchoResponse));
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ServerStreamingEchoResponse create() => ServerStreamingEchoResponse._();
|
||||
ServerStreamingEchoResponse createEmptyInstance() => create();
|
||||
static $pb.PbList<ServerStreamingEchoResponse> createRepeated() => $pb.PbList<ServerStreamingEchoResponse>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ServerStreamingEchoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ServerStreamingEchoResponse>(create);
|
||||
static ServerStreamingEchoResponse _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get message => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set message($core.String v) { $_setString(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasMessage() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearMessage() => clearField(1);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: echo.proto
|
||||
//
|
||||
// @dart = 2.3
|
||||
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: echo.proto
|
||||
//
|
||||
// @dart = 2.3
|
||||
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
|
||||
|
||||
import 'dart:async' as $async;
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
import 'package:grpc/service_api.dart' as $grpc;
|
||||
import 'echo.pb.dart' as $0;
|
||||
export 'echo.pb.dart';
|
||||
|
||||
class EchoServiceClient extends $grpc.Client {
|
||||
static final _$echo = $grpc.ClientMethod<$0.EchoRequest, $0.EchoResponse>(
|
||||
'/grpc.gateway.testing.EchoService/Echo',
|
||||
($0.EchoRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) => $0.EchoResponse.fromBuffer(value));
|
||||
static final _$serverStreamingEcho = $grpc.ClientMethod<
|
||||
$0.ServerStreamingEchoRequest, $0.ServerStreamingEchoResponse>(
|
||||
'/grpc.gateway.testing.EchoService/ServerStreamingEcho',
|
||||
($0.ServerStreamingEchoRequest value) => value.writeToBuffer(),
|
||||
($core.List<$core.int> value) =>
|
||||
$0.ServerStreamingEchoResponse.fromBuffer(value));
|
||||
|
||||
EchoServiceClient($grpc.ClientChannel channel, {$grpc.CallOptions options})
|
||||
: super(channel, options: options);
|
||||
|
||||
$grpc.ResponseFuture<$0.EchoResponse> echo($0.EchoRequest request,
|
||||
{$grpc.CallOptions options}) {
|
||||
final call = $createCall(_$echo, $async.Stream.fromIterable([request]),
|
||||
options: options);
|
||||
return $grpc.ResponseFuture(call);
|
||||
}
|
||||
|
||||
$grpc.ResponseStream<$0.ServerStreamingEchoResponse> serverStreamingEcho(
|
||||
$0.ServerStreamingEchoRequest request,
|
||||
{$grpc.CallOptions options}) {
|
||||
final call = $createCall(
|
||||
_$serverStreamingEcho, $async.Stream.fromIterable([request]),
|
||||
options: options);
|
||||
return $grpc.ResponseStream(call);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EchoServiceBase extends $grpc.Service {
|
||||
$core.String get $name => 'grpc.gateway.testing.EchoService';
|
||||
|
||||
EchoServiceBase() {
|
||||
$addMethod($grpc.ServiceMethod<$0.EchoRequest, $0.EchoResponse>(
|
||||
'Echo',
|
||||
echo_Pre,
|
||||
false,
|
||||
false,
|
||||
($core.List<$core.int> value) => $0.EchoRequest.fromBuffer(value),
|
||||
($0.EchoResponse value) => value.writeToBuffer()));
|
||||
$addMethod($grpc.ServiceMethod<$0.ServerStreamingEchoRequest,
|
||||
$0.ServerStreamingEchoResponse>(
|
||||
'ServerStreamingEcho',
|
||||
serverStreamingEcho_Pre,
|
||||
false,
|
||||
true,
|
||||
($core.List<$core.int> value) =>
|
||||
$0.ServerStreamingEchoRequest.fromBuffer(value),
|
||||
($0.ServerStreamingEchoResponse value) => value.writeToBuffer()));
|
||||
}
|
||||
|
||||
$async.Future<$0.EchoResponse> echo_Pre(
|
||||
$grpc.ServiceCall call, $async.Future<$0.EchoRequest> request) async {
|
||||
return echo(call, await request);
|
||||
}
|
||||
|
||||
$async.Stream<$0.ServerStreamingEchoResponse> serverStreamingEcho_Pre(
|
||||
$grpc.ServiceCall call,
|
||||
$async.Future<$0.ServerStreamingEchoRequest> request) async* {
|
||||
yield* serverStreamingEcho(call, await request);
|
||||
}
|
||||
|
||||
$async.Future<$0.EchoResponse> echo(
|
||||
$grpc.ServiceCall call, $0.EchoRequest request);
|
||||
$async.Stream<$0.ServerStreamingEchoResponse> serverStreamingEcho(
|
||||
$grpc.ServiceCall call, $0.ServerStreamingEchoRequest request);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: echo.proto
|
||||
//
|
||||
// @dart = 2.3
|
||||
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
|
||||
|
||||
const EchoRequest$json = const {
|
||||
'1': 'EchoRequest',
|
||||
'2': const [
|
||||
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
|
||||
],
|
||||
};
|
||||
|
||||
const EchoResponse$json = const {
|
||||
'1': 'EchoResponse',
|
||||
'2': const [
|
||||
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
|
||||
],
|
||||
};
|
||||
|
||||
const ServerStreamingEchoRequest$json = const {
|
||||
'1': 'ServerStreamingEchoRequest',
|
||||
'2': const [
|
||||
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
|
||||
const {'1': 'message_count', '3': 2, '4': 1, '5': 5, '10': 'messageCount'},
|
||||
const {'1': 'message_interval', '3': 3, '4': 1, '5': 5, '10': 'messageInterval'},
|
||||
],
|
||||
};
|
||||
|
||||
const ServerStreamingEchoResponse$json = const {
|
||||
'1': 'ServerStreamingEchoResponse',
|
||||
'2': const [
|
||||
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
|
||||
],
|
||||
};
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package grpc.gateway.testing;
|
||||
|
||||
message EchoRequest {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message EchoResponse {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message ServerStreamingEchoRequest {
|
||||
string message = 1;
|
||||
int32 message_count = 2;
|
||||
int32 message_interval = 3;
|
||||
}
|
||||
|
||||
message ServerStreamingEchoResponse {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
service EchoService {
|
||||
rpc Echo(EchoRequest) returns (EchoResponse);
|
||||
rpc ServerStreamingEcho(ServerStreamingEchoRequest)
|
||||
returns (stream ServerStreamingEchoResponse);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/sh
|
||||
|
||||
VERSION=v0.13.0
|
||||
SUFFIX=
|
||||
|
||||
case $TRAVIS_OS_NAME in
|
||||
linux)
|
||||
VARIANT=linux-x86_64
|
||||
;;
|
||||
osx)
|
||||
VARIANT=osx-x86_64
|
||||
;;
|
||||
windows)
|
||||
VARIANT=win64.exe
|
||||
SUFFIX=.exe
|
||||
;;
|
||||
esac
|
||||
|
||||
BINARY=grpcwebproxy-${VERSION}-${VARIANT}
|
||||
|
||||
wget https://github.com/improbable-eng/grpc-web/releases/download/${VERSION}/${BINARY}.zip -O /tmp/grpcwebproxy.zip
|
||||
rm -rf /tmp/grpcwebproxy
|
||||
mkdir /tmp/grpcwebproxy
|
||||
cd /tmp/grpcwebproxy
|
||||
unzip /tmp/grpcwebproxy.zip
|
||||
mv dist/${BINARY} ./grpcwebproxy${SUFFIX}
|
||||
|
Loading…
Reference in New Issue