[System Monitor] test list of inspectable components

This cl tests gathering a list of inspectable
components. Note that this feature is not yet used outside of the test.

Jira: DX-1573
Bug: 62
Test: system_monitor_harvester_tests
Change-Id: I2255942dc2386621d2a73d5ae486473db0c6bd5d
diff --git a/garnet/bin/system_monitor/harvester/BUILD.gn b/garnet/bin/system_monitor/harvester/BUILD.gn
index cca9b8c..73f59b5 100644
--- a/garnet/bin/system_monitor/harvester/BUILD.gn
+++ b/garnet/bin/system_monitor/harvester/BUILD.gn
@@ -32,6 +32,7 @@
   deps = [
     "//garnet/lib/system_monitor/dockyard:lib",
     "//garnet/lib/system_monitor/dockyard:protos",
+    "//garnet/public/lib/inspect/query",
     "//src/lib/fxl",
     "//third_party/grpc:grpc++",
     "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c",
@@ -77,6 +78,7 @@
     "//garnet/lib/system_monitor/dockyard:lib",
     "//garnet/lib/system_monitor/dockyard:protos",
     "//garnet/public/lib/gtest",
+    "//garnet/public/lib/inspect/query",
     "//sdk/lib/sys/cpp/testing:unit",
     "//src/lib/fxl",
     "//src/lib/fxl/test:gtest_main",
diff --git a/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.cc b/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.cc
index 498db75..0ab51d0 100644
--- a/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.cc
+++ b/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.cc
@@ -69,4 +69,28 @@
   return true;
 }
 
+bool DockyardProxyFake::CheckStringPrefixSent(
+    const std::string& dockyard_path_prefix, std::string* string) const {
+  for (const auto& iter : sent_strings_) {
+    if (iter.first.find(dockyard_path_prefix) == 0) {
+      *string = iter.second;
+      return true;
+    }
+  }
+  return false;
+}
+
+std::ostream& operator<<(std::ostream& out, const DockyardProxyFake& dockyard) {
+  out << "DockyardProxyFake:" << std::endl;
+  out << "  Strings:" << std::endl;
+  for (const auto& str : dockyard.sent_strings_) {
+    out << "    " << str.first << ": " << str.second << std::endl;
+  }
+  out << "  Values:" << std::endl;
+  for (const auto& value : dockyard.sent_values_) {
+    out << "    " << value.first << ": " << value.second << std::endl;
+  }
+  return out;
+}
+
 }  // namespace harvester
diff --git a/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.h b/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.h
index 18197d3..eb131ca 100644
--- a/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.h
+++ b/garnet/bin/system_monitor/harvester/dockyard_proxy_fake.h
@@ -41,12 +41,19 @@
                       dockyard::SampleValue* value) const;
   bool CheckStringSent(const std::string& dockyard_path,
                        std::string* string) const;
+  bool CheckStringPrefixSent(const std::string& dockyard_path_prefix,
+                             std::string* string) const;
 
  private:
   std::map<std::string, dockyard::SampleValue> sent_values_;
   std::map<std::string, std::string> sent_strings_;
+
+  friend std::ostream& operator<<(std::ostream& out,
+                                  const DockyardProxyFake& dockyard);
 };
 
+std::ostream& operator<<(std::ostream& out, const DockyardProxyFake& dockyard);
+
 }  // namespace harvester
 
 #endif  // GARNET_BIN_SYSTEM_MONITOR_HARVESTER_DOCKYARD_PROXY_FAKE_H_
diff --git a/garnet/bin/system_monitor/harvester/harvester.cc b/garnet/bin/system_monitor/harvester/harvester.cc
index 6c2773d..18c2ff6 100644
--- a/garnet/bin/system_monitor/harvester/harvester.cc
+++ b/garnet/bin/system_monitor/harvester/harvester.cc
@@ -6,6 +6,7 @@
 
 #include <lib/async/cpp/task.h>
 #include <lib/async/dispatcher.h>
+#include <lib/inspect/query/discover.h>
 #include <lib/zx/time.h>
 #include <task-utils/walker.h>
 #include <zircon/status.h>
@@ -199,7 +200,8 @@
   GatherCpuSamples();
   GatherMemorySamples();
   GatherThreadSamples();
