Improve temp test dir cleanup code (#10025)
diff --git a/packages/devtools_app/test/shared/diagnostics/inspector_service_test.dart b/packages/devtools_app/test/shared/diagnostics/inspector_service_test.dart
index 99b2929..655860a 100644
--- a/packages/devtools_app/test/shared/diagnostics/inspector_service_test.dart
+++ b/packages/devtools_app/test/shared/diagnostics/inspector_service_test.dart
@@ -7,8 +7,6 @@
 @TestOn('vm')
 library;
 
-import 'dart:async';
-
 import 'package:devtools_app/devtools_app.dart';
 import 'package:devtools_app_shared/shared.dart';
 import 'package:devtools_app_shared/ui.dart';
@@ -47,7 +45,10 @@
   try {
     group('inspector service tests', () {
       tearDown(env.tearDownEnvironment);
-      tearDownAll(() => unawaited(env.tearDownEnvironment(force: true)));
+      tearDownAll(() async {
+        await env.tearDownEnvironment(force: true);
+        env.finalTeardown();
+      });
 
       test('track widget creation on', () async {
         await env.setupEnvironment();
diff --git a/packages/devtools_app/test/test_infra/flutter_test_environment.dart b/packages/devtools_app/test/test_infra/flutter_test_environment.dart
index 71906b7..b2741f3 100644
--- a/packages/devtools_app/test/test_infra/flutter_test_environment.dart
+++ b/packages/devtools_app/test/test_infra/flutter_test_environment.dart
@@ -200,12 +200,12 @@
     _needsSetup = true;
   }
 
+  /// Deletes the temporary directory created for the test suite.
   void finalTeardown() {
-    // Delete the temporary directory created for the test suite.
-    if (_tempTestAppDirectory != null) {
-      final tempDirectory = Directory(_tempTestAppDirectory!);
+    if (_tempTestAppDirectory case final tempTestAppDirectory?) {
+      final tempDirectory = Directory(tempTestAppDirectory);
       if (tempDirectory.existsSync()) {
-        Directory(_tempTestAppDirectory!).deleteSync(recursive: true);
+        tempDirectory.deleteSync(recursive: true);
       }
     }
   }
diff --git a/packages/devtools_shared/test/deeplink/deeplink_manager_test.dart b/packages/devtools_shared/test/deeplink/deeplink_manager_test.dart
index 5483a19..b176679 100644
--- a/packages/devtools_shared/test/deeplink/deeplink_manager_test.dart
+++ b/packages/devtools_shared/test/deeplink/deeplink_manager_test.dart
@@ -20,13 +20,16 @@
     });
 
     tearDown(() {
-      expect(
-        manager.expectedCommands.isEmpty,
-        true,
-        reason:
-            'stub does not receive expected command ${manager.expectedCommands}',
-      );
-      tmpDir.deleteSync(recursive: true);
+      try {
+        expect(
+          manager.expectedCommands.isEmpty,
+          true,
+          reason:
+              'stub does not receive expected command ${manager.expectedCommands}',
+        );
+      } finally {
+        tmpDir.deleteSync(recursive: true);
+      }
     });
 
     test('getBuildVariants calls flutter command correctly', () async {
diff --git a/packages/devtools_shared/test/helpers/extension_test_manager.dart b/packages/devtools_shared/test/helpers/extension_test_manager.dart
index 00add39..0ff7c63 100644
--- a/packages/devtools_shared/test/helpers/extension_test_manager.dart
+++ b/packages/devtools_shared/test/helpers/extension_test_manager.dart
@@ -28,8 +28,10 @@
 
   Future<void> reset() async {
     // Run with retry to ensure this deletes properly on Windows.
-    await deleteDirectoryWithRetry(testDirectory);
-    _testDirectory = null;
+    if (_testDirectory case final testDirectory?) {
+      await deleteDirectoryWithRetry(testDirectory);
+      _testDirectory = null;
+    }
     _packagesRootUri = null;
     _runtimeAppRoot = null;
   }
diff --git a/packages/devtools_shared/test/helpers/helpers.dart b/packages/devtools_shared/test/helpers/helpers.dart
index 8c03895..0f9dbee 100644
--- a/packages/devtools_shared/test/helpers/helpers.dart
+++ b/packages/devtools_shared/test/helpers/helpers.dart
@@ -63,9 +63,7 @@
 
 class TestDartApp {
   TestDartApp() {
-    directory = Directory(
-      'tmp/test_app_${DateTime.now().millisecondsSinceEpoch}',
-    );
+    directory = Directory.systemTemp.createTempSync('test_app_');
   }
   static final dartVMServiceRegExp = RegExp(
     r'The Dart VM service is listening on (http://127.0.0.1:.*)',
@@ -78,7 +76,7 @@
   StreamSubscription<String>? _stderrSub;
 
   Future<String> start() async {
-    await _initTestApp();
+    _initTestApp();
     process = await Process.start(Platform.resolvedExecutable, [
       '--observe=0',
       'bin/main.dart',
@@ -122,10 +120,10 @@
     await deleteDirectoryWithRetry(directory);
   }
 
-  Future<void> _initTestApp() async {
-    await deleteDirectoryWithRetry(directory);
-    directory.createSync(recursive: true);
-    Directory(path.join(directory.path, '.dart_tool')).createSync();
+  void _initTestApp() {
+    Directory(
+      path.join(directory.path, '.dart_tool'),
+    ).createSync(recursive: true);
 
     final mainFile = File(path.join(directory.path, 'bin', 'main.dart'))
       ..createSync(recursive: true);
diff --git a/packages/devtools_shared/test/server/general_api_test.dart b/packages/devtools_shared/test/server/general_api_test.dart
index 1c57223..0a9fad7 100644
--- a/packages/devtools_shared/test/server/general_api_test.dart
+++ b/packages/devtools_shared/test/server/general_api_test.dart
@@ -186,7 +186,7 @@
           expect(response.success, true);
           expect(response.message, isNull);
           expect(response.uri, isNotNull);
-          expect(response.uri!.toString(), endsWith(app!.directory.path));
+          expect(response.uri!.toFilePath(), endsWith(app!.directory.path));
         });
 
         test('succeeds for a disconnect event when cache is empty', () async {
@@ -223,7 +223,7 @@
             expect(response.success, true);
             expect(response.message, isNull);
             expect(response.uri, isNotNull);
-            expect(response.uri!.toString(), endsWith(app!.directory.path));
+            expect(response.uri!.toFilePath(), endsWith(app!.directory.path));
 
             final disconnectResponse =
                 await server.VmServiceHandler.detectRootPackageForVmService(
@@ -236,7 +236,7 @@
             expect(disconnectResponse.message, isNull);
             expect(disconnectResponse.uri, isNotNull);
             expect(
-              disconnectResponse.uri!.toString(),
+              disconnectResponse.uri!.toFilePath(),
               endsWith(app!.directory.path),
             );
           },
diff --git a/packages/devtools_shared/test/utils/file_utils_test.dart b/packages/devtools_shared/test/utils/file_utils_test.dart
index 03b6c9a..f8b5bdc 100644
--- a/packages/devtools_shared/test/utils/file_utils_test.dart
+++ b/packages/devtools_shared/test/utils/file_utils_test.dart
@@ -56,9 +56,7 @@
       dtd?.process?.kill();
       await dtd?.process?.exitCode;
       dtd = null;
-    });
 
-    tearDownAll(() async {
       // Run with retry to ensure this deletes properly on Windows.
       await deleteDirectoryWithRetry(testDirectory);
     });
diff --git a/tool/lib/commands/rollback.dart b/tool/lib/commands/rollback.dart
index de8c5e9..0a0680a 100644
--- a/tool/lib/commands/rollback.dart
+++ b/tool/lib/commands/rollback.dart
@@ -30,51 +30,59 @@
     final tempDir = (await io.Directory.systemTemp.createTemp(
       'devtools-rollback',
     )).absolute;
-    print('file://${tempDir.path}');
-    final tarball = io.File('${tempDir.path}/devtools.tar.gz');
-    final extractDir = await io.Directory(
-      '${tempDir.path}/extract/',
-    ).absolute.create();
-    final client = io.HttpClient();
-    final version = argResults![_toVersionArg] as String;
-    print('downloading tarball to ${tarball.path}');
-    final tarballRequest = await client.getUrl(
-      Uri.http(
-        'storage.googleapis.com',
-        'pub-packages/packages/devtools-$version.tar.gz',
-      ),
-    );
-    final tarballResponse = await tarballRequest.close();
-    await tarballResponse.pipe(tarball.openWrite());
-    print('Tarball written; unzipping.');
+    try {
+      print('file://${tempDir.path}');
+      final tarball = io.File('${tempDir.path}/devtools.tar.gz');
+      final extractDir = await io.Directory(
+        '${tempDir.path}/extract/',
+      ).absolute.create();
+      final client = io.HttpClient();
+      final version = argResults![_toVersionArg] as String;
+      print('downloading tarball to ${tarball.path}');
+      final tarballRequest = await client.getUrl(
+        Uri.http(
+          'storage.googleapis.com',
+          'pub-packages/packages/devtools-$version.tar.gz',
+        ),
+      );
+      final tarballResponse = await tarballRequest.close();
+      await tarballResponse.pipe(tarball.openWrite());
+      print('Tarball written; unzipping.');
 
-    await io.Process.run('tar', [
-      '-x',
-      '-z',
-      '-f',
-      tarball.path.split('/').last,
-      '-C',
-      extractDir.path,
-    ], workingDirectory: tempDir.path);
-    print('file://${tempDir.path}');
+      await io.Process.run('tar', [
+        '-x',
+        '-z',
+        '-f',
+        tarball.path.split('/').last,
+        '-C',
+        extractDir.path,
+      ], workingDirectory: tempDir.path);
+      print('file://${tempDir.path}');
 
-    final buildDir = io.Directory('${repo.repoPath}/packages/devtools/build/');
-    await buildDir.delete(recursive: true);
-    await io.Directory(
-      '${extractDir.path}build/',
-    ).rename('${repo.repoPath}/packages/devtools/build/');
+      final buildDir = io.Directory(
+        '${repo.repoPath}/packages/devtools/build/',
+      );
+      await buildDir.delete(recursive: true);
+      await io.Directory(
+        '${extractDir.path}build/',
+      ).rename('${repo.repoPath}/packages/devtools/build/');
 
-    print(
-      'Build outputs from Devtools version $version checked out and moved '
-      'to ${buildDir.path}',
-    );
-    print(
-      'To complete the rollback, go to ${repo.repoPath}/packages/devtools, '
-      'rev pubspec.yaml, update the changelog, unhide build/ from the '
-      'packages/devtools/.gitignore file, then run pub publish.',
-    );
-    // TODO(djshuckerow): automatically rev pubspec.yaml and update the
-    // changelog so that the user can just run pub publish from
-    // packages/devtools.
+      print(
+        'Build outputs from Devtools version $version checked out and moved '
+        'to ${buildDir.path}',
+      );
+      print(
+        'To complete the rollback, go to ${repo.repoPath}/packages/devtools, '
+        'rev pubspec.yaml, update the changelog, unhide build/ from the '
+        'packages/devtools/.gitignore file, then run pub publish.',
+      );
+      // TODO(djshuckerow): automatically rev pubspec.yaml and update the
+      // changelog so that the user can just run pub publish from
+      // packages/devtools.
+    } finally {
+      if (await tempDir.exists()) {
+        await tempDir.delete(recursive: true);
+      }
+    }
   }
 }
diff --git a/tool/test/license_utils_test.dart b/tool/test/license_utils_test.dart
index 269d00c..2a4ee55 100644
--- a/tool/test/license_utils_test.dart
+++ b/tool/test/license_utils_test.dart
@@ -60,7 +60,7 @@
       await _setupTestConfigFile();
     });
 
-    tearDownAll(() async {
+    tearDown(() async {
       await deleteDirectoryWithRetry(testDirectory);
     });
 
@@ -171,7 +171,7 @@
       await _setupTestDirectoryStructure();
     });
 
-    tearDownAll(() async {
+    tearDown(() async {
       await deleteDirectoryWithRetry(testDirectory);
     });