[inspect][dart] Expose VMO file in diagnostics, not in debug

BUG=41194
TESTED=dart inspect tests

Change-Id: I09f2d246c22f9d64d7cd39e86e6ff1862015bd3d
diff --git a/public/dart/fuchsia_inspect/examples/inspect_mod/test/inspect_mod_test.dart b/public/dart/fuchsia_inspect/examples/inspect_mod/test/inspect_mod_test.dart
index ee4cc58..08d7357 100644
--- a/public/dart/fuchsia_inspect/examples/inspect_mod/test/inspect_mod_test.dart
+++ b/public/dart/fuchsia_inspect/examples/inspect_mod/test/inspect_mod_test.dart
@@ -111,10 +111,10 @@
     // TODO(fxb/38305): Address or remove this old TODO, and reenable test in //topaz/BUILD.gn.
     //   CL should have landed so stories reuse session envs. This breaks hardcoded inspect paths.
     //   Old TODO(vickiecheng): remove this one once stories reuse session envs.
-    '/hub/r/modular_test_harness_*/*/r/session-*/*/r/*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/debug/root.inspect',
-    '/hub/r/modular_test_harness_*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/debug/root.inspect',
-    '/hub/r/mth_*/*/r/session-*/*/r/*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/debug/root.inspect',
-    '/hub/r/mth_*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/debug/root.inspect',
+    '/hub/r/modular_test_harness_*/*/r/session-*/*/r/*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/(debug|diagnostics)/root.inspect',
+    '/hub/r/modular_test_harness_*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/(debug|diagnostics)/root.inspect',
+    '/hub/r/mth_*/*/r/session-*/*/r/*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/(debug|diagnostics)/root.inspect',
+    '/hub/r/mth_*/*/c/flutter_*_runner.cmx/*/c/$_testAppName/*/out/(debug|diagnostics)/root.inspect',
   ];
   for (final globString in globs) {
     await for (var f in Glob(globString).list()) {
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart b/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
index 85c86f0..d925662 100644
--- a/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
@@ -58,8 +58,8 @@
     if (_singleton == null) {
       var context = StartupContext.fromStartupInfo();
       var writer = VmoWriter.withSize(vmoSize);
-      _singleton =
-          InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+      _singleton = InspectImpl(
+          context.outgoing.diagnosticsDir(), 'root.inspect', writer);
     }
     return _singleton;
   }
@@ -76,7 +76,7 @@
     var context = StartupContext.fromStartupInfo();
     var writer = VmoWriter.withSize(vmoSize);
     var fileName = _nextInstanceWithName(name);
-    return InspectImpl(context.outgoing.debugDir(), fileName, writer);
+    return InspectImpl(context.outgoing.diagnosticsDir(), fileName, writer);
   }
 
   /// Mounts an [Inspect] file at <name>.inspect whose contents are
@@ -86,7 +86,7 @@
   /// name, a unique number will be appended to the name.
   static void onDemand(String name, OnDemandRootFn rootNodeCallback) {
     var context = StartupContext.fromStartupInfo();
-    var directory = context.outgoing.debugDir();
+    var directory = context.outgoing.diagnosticsDir();
     var fileName = _nextInstanceWithName(name);
     var pseudoVmoNode = PseudoVmoFile.readOnly(() {
       var writer = VmoWriter.withSize(vmoSize);
diff --git a/public/dart/fuchsia_inspect/test/inspect/internal/inspect_impl_test.dart b/public/dart/fuchsia_inspect/test/inspect/internal/inspect_impl_test.dart
index 59ccc63..3bbecea 100644
--- a/public/dart/fuchsia_inspect/test/inspect/internal/inspect_impl_test.dart
+++ b/public/dart/fuchsia_inspect/test/inspect/internal/inspect_impl_test.dart
@@ -17,7 +17,7 @@
     var writer = VmoWriter.withVmo(vmo);
 
     var inspect =
-        InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+        InspectImpl(context.outgoing.diagnosticsDir(), 'root.inspect', writer);
     expect(inspect.root, isNotNull);
   });
 }
diff --git a/public/dart/fuchsia_inspect/test/inspect/node_test.dart b/public/dart/fuchsia_inspect/test/inspect/node_test.dart
index f62caf8..5f95c08 100644
--- a/public/dart/fuchsia_inspect/test/inspect/node_test.dart
+++ b/public/dart/fuchsia_inspect/test/inspect/node_test.dart
@@ -22,7 +22,7 @@
     vmo = FakeVmoHolder(512);
     var writer = VmoWriter.withVmo(vmo);
     Inspect inspect =
-        InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+        InspectImpl(context.outgoing.diagnosticsDir(), 'root.inspect', writer);
     root = inspect.root;
   });
 
@@ -174,8 +174,8 @@
       var tinyVmo = FakeVmoHolder(64);
       var writer = VmoWriter.withVmo(tinyVmo);
       var context = StartupContext.fromStartupInfo();