-  // TODO(smbug.com/16): This should be enabled on demand.
+  // TODO(smbug.com/16): These should be enabled on demand.
+  // GatherInspectableComponents();
   // GatherComponentIntrospection();
   // TODO(smbug.com/18): make this actually run at rate (i.e. remove drift from
   // execution time).
@@ -308,6 +310,18 @@
   task_harvester.UploadTaskInfo(dockyard_proxy_);
 }
 
+void Harvester::GatherInspectableComponents() {
+  // Gather a list of components that contain inspect data.
+  const std::string path = "/hub";
+  StringSampleList string_sample_list;
+  for (auto& location : inspect::SyncFindPaths(path)) {
+    std::ostringstream label;
+    label << "inspectable:" << location.AbsoluteFilePath();
+    string_sample_list.emplace_back(label.str(), location.file_name);
+  }
+  dockyard_proxy_->SendStringSampleList(string_sample_list);
+}
+
 void Harvester::GatherComponentIntrospection() {
   std::string fake_json_data = "{ \"test\": 5 }";
   DockyardProxyStatus status = dockyard_proxy_->SendInspectJson(
diff --git a/garnet/bin/system_monitor/harvester/harvester.h b/garnet/bin/system_monitor/harvester/harvester.h
index 1da3c6e..2c27cb3 100644
--- a/garnet/bin/system_monitor/harvester/harvester.h
+++ b/garnet/bin/system_monitor/harvester/harvester.h
@@ -27,6 +27,12 @@
 
   void GatherData();
 
+  // Inspect information for components.
+  void GatherComponentIntrospection();
+
+  // Collect a list of components that have inspect data.
+  void GatherInspectableComponents();
+
  private:
   zx::duration cycle_period_;
   zx_handle_t root_resource_;
@@ -39,8 +45,6 @@
   void GatherCpuSamples();
   void GatherMemorySamples();
   void GatherThreadSamples();
-
-  void GatherComponentIntrospection();
 };
 
 }  // namespace harvester
diff --git a/garnet/bin/system_monitor/harvester/harvester_test.cc b/garnet/bin/system_monitor/harvester/harvester_test.cc
index 093e424..faf1887 100644
--- a/garnet/bin/system_monitor/harvester/harvester_test.cc
+++ b/garnet/bin/system_monitor/harvester/harvester_test.cc
@@ -81,12 +81,27 @@
         ->CheckStringSent(path, value);
   }
 
+  bool CheckStringPrefix(const std::string& path, std::string* value) {
+    return static_cast<harvester::DockyardProxyFake*>(
+               test_harvester->dockyard_proxy_.get())
+        ->CheckStringPrefixSent(path, value);
+  }
+
   bool CheckValue(const std::string& path, dockyard::SampleValue* value) {
     return static_cast<harvester::DockyardProxyFake*>(
                test_harvester->dockyard_proxy_.get())
         ->CheckValueSent(path, value);
   }
 
+  // Dump out the state of the fake dockyard proxy.
+  void DebugDump() {
+    std::cout << "DebugDump:" << std::endl;
+    std::cout << "  self_koid_: " << self_koid_ << std::endl;
+    std::cout << *static_cast<harvester::DockyardProxyFake*>(
+        test_harvester->dockyard_proxy_.get());
+    std::cout << std::endl << std::endl << std::flush;
+  }
+
   // Get a dockyard path for our koid with the given |suffix| key.
   std::string KoidPath(const std::string& suffix) {
     std::ostringstream out;
@@ -102,7 +117,7 @@
   std::string self_koid_;
 };
 
-TEST_F(SystemMonitorHarvesterTest, True) {
+TEST_F(SystemMonitorHarvesterTest, GatherData) {
   // Perform a data gathering pass. This will send samples to the
   // dockyard_proxy.
   test_harvester->GatherData();
@@ -119,3 +134,11 @@
   // that is running.
   EXPECT_EQ("system_monitor_harvester_test.c", test_string);
 }
+
+TEST_F(SystemMonitorHarvesterTest, Inspectable) {
+  test_harvester->GatherInspectableComponents();
+  std::string test_string;
+  EXPECT_TRUE(CheckStringPrefix(
+      "inspectable:/hub/c/system_monitor_harvester_test.cmx/", &test_string));
+  EXPECT_EQ("fuchsia.inspect.Inspect", test_string);
+}