blob: 5cf8e739f89a2b4f63543f88b30acc750d9b124f [file] [log] [blame]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:typed_data';
import 'package:async/async.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test/test.dart';
import 'package:web_socket/web_socket.dart';
import 'close_local_server_vm.dart'
if (dart.library.html) 'close_local_server_web.dart';
import 'continuously_writing_server_vm.dart'
if (dart.library.html) 'continuously_writing_server_web.dart'
as writing_server;
/// Tests that the [WebSocket] can correctly close the connection to the peer.
void testCloseLocal(
Future<WebSocket> Function(Uri uri, {Iterable<String>? protocols})
channelFactory) {
group('remote writing', () {
late Uri uri;
late StreamChannel<Object?> httpServerChannel;
late StreamQueue<Object?> httpServerQueue;
setUp(() async {
httpServerChannel = await writing_server.startServer();
httpServerQueue = StreamQueue(httpServerChannel.stream);
uri = Uri.parse('ws://localhost:${await httpServerQueue.next}');
});
tearDown(() async {
httpServerChannel.sink.add(null);
});
test('peer writes after close are ignored', () async {
final channel = await channelFactory(uri);
await channel.close();
expect(await channel.events.isEmpty, true);
});
});
group('local close', () {
late Uri uri;
late StreamChannel<Object?> httpServerChannel;
late StreamQueue<Object?> httpServerQueue;
setUp(() async {
httpServerChannel = await startServer();
httpServerQueue = StreamQueue(httpServerChannel.stream);
uri = Uri.parse('ws://localhost:${await httpServerQueue.next}');
});
tearDown(() async {
httpServerChannel.sink.add(null);
});
test('reserved close code', () async {
final channel = await channelFactory(uri);
await expectLater(() => channel.close(1004), throwsA(isA<RangeError>()));
});
test('too long close reason', () async {
final channel = await channelFactory(uri);
await expectLater(() => channel.close(3000, 'a'.padLeft(124)),
throwsA(isA<ArgumentError>()));
});
test('close', () async {
final channel = await channelFactory(uri);
await channel.close();
final closeCode = await httpServerQueue.next as int?;
final closeReason = await httpServerQueue.next as String?;
expect(closeCode, 1005);
expect(closeReason, '');
expect(await channel.events.isEmpty, true);
});
test('with code 3000', () async {
final channel = await channelFactory(uri);
await channel.close(3000);
final closeCode = await httpServerQueue.next as int?;
final closeReason = await httpServerQueue.next as String?;
expect(closeCode, 3000);
expect(closeReason, '');
expect(await channel.events.isEmpty, true);
});
test('with code 4999', () async {
final channel = await channelFactory(uri);
await channel.close(4999);
final closeCode = await httpServerQueue.next as int?;
final closeReason = await httpServerQueue.next as String?;
expect(closeCode, 4999);
expect(closeReason, '');
expect(await channel.events.isEmpty, true);
});
test('with code and reason', () async {
final channel = await channelFactory(uri);
await channel.close(3000, 'Client initiated closure');
final closeCode = await httpServerQueue.next as int?;
final closeReason = await httpServerQueue.next as String?;
expect(closeCode, 3000);
expect(closeReason, 'Client initiated closure');
expect(await channel.events.isEmpty, true);
});
test('close after close', () async {
final channel = await channelFactory(uri);
await channel.close(3000, 'Client initiated closure');
await expectLater(
() async => await channel.close(3001, 'Client initiated closure'),
throwsA(isA<WebSocketConnectionClosed>()));
});
test('sendBytes after close', () async {
final channel = await channelFactory(uri);
await channel.close(3000, 'Client initiated closure');
expect(() => channel.sendBytes(Uint8List(10)),
throwsA(isA<WebSocketConnectionClosed>()));
});
test('sendText after close', () async {
final channel = await channelFactory(uri);
await channel.close(3000, 'Client initiated closure');
expect(() => channel.sendText('Hello World'),
throwsA(isA<WebSocketConnectionClosed>()));
});
});
}