-      Inspect inspect =
-          InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+      Inspect inspect = InspectImpl(
+          context.outgoing.diagnosticsDir(), 'root.inspect', writer);
       tinyRoot = inspect.root;
     });
 
diff --git a/public/dart/fuchsia_inspect/test/inspect/property_test.dart b/public/dart/fuchsia_inspect/test/inspect/property_test.dart
index c4c4cb0..71069c0 100644
--- a/public/dart/fuchsia_inspect/test/inspect/property_test.dart
+++ b/public/dart/fuchsia_inspect/test/inspect/property_test.dart
@@ -22,7 +22,7 @@
     vmo = FakeVmoHolder(512);
     var writer = VmoWriter.withVmo(vmo);
     Inspect inspect =
-        InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+        InspectImpl(context.outgoing.diagnosticsDir(), 'root.inspect', writer);
     node = inspect.root;
   });
 
@@ -203,8 +203,8 @@
       var tinyVmo = FakeVmoHolder(64);
       var writer = VmoWriter.withVmo(tinyVmo);
       var context = StartupContext.fromStartupInfo();
-      Inspect inspect =
-          InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+      Inspect inspect = InspectImpl(
+          context.outgoing.diagnosticsDir(), 'root.inspect', writer);
       var tinyRoot = inspect.root;
       var missingProperty = tinyRoot.stringProperty('missing');
       expect(() => missingProperty.setValue('something'), returnsNormally);
@@ -215,8 +215,8 @@
       var tinyVmo = FakeVmoHolder(64);
       var writer = VmoWriter.withVmo(tinyVmo);
       var context = StartupContext.fromStartupInfo();
-      Inspect inspect =
-          InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+      Inspect inspect = InspectImpl(
+          context.outgoing.diagnosticsDir(), 'root.inspect', writer);
       var tinyRoot = inspect.root;
       var bytes = toByteData('this will not set');
       var missingProperty = tinyRoot.byteDataProperty('missing');
@@ -425,8 +425,8 @@
       var tinyVmo = FakeVmoHolder(64);
       var writer = VmoWriter.withVmo(tinyVmo);
       var context = StartupContext.fromStartupInfo();
-      Inspect inspect =
-          InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+      Inspect inspect = InspectImpl(
+          context.outgoing.diagnosticsDir(), 'root.inspect', writer);
       var tinyRoot = inspect.root;
       var missingProperty = tinyRoot.intProperty('missing');
       expect(() => missingProperty.setValue(1), returnsNormally);
@@ -437,8 +437,8 @@
       var tinyVmo = FakeVmoHolder(64);
       var writer = VmoWriter.withVmo(tinyVmo);
       var context = StartupContext.fromStartupInfo();
-      Inspect inspect =
-          InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+      Inspect inspect = InspectImpl(
+          context.outgoing.diagnosticsDir(), 'root.inspect', writer);
       var tinyRoot = inspect.root;
       var missingProperty = tinyRoot.doubleProperty('missing');
       expect(() => missingProperty.setValue(1.0), returnsNormally);
@@ -453,9 +453,9 @@
     var writer2 = VmoWriter.withVmo(tinyVmo2);
     var context = StartupContext.fromStartupInfo();
     Inspect inspect =
-        InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+        InspectImpl(context.outgoing.diagnosticsDir(), 'root.inspect', writer);
     Inspect inspect2 =
-        InspectImpl(context.outgoing.debugDir(), 'test.inspect', writer2);
+        InspectImpl(context.outgoing.diagnosticsDir(), 'test.inspect', writer2);
     expect(() => inspect, isNotNull);
     expect(() => inspect2, isNotNull);
   });
