mirror of https://github.com/grpc/grpc-dart.git
Deflake keepalive tests (#645)
* Deflake keepalive tests * Add timer * Increase wait timer * Only send ping on open connection * Switch server keepalive to fakeasync * Tiny refactor * Add changelog entry
This commit is contained in:
parent
517cde91a6
commit
b7df4c8290
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
* Add const constructor to `GrpcError` fixing #606.
|
* Add const constructor to `GrpcError` fixing #606.
|
||||||
* Make `GrpcError` non-final to allow implementations.
|
* Make `GrpcError` non-final to allow implementations.
|
||||||
|
* Only send keepalive pings on open connections.
|
||||||
|
|
||||||
## 3.2.2
|
## 3.2.2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,11 @@ class Http2ClientConnection implements connection.ClientConnection {
|
||||||
if (options.keepAlive.shouldSendPings) {
|
if (options.keepAlive.shouldSendPings) {
|
||||||
keepAliveManager = ClientKeepAlive(
|
keepAliveManager = ClientKeepAlive(
|
||||||
options: options.keepAlive,
|
options: options.keepAlive,
|
||||||
ping: () => transport.ping(),
|
ping: () {
|
||||||
|
if (transport.isOpen) {
|
||||||
|
transport.ping();
|
||||||
|
}
|
||||||
|
},
|
||||||
onPingTimeout: () => shutdown(),
|
onPingTimeout: () => shutdown(),
|
||||||
);
|
);
|
||||||
transport.onFrameReceived
|
transport.onFrameReceived
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
await fakeChannel.terminate();
|
await fakeChannel.shutdown();
|
||||||
await server.shutdown();
|
await server.shutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -73,8 +73,12 @@ void main() {
|
||||||
test('Server doesnt terminate connection after pings, as data is sent',
|
test('Server doesnt terminate connection after pings, as data is sent',
|
||||||
() async {
|
() async {
|
||||||
final timer = Timer.periodic(
|
final timer = Timer.periodic(
|
||||||
Duration(milliseconds: 30), (timer) => fakeClient.echo(EchoRequest()));
|
Duration(milliseconds: 10), (timer) => fakeClient.echo(EchoRequest()));
|
||||||
await Future.delayed(Duration(milliseconds: 200), () => timer.cancel());
|
await Future.delayed(Duration(milliseconds: 200), () => timer.cancel());
|
||||||
|
|
||||||
|
// Wait for last request to be sent
|
||||||
|
await Future.delayed(Duration(milliseconds: 20));
|
||||||
|
|
||||||
// Check that the server never closed the connection
|
// Check that the server never closed the connection
|
||||||
expect(fakeChannel.newConnectionCounter, 1);
|
expect(fakeChannel.newConnectionCounter, 1);
|
||||||
});
|
});
|
||||||
|
|
@ -90,7 +94,7 @@ void main() {
|
||||||
|
|
||||||
/// A wrapper around a [FakeHttp2ClientConnection]
|
/// A wrapper around a [FakeHttp2ClientConnection]
|
||||||
class FakeClientChannel extends ClientChannel {
|
class FakeClientChannel extends ClientChannel {
|
||||||
late FakeHttp2ClientConnection fakeHttp2ClientConnection;
|
FakeHttp2ClientConnection? fakeHttp2ClientConnection;
|
||||||
FakeClientChannel(
|
FakeClientChannel(
|
||||||
super.host, {
|
super.host, {
|
||||||
super.port = 443,
|
super.port = 443,
|
||||||
|
|
@ -101,11 +105,11 @@ class FakeClientChannel extends ClientChannel {
|
||||||
@override
|
@override
|
||||||
ClientConnection createConnection() {
|
ClientConnection createConnection() {
|
||||||
fakeHttp2ClientConnection = FakeHttp2ClientConnection(host, port, options);
|
fakeHttp2ClientConnection = FakeHttp2ClientConnection(host, port, options);
|
||||||
return fakeHttp2ClientConnection;
|
return fakeHttp2ClientConnection!;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get newConnectionCounter =>
|
int get newConnectionCounter =>
|
||||||
fakeHttp2ClientConnection.newConnectionCounter;
|
fakeHttp2ClientConnection?.newConnectionCounter ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Http2ClientConnection] exposing a counter for new connections
|
/// A [Http2ClientConnection] exposing a counter for new connections
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:fake_async/fake_async.dart';
|
||||||
import 'package:grpc/src/server/server_keepalive.dart';
|
import 'package:grpc/src/server/server_keepalive.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
|
@ -33,75 +34,83 @@ void main() {
|
||||||
dataStream.close();
|
dataStream.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final timeAfterPing = Duration(milliseconds: 10);
|
||||||
|
|
||||||
test('Sending too many pings without data kills connection', () async {
|
test('Sending too many pings without data kills connection', () async {
|
||||||
initServer();
|
FakeAsync().run((async) {
|
||||||
// Send good ping
|
initServer();
|
||||||
pingStream.sink.add(null);
|
// Send good ping
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
// Send [maxBadPings] bad pings, that's still ok
|
|
||||||
for (var i = 0; i < maxBadPings; i++) {
|
|
||||||
pingStream.sink.add(null);
|
pingStream.sink.add(null);
|
||||||
}
|
async.elapse(timeAfterPing);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
expect(goAway, false);
|
|
||||||
|
|
||||||
// Send another bad ping; that's one too many!
|
// Send [maxBadPings] bad pings, that's still ok
|
||||||
pingStream.sink.add(null);
|
for (var i = 0; i < maxBadPings; i++) {
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
pingStream.sink.add(null);
|
||||||
expect(goAway, true);
|
}
|
||||||
|
async.elapse(timeAfterPing);
|
||||||
|
expect(goAway, false);
|
||||||
|
|
||||||
|
// Send another bad ping; that's one too many!
|
||||||
|
pingStream.sink.add(null);
|
||||||
|
async.elapse(timeAfterPing);
|
||||||
|
expect(goAway, true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
test(
|
test(
|
||||||
'Sending too many pings without data doesn`t kill connection if the server doesn`t care',
|
'Sending too many pings without data doesn`t kill connection if the server doesn`t care',
|
||||||
() async {
|
() async {
|
||||||
initServer(ServerKeepAliveOptions(
|
FakeAsync().run((async) {
|
||||||
maxBadPings: null,
|
initServer(ServerKeepAliveOptions(
|
||||||
minIntervalBetweenPingsWithoutData: Duration(milliseconds: 5),
|
maxBadPings: null,
|
||||||
));
|
minIntervalBetweenPingsWithoutData: Duration(milliseconds: 5),
|
||||||
// Send good ping
|
));
|
||||||
pingStream.sink.add(null);
|
// Send good ping
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
// Send a lot of bad pings, that's still ok.
|
|
||||||
for (var i = 0; i < 50; i++) {
|
|
||||||
pingStream.sink.add(null);
|
pingStream.sink.add(null);
|
||||||
}
|
async.elapse(timeAfterPing);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
expect(goAway, false);
|
// Send a lot of bad pings, that's still ok.
|
||||||
|
for (var i = 0; i < 50; i++) {
|
||||||
|
pingStream.sink.add(null);
|
||||||
|
}
|
||||||
|
async.elapse(timeAfterPing);
|
||||||
|
expect(goAway, false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Sending many pings with data doesn`t kill connection', () async {
|
test('Sending many pings with data doesn`t kill connection', () async {
|
||||||
initServer();
|
FakeAsync().run((async) {
|
||||||
|
initServer();
|
||||||
|
|
||||||
// Send good ping
|
// Send good ping
|
||||||
pingStream.sink.add(null);
|
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
// Send [maxBadPings] bad pings, that's still ok
|
|
||||||
for (var i = 0; i < maxBadPings; i++) {
|
|
||||||
pingStream.sink.add(null);
|
pingStream.sink.add(null);
|
||||||
}
|
async.elapse(timeAfterPing);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
expect(goAway, false);
|
|
||||||
|
|
||||||
// Sending data resets the bad ping count
|
// Send [maxBadPings] bad pings, that's still ok
|
||||||
dataStream.add(null);
|
for (var i = 0; i < maxBadPings; i++) {
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
pingStream.sink.add(null);
|
||||||
|
}
|
||||||
|
async.elapse(timeAfterPing);
|
||||||
|
expect(goAway, false);
|
||||||
|
|
||||||
// Send good ping
|
// Sending data resets the bad ping count
|
||||||
pingStream.sink.add(null);
|
dataStream.add(null);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
async.elapse(timeAfterPing);
|
||||||
|
|
||||||
// Send [maxBadPings] bad pings, that's still ok
|
// Send good ping
|
||||||
for (var i = 0; i < maxBadPings; i++) {
|
|
||||||
pingStream.sink.add(null);
|
pingStream.sink.add(null);
|
||||||
}
|
async.elapse(timeAfterPing);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
expect(goAway, false);
|
|
||||||
|
|
||||||
// Send another bad ping; that's one too many!
|
// Send [maxBadPings] bad pings, that's still ok
|
||||||
pingStream.sink.add(null);
|
for (var i = 0; i < maxBadPings; i++) {
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
pingStream.sink.add(null);
|
||||||
expect(goAway, true);
|
}
|
||||||
|
async.elapse(timeAfterPing);
|
||||||
|
expect(goAway, false);
|
||||||
|
|
||||||
|
// Send another bad ping; that's one too many!
|
||||||
|
pingStream.sink.add(null);
|
||||||
|
async.elapse(timeAfterPing);
|
||||||
|
expect(goAway, true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue