[System Monitor] move code to get root resource

Move the code to get the root resource into its own .h/.cc and add a _test.cc.
This reduces redundancy and makes it cleaner to add another use of the code in
the future.

Change-Id: I64f6c9830b387a8d79692290b1d2ec9b6ecf5a9b
diff --git a/garnet/bin/system_monitor/harvester/BUILD.gn b/garnet/bin/system_monitor/harvester/BUILD.gn
index fd2a7a0..f9ea387 100644
--- a/garnet/bin/system_monitor/harvester/BUILD.gn
+++ b/garnet/bin/system_monitor/harvester/BUILD.gn
@@ -15,34 +15,44 @@
   ]
 }
 
-executable("bin") {
-  output_name = "system_monitor_harvester"
-
+source_set("lib") {
   sources = [
     "dockyard_proxy.h",
-    "dockyard_proxy_grpc.cc",
-    "dockyard_proxy_grpc.h",
-    "dockyard_proxy_local.cc",
-    "dockyard_proxy_local.h",
     "harvester.cc",
     "harvester.h",
-    "harvester_main.cc",
+    "root_resource.cc",
+    "root_resource.h",
   ]
 
-  deps = [
+  public_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",
     "//zircon/public/lib/async-cpp",
     "//zircon/public/lib/async-loop-cpp",
-    "//zircon/public/lib/fdio",
     "//zircon/public/lib/task-utils",
   ]
 }
 
+executable("bin") {
+  output_name = "system_monitor_harvester"
+
+  sources = [
+    "dockyard_proxy_grpc.cc",
+    "dockyard_proxy_grpc.h",
+    "dockyard_proxy_local.cc",
+    "dockyard_proxy_local.h",
+    "harvester_main.cc",
+  ]
+
+  deps = [
+    ":lib",
+    "//third_party/grpc:grpc++",
+  ]
+}
+
 package("system_monitor_harvester") {
   deprecated_shell = "//build"
 
@@ -68,26 +78,17 @@
   testonly = true
 
   sources = [
-    "dockyard_proxy.h",
     "dockyard_proxy_fake.cc",
     "dockyard_proxy_fake.h",
-    "harvester.cc",
-    "harvester.h",
     "harvester_test.cc",
+    "root_resource_test.cc",
   ]
 
   deps = [
-    "//garnet/lib/system_monitor/dockyard:lib",
-    "//garnet/lib/system_monitor/dockyard:protos",
+    ":lib",
     "//garnet/public/lib/gtest",
-    "//garnet/public/lib/inspect/query",
     "//sdk/lib/sys/cpp/testing:unit",
-    "//src/lib/fxl",
     "//src/lib/fxl/test:gtest_main",
-    "//third_party/grpc:grpc++",
-    "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c",
-    "//zircon/public/lib/task-utils",
-    "//zircon/public/lib/zx",
   ]
 }
 
diff --git a/garnet/bin/system_monitor/harvester/harvester_main.cc b/garnet/bin/system_monitor/harvester/harvester_main.cc
index b5be1ef..8b1be4a 100644
--- a/garnet/bin/system_monitor/harvester/harvester_main.cc
+++ b/garnet/bin/system_monitor/harvester/harvester_main.cc
@@ -2,64 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <fcntl.h>
-#include <fuchsia/sysinfo/c/fidl.h>
-#include <grpc++/grpc++.h>
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/fdio/fdio.h>
-#include <lib/zx/channel.h>
-#include <lib/zx/time.h>
 #include <zircon/status.h>
 
-#include <chrono>
-#include <iostream>
 #include <string>
-#include <thread>
 
 #include "dockyard_proxy.h"
 #include "dockyard_proxy_grpc.h"
 #include "dockyard_proxy_local.h"
 #include "harvester.h"
+#include "root_resource.h"
 #include "src/lib/fxl/command_line.h"
 #include "src/lib/fxl/log_settings_command_line.h"
 #include "src/lib/fxl/logging.h"
 #include "src/lib/fxl/strings/string_number_conversions.h"
 
-namespace {
-
-zx_status_t get_root_resource(zx_handle_t* root_resource) {
-  const char* sysinfo = "/dev/misc/sysinfo";
-  int fd = open(sysinfo, O_RDWR);
-  if (fd < 0) {
-    FXL_LOG(ERROR) << "Cannot open sysinfo: " << strerror(errno);
-    return ZX_ERR_NOT_FOUND;
-  }
-
-  zx::channel channel;
-  zx_status_t status =
-      fdio_get_service_handle(fd, channel.reset_and_get_address());
-  if (status != ZX_OK) {
-    FXL_LOG(ERROR) << "Cannot obtain sysinfo channel: "
-                   << zx_status_get_string(status);
-    return status;
-  }
-
-  zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootResource(
-      channel.get(), &status, root_resource);
-  if (fidl_status != ZX_OK) {
-    FXL_LOG(ERROR) << "Cannot obtain root resource: "
-                   << zx_status_get_string(fidl_status);
-    return fidl_status;
-  } else if (status != ZX_OK) {
-    FXL_LOG(ERROR) << "Cannot obtain root resource: "
-                   << zx_status_get_string(status);
-    return status;
-  }
-  return ZX_OK;
-}
-
-}  // namespace
-
 int main(int argc, char** argv) {
   constexpr int EXIT_CODE_OK = 0;
   // A broad 'something went wrong' error.
@@ -133,7 +91,7 @@
   }
 
   zx_handle_t root_resource;
-  zx_status_t ret = get_root_resource(&root_resource);
+  zx_status_t ret = harvester::GetRootResource(&root_resource);
   if (ret != ZX_OK) {
     exit(EXIT_CODE_GENERAL_ERROR);
   }
diff --git a/garnet/bin/system_monitor/harvester/harvester_test.cc b/garnet/bin/system_monitor/harvester/harvester_test.cc
index 675cb04..25c5674 100644
--- a/garnet/bin/system_monitor/harvester/harvester_test.cc
+++ b/garnet/bin/system_monitor/harvester/harvester_test.cc
@@ -14,33 +14,10 @@
 
 #include "dockyard_proxy_fake.h"
 #include "gtest/gtest.h"
+#include "root_resource.h"
 
 namespace {
 
-zx_status_t get_root_resource(zx_handle_t* root_resource) {
-  const char* sysinfo = "/dev/misc/sysinfo";
-  int fd = open(sysinfo, O_RDWR);
-  if (fd < 0) {
-    return ZX_ERR_NOT_FOUND;
-  }
-
-  zx::channel channel;
-  zx_status_t status =
-      fdio_get_service_handle(fd, channel.reset_and_get_address());
-  if (status != ZX_OK) {
-    return status;
-  }
-
-  zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootResource(
-      channel.get(), &status, root_resource);
-  if (fidl_status != ZX_OK) {
-    return fidl_status;
-  } else if (status != ZX_OK) {
-    return status;
-  }
-  return ZX_OK;
-}
-
 class AsyncDispatcherFake : public async::DispatcherStub {
  public:
   zx::time Now() override { return current_time_; }
@@ -68,7 +45,7 @@
         std::make_unique<harvester::DockyardProxyFake>();
 
     zx_handle_t root_resource;
-    zx_status_t ret = get_root_resource(&root_resource);
+    zx_status_t ret = harvester::GetRootResource(&root_resource);
     EXPECT_EQ(ret, ZX_OK);
 
     test_harvester = std::make_unique<harvester::Harvester>(
diff --git a/garnet/bin/system_monitor/harvester/root_resource.cc b/garnet/bin/system_monitor/harvester/root_resource.cc
new file mode 100644
index 0000000..3487505
--- /dev/null
+++ b/garnet/bin/system_monitor/harvester/root_resource.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "root_resource.h"
+
+#include <fcntl.h>
+#include <fuchsia/sysinfo/c/fidl.h>
+#include <lib/fdio/fdio.h>
+#include <lib/zx/channel.h>
+
+#include "src/lib/fxl/logging.h"
+
+namespace harvester {
+
+zx_status_t GetRootResource(zx_handle_t* root_resource) {
+  const char* sysinfo = "/dev/misc/sysinfo";
+  int fd = open(sysinfo, O_RDWR);
+  if (fd < 0) {
+    FXL_LOG(ERROR) << "Cannot open sysinfo: " << strerror(errno);
+    return ZX_ERR_NOT_FOUND;
+  }
+
+  zx::channel channel;
+  zx_status_t status =
+      fdio_get_service_handle(fd, channel.reset_and_get_address());
+  if (status != ZX_OK) {
+    FXL_LOG(ERROR) << "Cannot obtain sysinfo channel: "
+                   << zx_status_get_string(status);
+    return status;
+  }
+
+  zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootResource(
+      channel.get(), &status, root_resource);
+  if (fidl_status != ZX_OK) {
+    FXL_LOG(ERROR) << "FIDL issue while trying to get root resource: "
+                   << zx_status_get_string(fidl_status);
+    return fidl_status;
+  } else if (status != ZX_OK) {
+    FXL_LOG(ERROR) << "Cannot obtain root resource: "
+                   << zx_status_get_string(status);
+    return status;
+  }
+  return ZX_OK;
+}
+
+}  // namespace harvester
diff --git a/garnet/bin/system_monitor/harvester/root_resource.h b/garnet/bin/system_monitor/harvester/root_resource.h
new file mode 100644
index 0000000..dc83bed
--- /dev/null
+++ b/garnet/bin/system_monitor/harvester/root_resource.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_SYSTEM_MONITOR_HARVESTER_ROOT_RESOURCE_H_
+#define GARNET_BIN_SYSTEM_MONITOR_HARVESTER_ROOT_RESOURCE_H_
+
+#include <zircon/status.h>
+#include <zircon/types.h>
+
+namespace harvester {
+
+// Get a handle to the root resource, which can be used to find its children
+// and so on to review a tree of resources.
+zx_status_t GetRootResource(zx_handle_t* root_resource);
+
+}  // namespace harvester
+
+#endif  // GARNET_BIN_SYSTEM_MONITOR_HARVESTER_ROOT_RESOURCE_H_
diff --git a/garnet/bin/system_monitor/harvester/root_resource_test.cc b/garnet/bin/system_monitor/harvester/root_resource_test.cc
new file mode 100644
index 0000000..fff0040
--- /dev/null
+++ b/garnet/bin/system_monitor/harvester/root_resource_test.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "root_resource.h"
+
+#include <lib/zx/time.h>
+
+#include "gtest/gtest.h"
+
+class SystemMonitorRootResourceTest : public ::testing::Test {};
+
+TEST_F(SystemMonitorRootResourceTest, GatherData) {
+  zx_handle_t root_resource;
+  zx_status_t status = harvester::GetRootResource(&root_resource);
+  EXPECT_EQ(status, ZX_OK);
+  EXPECT_NE(root_resource, ZX_HANDLE_INVALID);
+
+  // Arbitrary choice of system calls to try out the handle.
+  zx_info_cpu_stats_t stats;
+  size_t actual, avail;
+  status = zx_object_get_info(root_resource, ZX_INFO_CPU_STATS, &stats,
+                              sizeof(stats), &actual, &avail);
+  EXPECT_EQ(status, ZX_OK);
+  // This test is not about this data, so only a few sanity checks are
+  // performed.
+  EXPECT_EQ(actual, 1ULL);
+  EXPECT_GT(avail, 0ULL);
+  // Expecting less than 5,000 cores seems reasonable, for now.
+  EXPECT_LT(actual, 5000ULL);
+  EXPECT_GT(stats.idle_time, 0LL);
+  // Assuming less than ten years of accumulated idle time is reasonable.
+  const zx_duration_t TEN_YEARS = 315360000000000000ULL;
+  EXPECT_LT(stats.idle_time, TEN_YEARS);
+  EXPECT_GT(stats.syscalls, 0ULL);
+}