make the log file test less flaky by retrying deletes and reads (#180)

Seeing a lot of flakes on windows for this test, adding some retry logic for deleting the file and also reading from it should make it more reliable.
diff --git a/pkgs/dart_mcp_server/test/dart_tooling_mcp_server_test.dart b/pkgs/dart_mcp_server/test/dart_tooling_mcp_server_test.dart
index 8d8a4c2..607c56e 100644
--- a/pkgs/dart_mcp_server/test/dart_tooling_mcp_server_test.dart
+++ b/pkgs/dart_mcp_server/test/dart_tooling_mcp_server_test.dart
@@ -2,6 +2,7 @@
 // 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:async';
 import 'dart:io';
 
 import 'package:test/test.dart';
@@ -23,16 +24,43 @@
     });
 
     test('logs traffic to a file', () async {
-      expect(
-        await File(logDescriptor.io.path).readAsLines(),
-        containsAll([
-          allOf(startsWith('<<<'), contains('"method":"initialize"')),
-          allOf(startsWith('>>>'), contains('"serverInfo"')),
-          allOf(startsWith('<<<'), contains('"notifications/initialized"')),
-        ]),
+      // It may take a bit for all the lines to show up in the log.
+      await doWithRetries(
+        () async => expect(
+          await File(logDescriptor.io.path).readAsLines(),
+          containsAll([
+            allOf(startsWith('<<<'), contains('"method":"initialize"')),
+            allOf(startsWith('>>>'), contains('"serverInfo"')),
+            allOf(startsWith('<<<'), contains('"notifications/initialized"')),
+          ]),
+        ),
       );
+
       // Ensure the file handle is released before the file is cleaned up.
       await testHarness.serverConnectionPair.serverConnection.shutdown();
+
+      // Wait for the process to release the file.
+      await doWithRetries(() => File(logDescriptor.io.path).delete());
     });
   });
 }
+
+/// Performs [action] up to [maxRetries] times, backing off an extra 50ms
+/// between each attempt.
+FutureOr<T> doWithRetries<T>(
+  FutureOr<T> Function() action, {
+  int maxRetries = 5,
+}) async {
+  var count = 0;
+  while (true) {
+    try {
+      return await action();
+    } catch (_) {
+      if (count == maxRetries) {
+        rethrow;
+      }
+    }
+    count++;
+    await Future<void>.delayed(Duration(milliseconds: 50 * count));
+  }
+}