blob: be17103f96ca6461b5acee18a0a8960bfe1b8a08 [file] [edit]
// Copyright (c) 2026, 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.
@TestOn('vm')
library;
import 'package:checks/checks.dart';
import 'package:dartpad/src/worker_client.dart';
import 'package:dartpad_worker/src/worker.dart';
import 'package:fake_async/fake_async.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test/test.dart';
import 'asset_server/asset_server_client.dart';
import 'in_process_worker.dart';
extension on Worker {
WorkerClient sessionWithClient({bool keepAlive = true}) {
final controller = StreamChannelController<Object?>();
session(controller.foreign);
return WorkerClient(controller.local, keepAlive: keepAlive);
}
}
void main() => test('idle session timeout and keepAlive', () async {
final server = await AssetServerClient.spawnHybrid();
final worker = await createInProcessWorkerInstance(server, 'dart');
fakeAsync((async) {
final idleClient = worker.sessionWithClient(keepAlive: false);
final recoveringClient = worker.sessionWithClient(keepAlive: false);
final activeClient = worker.sessionWithClient();
// At 5m20s, the 5-minute sweep has started the 40s confirmation timer,
// so idle sessions are still open. Sending a ping from recoveringClient
// both verifies it is still open and rescues it during the 40s window.
async.elapse(const Duration(minutes: 5, seconds: 20));
check(recoveringClient.ping()).completes();
// After the 40s confirmation timer fires (at 5m40s), idleClient is
// closed, while recoveringClient remains open.
async.elapse(const Duration(seconds: 30));
check(idleClient.done).completes();
check(idleClient.ping()).throws();
check(recoveringClient.ping()).completes();
// After another 10 minutes, recoveringClient (keepAlive: false) has now
// timed out, while activeClient's 30s pings keep it open.
async.elapse(const Duration(minutes: 10));
check(recoveringClient.done).completes();
check(activeClient.ping()).completes();
// Flush so ping() completes before close() is called below.
async.flushMicrotasks();
check(activeClient.close()).completes();
// Flush so close() future completes before fakeAsync exits.
async.flushMicrotasks();
});
});