mirror of https://github.com/grpc/grpc-dart.git
Switch to Dart 3 (#633)
* Switch to Dart 3 * Trying to get the new version to run * Fix test * Switch CI to Dart 3 * Adapt CI * Do not run vmservice on chrome * Typo * Add skip to not fail on `dart test` * Add changelog entry * Changes as per review
This commit is contained in:
parent
244dea0361
commit
f420b77a22
|
@ -16,7 +16,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
sdk: [dev, 2.17.0]
|
||||
sdk: [3.0.0, dev]
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
- uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
|
||||
|
@ -60,7 +60,7 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
sdk: [dev, 2.17.0]
|
||||
sdk: [3.0.0, dev]
|
||||
platform: [vm, chrome]
|
||||
exclude:
|
||||
# We only run Chrome tests on Linux. No need to run them
|
||||
|
@ -92,3 +92,6 @@ jobs:
|
|||
run: dart pub get
|
||||
- name: Run tests
|
||||
run: dart test --platform ${{ matrix.platform }}
|
||||
- name: Run vmservice test
|
||||
if: ${{ matrix.platform != 'chrome' }}
|
||||
run: dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
* Add a `channelShutdownHandler` argument to `ClientChannel` and the subclasses.
|
||||
This callback can be used to react to channel shutdown or termination.
|
||||
* Export the `Code` protobuf enum from the `grpc.dart` library.
|
||||
* Require Dart 3.0.0 or greater.
|
||||
|
||||
## 3.1.0
|
||||
|
||||
|
|
|
@ -369,8 +369,10 @@ class ClientCall<Q, R> implements Response {
|
|||
if (!_headers.isCompleted) {
|
||||
_headerMetadata = data.metadata;
|
||||
if (_requestTimeline != null) {
|
||||
_responseTimeline = timelineTaskFactory(
|
||||
parent: _requestTimeline, filterKey: clientTimelineFilterKey);
|
||||
_responseTimeline = TimelineTask(
|
||||
parent: _requestTimeline,
|
||||
filterKey: clientTimelineFilterKey,
|
||||
);
|
||||
}
|
||||
_responseTimeline?.start('gRPC Response');
|
||||
_responseTimeline?.instant('Metadata received', arguments: {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import '../shared/profiler.dart';
|
||||
import '../shared/status.dart';
|
||||
|
@ -109,7 +110,7 @@ abstract class ClientChannelBase implements ClientChannel {
|
|||
requests,
|
||||
options,
|
||||
isTimelineLoggingEnabled
|
||||
? timelineTaskFactory(filterKey: clientTimelineFilterKey)
|
||||
? TimelineTask(filterKey: clientTimelineFilterKey)
|
||||
: null);
|
||||
getConnection().then((connection) {
|
||||
if (call.isCancelled) return;
|
||||
|
|
|
@ -76,7 +76,7 @@ class ResponseStream<R> extends StreamView<R> with _ResponseMixin<dynamic, R> {
|
|||
ResponseFuture<R> get single => ResponseFuture(_call);
|
||||
}
|
||||
|
||||
abstract class _ResponseMixin<Q, R> implements Response {
|
||||
mixin _ResponseMixin<Q, R> implements Response {
|
||||
ClientCall<Q, R> get _call;
|
||||
|
||||
@override
|
||||
|
|
|
@ -38,7 +38,7 @@ class GrpcWebDecoder extends Converter<ByteBuffer, GrpcMessage> {
|
|||
}
|
||||
}
|
||||
|
||||
class _GrpcWebConversionSink extends ChunkedConversionSink<ByteBuffer> {
|
||||
class _GrpcWebConversionSink implements ChunkedConversionSink<ByteBuffer> {
|
||||
static const int frameTypeData = 0x00;
|
||||
static const int frameTypeTrailers = 0x80;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class GrpcData extends GrpcMessage {
|
|||
String toString() => 'gRPC Data (${data.length} bytes)';
|
||||
}
|
||||
|
||||
class GrpcMessageSink extends Sink<GrpcMessage> {
|
||||
class GrpcMessageSink implements Sink<GrpcMessage> {
|
||||
late final GrpcMessage message;
|
||||
bool _messageReceived = false;
|
||||
|
||||
|
|
|
@ -13,17 +13,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'dart:developer';
|
||||
|
||||
typedef TimelineTaskFactory = TimelineTask Function(
|
||||
{String? filterKey, TimelineTask? parent});
|
||||
|
||||
TimelineTaskFactory timelineTaskFactory = _defaultTimelineTaskFactory;
|
||||
|
||||
TimelineTask _defaultTimelineTaskFactory(
|
||||
{String? filterKey, TimelineTask? parent}) =>
|
||||
TimelineTask(filterKey: filterKey, parent: parent);
|
||||
|
||||
const String clientTimelineFilterKey = 'grpc/client';
|
||||
|
||||
/// Enable logging requests and response for clients.
|
||||
|
|
|
@ -59,7 +59,8 @@ class GrpcHttpDecoder extends Converter<StreamMessage, GrpcMessage> {
|
|||
}
|
||||
}
|
||||
|
||||
class _GrpcMessageConversionSink extends ChunkedConversionSink<StreamMessage> {
|
||||
class _GrpcMessageConversionSink
|
||||
implements ChunkedConversionSink<StreamMessage> {
|
||||
final Sink<GrpcMessage> _out;
|
||||
final bool _forResponse;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ version: 3.2.0-dev
|
|||
repository: https://github.com/grpc/grpc-dart
|
||||
|
||||
environment:
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
archive: ^3.0.0
|
||||
|
@ -28,6 +28,7 @@ dev_dependencies:
|
|||
test: ^1.16.0
|
||||
stream_channel: ^2.1.0
|
||||
stream_transform: ^2.0.0
|
||||
vm_service: ^11.6.0
|
||||
|
||||
false_secrets:
|
||||
- interop/server1.key
|
||||
|
|
|
@ -14,16 +14,18 @@
|
|||
// limitations under the License.
|
||||
|
||||
@TestOn('vm')
|
||||
@Skip(
|
||||
'Run only as `dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart`')
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
import 'dart:developer' as dev;
|
||||
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:grpc/src/client/channel.dart' hide ClientChannel;
|
||||
import 'package:grpc/src/client/connection.dart';
|
||||
import 'package:grpc/src/client/http2_connection.dart';
|
||||
import 'package:grpc/src/shared/profiler.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:vm_service/vm_service_io.dart';
|
||||
|
||||
const String path = '/test.TestService/stream';
|
||||
|
||||
|
@ -64,78 +66,13 @@ class FixedConnectionClientChannel extends ClientChannelBase {
|
|||
ClientConnection createConnection() => clientConnection;
|
||||
}
|
||||
|
||||
class FakeTimelineTask extends Fake implements TimelineTask {
|
||||
static final List<FakeTimelineTask> tasks = [];
|
||||
static final List<Map> events = [];
|
||||
static int _idCount = 0;
|
||||
|
||||
final String? filterKey;
|
||||
final TimelineTask? parent;
|
||||
final int id = _idCount++;
|
||||
int _startFinishCount = 0;
|
||||
|
||||
factory FakeTimelineTask({TimelineTask? parent, String? filterKey}) {
|
||||
final task = FakeTimelineTask._(parent: parent, filterKey: filterKey);
|
||||
tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
FakeTimelineTask._({this.parent, this.filterKey});
|
||||
|
||||
bool get isComplete => _startFinishCount == 0;
|
||||
|
||||
@override
|
||||
void start(String name, {Map? arguments}) {
|
||||
events.add({
|
||||
'id': id,
|
||||
'ph': 'b',
|
||||
'name': name,
|
||||
'args': {
|
||||
if (filterKey != null) 'filterKey': filterKey,
|
||||
if (parent != null) 'parentId': (parent as FakeTimelineTask).id,
|
||||
if (arguments != null) ...arguments,
|
||||
}
|
||||
});
|
||||
++_startFinishCount;
|
||||
}
|
||||
|
||||
@override
|
||||
void instant(String name, {Map? arguments}) {
|
||||
events.add({
|
||||
'id': id,
|
||||
'ph': 'i',
|
||||
'name': name,
|
||||
'args': {
|
||||
if (filterKey != null) 'filterKey': filterKey,
|
||||
if (arguments != null) ...arguments,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void finish({Map? arguments}) {
|
||||
events.add({
|
||||
'id': id,
|
||||
'ph': 'e',
|
||||
'args': {
|
||||
if (filterKey != null) 'filterKey': filterKey,
|
||||
if (arguments != null) ...arguments,
|
||||
}
|
||||
});
|
||||
--_startFinishCount;
|
||||
expect(_startFinishCount >= 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
TimelineTask fakeTimelineTaskFactory(
|
||||
{String? filterKey, TimelineTask? parent}) =>
|
||||
FakeTimelineTask(filterKey: filterKey, parent: parent);
|
||||
|
||||
Future<void> testee() async {
|
||||
Future<VmService> testee() async {
|
||||
isTimelineLoggingEnabled = true;
|
||||
final info = await dev.Service.getInfo();
|
||||
final uri = info.serverWebSocketUri!;
|
||||
final vmService = await vmServiceConnectUri(uri.toString());
|
||||
final server = Server.create(services: [TestService()]);
|
||||
await server.serve(address: 'localhost', port: 0);
|
||||
isTimelineLoggingEnabled = true;
|
||||
timelineTaskFactory = fakeTimelineTaskFactory;
|
||||
final channel = FixedConnectionClientChannel(Http2ClientConnection(
|
||||
'localhost',
|
||||
server.port!,
|
||||
|
@ -144,6 +81,7 @@ Future<void> testee() async {
|
|||
final testClient = TestClient(channel);
|
||||
await testClient.stream(1).toList();
|
||||
await server.shutdown();
|
||||
return vmService;
|
||||
}
|
||||
|
||||
void checkStartEvent(List<Map> events) {
|
||||
|
@ -151,13 +89,9 @@ void checkStartEvent(List<Map> events) {
|
|||
expect(e.length, 2);
|
||||
|
||||
expect(e[0]['name'], 'gRPC Request: $path');
|
||||
expect(e[0]['id'], 0);
|
||||
expect(e[0]['args']['method'], isNotNull);
|
||||
expect(e[0]['args']['method'], equals(path));
|
||||
|
||||
expect(e[1]['name'], 'gRPC Response');
|
||||
expect(e[1]['id'], 1);
|
||||
expect(e[1]['args']['parentId'], 0);
|
||||
}
|
||||
|
||||
void checkSendEvent(List<Map> events) {
|
||||
|
@ -176,7 +110,6 @@ void checkReceiveEvent(List<Map> events) {
|
|||
expect(events.length, equals(3));
|
||||
var sum = 0;
|
||||
for (final e in events) {
|
||||
expect(e['id'], 1);
|
||||
// 3 elements are 1, 2 and 3.
|
||||
sum |= 1 << int.parse(e['args']['data']);
|
||||
}
|
||||
|
@ -187,7 +120,6 @@ void checkReceiveMetaDataEvent(List<Map> events) {
|
|||
events = events.where((e) => e['name'] == 'Metadata received').toList();
|
||||
expect(events.length, equals(2));
|
||||
for (final e in events) {
|
||||
expect(e['id'], 1);
|
||||
if (e['args']['headers'] != null) {
|
||||
final header = e['args']['headers'];
|
||||
expect(header, contains('status: 200'));
|
||||
|
@ -205,11 +137,10 @@ void checkFinishEvent(List<Map> events) {
|
|||
|
||||
void main([args = const <String>[]]) {
|
||||
test('Test gRPC timeline logging', () async {
|
||||
await testee();
|
||||
for (final task in FakeTimelineTask.tasks) {
|
||||
expect(task.isComplete, true);
|
||||
}
|
||||
final events = FakeTimelineTask.events
|
||||
final vmService = await testee();
|
||||
final timeline = await vmService.getVMTimeline();
|
||||
final events = timeline.traceEvents!
|
||||
.map((e) => e.json!)
|
||||
.where((e) => e['args']['filterKey'] == 'grpc/client')
|
||||
.toList();
|
||||
checkStartEvent(events);
|
||||
|
@ -218,5 +149,6 @@ void main([args = const <String>[]]) {
|
|||
checkReceiveEvent(events);
|
||||
checkReceiveMetaDataEvent(events);
|
||||
checkFinishEvent(events);
|
||||
await vmService.dispose();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
dart test
|
||||
dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart
|
Loading…
Reference in New Issue