diff --git a/public/dart/fuchsia_inspect/test/inspect_flutter_integration_tester/test/integration_driver_test.dart b/public/dart/fuchsia_inspect/test/inspect_flutter_integration_tester/test/integration_driver_test.dart
index 6763622..68608f5 100644
--- a/public/dart/fuchsia_inspect/test/inspect_flutter_integration_tester/test/integration_driver_test.dart
+++ b/public/dart/fuchsia_inspect/test/inspect_flutter_integration_tester/test/integration_driver_test.dart
@@ -137,8 +137,8 @@
     // TODO(fxb/38305): Address and/or update above TODO, and reenable test in //topaz/BUILD.gn.
     //   CL should have landed so stories reuse session envs. This breaks hardcoded inspect paths.
     var globs = [
-      '/hub/r/modular_test_harness_*/*/r/session-*/*/r/*/*/c/flutter*/*/c/$_testAppName/*/out/debug/*',
-      '/hub/r/mth_*/*/r/session-*/*/r/*/*/c/flutter*/*/c/$_testAppName/*/out/debug/*'
+      '/hub/r/modular_test_harness_*/*/r/session-*/*/r/*/*/c/flutter*/*/c/$_testAppName/*/out/diagnostics/*',
+      '/hub/r/mth_*/*/r/session-*/*/r/*/*/c/flutter*/*/c/$_testAppName/*/out/diagnostics/*'
     ];
     for (final globString in globs) {
       var fileEntity = await Glob(globString).list().toList();
diff --git a/public/dart/fuchsia_inspect/test/integration/test.cc b/public/dart/fuchsia_inspect/test/integration/test.cc
index 022e2fa..6da3623 100644
--- a/public/dart/fuchsia_inspect/test/integration/test.cc
+++ b/public/dart/fuchsia_inspect/test/integration/test.cc
@@ -64,7 +64,7 @@
   fit::result<fuchsia::io::FileSyncPtr, zx_status_t> OpenInspectVmoFile(
       const std::string& file_name) {
     files::Glob glob(
-        Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/debug/$1.inspect",
+        Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/diagnostics/$1.inspect",
                    kTestProcessName, file_name));
     if (glob.size() == 0) {
       printf("Size == 0\n");
@@ -214,10 +214,10 @@
 
 TEST_F(InspectTest, NamedInspectVisible) {
   files::Glob glob1(
-      Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/debug/$1.inspect",
+      Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/diagnostics/$1.inspect",
                  kTestProcessName, kTestInspectFileName1));
   files::Glob glob2(
-      Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/debug/$1.inspect",
+      Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/diagnostics/$1.inspect",
                  kTestProcessName, kTestInspectFileName2));
   EXPECT_TRUE(glob1.size() > 0);
   EXPECT_TRUE(glob2.size() > 0);
diff --git a/public/dart/fuchsia_services/lib/src/outgoing.dart b/public/dart/fuchsia_services/lib/src/outgoing.dart
index f260ffc..4f81a89 100644
--- a/public/dart/fuchsia_services/lib/src/outgoing.dart
+++ b/public/dart/fuchsia_services/lib/src/outgoing.dart
@@ -12,6 +12,7 @@
   final vfs.PseudoDir _root = vfs.PseudoDir();
   final vfs.PseudoDir _public = vfs.PseudoDir();
   final vfs.PseudoDir _debug = vfs.PseudoDir();
+  final vfs.PseudoDir _diagnostics = vfs.PseudoDir();
   final vfs.PseudoDir _ctrl = vfs.PseudoDir();
   bool _isClosed = false;
 
@@ -26,6 +27,7 @@
       ..addNode('public', _public)
       ..addNode('svc', _public)
       ..addNode('debug', _debug)
+      ..addNode('diagnostics', _diagnostics)
       ..addNode('ctrl', _ctrl);
   }
 
@@ -64,6 +66,12 @@
     return _debug;
   }
 
+  /// return diagnostics directory which can be used to publish debug info to /hub
+  vfs.PseudoDir diagnosticsDir() {
+    _ensureNotClosed();
+    return _diagnostics;
+  }
+
   /// return public directory which usually contains all published services.
   vfs.PseudoDir publicDir() {
     _ensureNotClosed();
diff --git a/public/dart/fuchsia_services/test/outgoing_test.dart b/public/dart/fuchsia_services/test/outgoing_test.dart
index 73c96e9..409e942 100644
--- a/public/dart/fuchsia_services/test/outgoing_test.dart
+++ b/public/dart/fuchsia_services/test/outgoing_test.dart
@@ -4,9 +4,12 @@
 
 // ignore_for_file: implementation_imports
 import 'dart:async';
+import 'dart:convert' show utf8;
 import 'package:fidl/fidl.dart';
 import 'package:fidl_fuchsia_io/fidl_async.dart';
 import 'package:fuchsia_services/src/outgoing.dart';
+import 'package:fidl_fuchsia_io/fidl_async.dart' as io;
+import 'package:fuchsia_vfs/vfs.dart';
 import 'package:test/test.dart';
 
 void main() {
@@ -46,5 +49,23 @@
         expect(response, true);
       }, count: 2));
     });
+
+    test('diagnostics dir', () async {
+      final outgoingImpl = Outgoing();
+      final dirProxy = DirectoryProxy();
+      outgoingImpl
+          .diagnosticsDir()
+          .addNode('foo', PseudoFile.readOnlyStr(() => 'test'));
+      outgoingImpl
+          .serve(InterfaceRequest(dirProxy.ctrl.request().passChannel()));
+      final fileProxy = io.FileProxy();
+      await dirProxy.open(
+          io.openRightReadable,
+          io.modeTypeFile,
+          'diagnostics/foo',
+          InterfaceRequest<io.Node>(fileProxy.ctrl.request().passChannel()));
+      final response = await fileProxy.read(io.maxBuf);
+      expect(utf8.decode(response.data), 'test');
+    });
   });
 }