blob: af2a2000083479fbc1d360962b4f6eb3f025733b [file]
// Copyright (c) 2025, 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:io';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import '../utils.dart';
import 'client_simulator.dart';
import 'file_changer.dart';
/// End to end test using a [FileChanger] that randomly changes files, then a
/// [ClientSimulator] that tracks state using a Watcher.
///
/// The test passes if the [ClientSimulator] tracking matches what's actually on
/// disk.
///
/// Fails on Linux due to https://github.com/dart-lang/tools/issues/2228.
///
/// Fails sometimes on Windows due to
/// https://github.com/dart-lang/tools/issues/2234.
void endToEndTests({required bool isNative}) {
test('end to end test', timeout: const Timeout(Duration(minutes: 5)),
() async {
final temp = Directory.systemTemp.createTempSync();
addTearDown(() => temp.deleteSync(recursive: true));
// Start with some files.
final changer = FileChanger(temp.path);
await changer.changeFiles(times: 100);
// Create the watcher and [ClientSimulator].
final watcher = createWatcher(path: temp.path);
final client = await ClientSimulator.watch(watcher);
addTearDown(client.close);
// 20 iterations of making changes, waiting for events to settle, and
// checking for consistency.
for (var i = 0; i != 20; ++i) {
// File changes.
final messages = await changer.changeFiles(times: 100);
// Give time for events to arrive. To allow tests to run quickly when the
// events are handled quickly, poll and continue if verification passes.
for (var waits = 0; waits != 20; ++waits) {
if (client.verify(log: false)) {
break;
}
await client.waitForNoEvents(const Duration(milliseconds: 100));
}
// Verify for real and fail the test if still not consistent.
if (!client.verify(log: true)) {
if (Platform.isLinux && isNative) {
print('Ignoring expected failure for Linux native watcher.');
return;
}
// Write the file operations before the failure to a log, fail the test.
final logTemp = Directory.systemTemp.createTempSync();
final fileChangesLogPath = p.join(logTemp.path, 'changes.txt');
File(fileChangesLogPath)
.writeAsStringSync(messages.map((m) => '$m\n').join(''));
final clientLogPath = p.join(logTemp.path, 'client.txt');
File(clientLogPath)
.writeAsStringSync(client.messages.map((m) => '$m\n').join(''));
fail('''
Failed on run $i.
Files changes: $fileChangesLogPath
Client log: $clientLogPath''');
}
}
if (Platform.isLinux && isNative) {
fail('Expected Linux native watcher failure, but test passed!');
}
// Can't expect the Windows failure as it does sometimes succeed.
});
}