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:
Moritz 2023-06-07 10:24:33 +02:00 committed by GitHub
parent 244dea0361
commit f420b77a22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 39 additions and 105 deletions

View File

@ -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

View File

@ -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

View File

@ -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: {

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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();
});
}

4
tool/test_all.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
dart test
dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart