[weave] Add unittests for WeaveInspector

Add unittests for WeaveInspector module.

Bug: 73583
Test: fx test weavestack-adaptation-unittests

Change-Id: I40efce649200dc01c818aeae889d34fb0ba14b01
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/510441
Commit-Queue: Neethu Joseph <neethujoseph@google.com>
Reviewed-by: Sundarajan Srinivasan <sundarsrini@google.com>
Reviewed-by: Prashanth Swaminathan <prashanthsw@google.com>
diff --git a/src/connectivity/weave/adaptation/tests/BUILD.gn b/src/connectivity/weave/adaptation/tests/BUILD.gn
index 040c585..f13f3dc 100644
--- a/src/connectivity/weave/adaptation/tests/BUILD.gn
+++ b/src/connectivity/weave/adaptation/tests/BUILD.gn
@@ -58,6 +58,11 @@
   deps = [ ":weave_config_manager_unittests" ]
 }
 
+fuchsia_unittest_component("weave-inspector-test") {
+  manifest = rebase_path("meta/weave_inspector_unittests.cmx")
+  deps = [ ":weave_inspector_unittests" ]
+}
+
 test("ble_manager_unittests") {
   output_name = "ble_manager_unittests"
   sources = [ "ble_manager_unittests.cpp" ]
@@ -115,6 +120,15 @@
   ]
 }
 
+test("weave_inspector_unittests") {
+  output_name = "weave_inspector_unittests"
+  sources = [ "weave_inspector_unittests.cpp" ]
+  deps = [
+    ":common_test_deps",
+    "//sdk/lib/inspect/testing/cpp",
+  ]
+}
+
 resource("weavestack-adaptation-resources") {
   sources = [
     "../../weavestack/data/default_environment_schema.json",
@@ -161,6 +175,7 @@
     ":thread-stack-manager-test",
     ":warm-platform-support-test",
     ":weave-config-manager-test",
+    ":weave-inspector-test",
   ]
   test_specs = {
     log_settings = {
diff --git a/src/connectivity/weave/adaptation/tests/meta/weave_inspector_unittests.cmx b/src/connectivity/weave/adaptation/tests/meta/weave_inspector_unittests.cmx
new file mode 100644
index 0000000..ad9d249
--- /dev/null
+++ b/src/connectivity/weave/adaptation/tests/meta/weave_inspector_unittests.cmx
@@ -0,0 +1,8 @@
+{
+    "include": [
+        "sdk/lib/diagnostics/syslog/client.shard.cmx"
+    ],
+    "program": {
+        "binary": "test/weave_inspector_unittests"
+    }
+}
diff --git a/src/connectivity/weave/adaptation/tests/weave_inspector_unittests.cpp b/src/connectivity/weave/adaptation/tests/weave_inspector_unittests.cpp
new file mode 100644
index 0000000..7ef4ff7
--- /dev/null
+++ b/src/connectivity/weave/adaptation/tests/weave_inspector_unittests.cpp
@@ -0,0 +1,248 @@
+// Copyright 2021 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 <lib/gtest/real_loop_fixture.h>
+#include <lib/inspect/cpp/inspect.h>
+#include <lib/inspect/testing/cpp/inspect.h>
+
+#include "weave_inspector.h"
+
+namespace nl::Weave::testing {
+
+// Inspect Node names
+const std::string kNode_Reason = "reason";
+const std::string kNode_State = "state";
+const std::string kNode_Time = "@time";
+const std::string kNode_Type = "type";
+const std::string kNode_TunnelStatus = "tunnel_status";
+const std::string kNode_TunnelStatus_TimeTunnelDown = "last_time_tunnel_down";
+const std::string kNode_TunnelStatus_TimeTunnelEstablish = "last_time_tunnel_established";
+const std::string kNode_WeaveStatus = "weave_status";
+const std::string kNode_WeaveStatus_FailsafeState = "failsafe_state";
+const std::string kNode_WeaveStatus_PairingState = "pairing_state";
+const std::string kNode_WeaveStatus_TunnelState = "tunnel_state";
+const std::string kNode_WeaveStatus_TunnelState_IsRestricted = "is_restricted";
+const std::string kNode_WeaveStatus_SetupState = "setup_state";
+
+class WeaveInspectorTest : public ::gtest::RealLoopFixture {
+ public:
+  // Get the underlying inspect::Inspector for Weave component.
+  inspect::Inspector* GetInspector() {
+    auto& weave_inspector = GetTestWeaveInspector();
+    return weave_inspector.inspector_->inspector();
+  }
+
+  // Return WeaveInspector for test.
+  WeaveInspector& GetTestWeaveInspector() { return weave_inspector_; }
+
+  // Validate single Weave status entry node.
+  void ValidateWeaveStatusEntryNode(
+      const inspect::Hierarchy* weave_status_node,
+      WeaveInspector::WeaveStatusNode::WeaveCurrentStatus weave_status_info) {
+    ASSERT_TRUE(weave_status_node);
+
+    auto* timestamp =
+        weave_status_node->node().get_property<inspect::UintPropertyValue>(kNode_Time);
+    ASSERT_TRUE(timestamp);
+
+    auto* pairing_state = weave_status_node->node().get_property<inspect::StringPropertyValue>(
+        kNode_WeaveStatus_PairingState);
+    ASSERT_TRUE(pairing_state);
+    EXPECT_EQ(pairing_state->value(), weave_status_info.pairing_state_);
+
+    auto* setup_state = weave_status_node->node().get_property<inspect::StringPropertyValue>(
+        kNode_WeaveStatus_SetupState);
+    ASSERT_TRUE(setup_state);
+    EXPECT_EQ(setup_state->value(), weave_status_info.setup_state_);
+
+    auto* tunnel_state = weave_status_node->GetByPath({kNode_WeaveStatus_TunnelState});
+    ASSERT_TRUE(tunnel_state);
+
+    auto* is_restricted = tunnel_state->node().get_property<inspect::BoolPropertyValue>(
+        kNode_WeaveStatus_TunnelState_IsRestricted);
+    ASSERT_TRUE(setup_state);
+    EXPECT_EQ(is_restricted->value(), weave_status_info.tunnel_restricted_);
+
+    auto* tunnel_state_value =
+        tunnel_state->node().get_property<inspect::StringPropertyValue>(kNode_State);
+    ASSERT_TRUE(setup_state);
+    EXPECT_EQ(tunnel_state_value->value(), weave_status_info.tunnel_state_);
+
+    auto* tunnel_state_type =
+        tunnel_state->node().get_property<inspect::StringPropertyValue>(kNode_Type);
+    ASSERT_TRUE(tunnel_state_type);
+    EXPECT_EQ(tunnel_state_type->value(), weave_status_info.tunnel_type_);
+
+    auto* failsafe_state = weave_status_node->GetByPath({kNode_WeaveStatus_FailsafeState});
+    ASSERT_TRUE(failsafe_state);
+
+    auto* failsafe_state_value =
+        failsafe_state->node().get_property<inspect::StringPropertyValue>(kNode_State);
+    ASSERT_TRUE(failsafe_state_value);
+    EXPECT_EQ(failsafe_state_value->value(), weave_status_info.failsafe_state_);
+
+    auto* failsafe_state_reason =
+        failsafe_state->node().get_property<inspect::StringPropertyValue>(kNode_Reason);
+    ASSERT_TRUE(failsafe_state_reason);
+    EXPECT_EQ(failsafe_state_reason->value(), weave_status_info.failsafe_state_reason_);
+  }
+
+  // Returns Weave status info filled with init values.
+  WeaveInspector::WeaveStatusNode::WeaveCurrentStatus GetInitializedWeaveStatusInfo() {
+    WeaveInspector::WeaveStatusNode::WeaveCurrentStatus weave_status_info;
+    weave_status_info.tunnel_restricted_ = false;
+    weave_status_info.tunnel_state_ = WeaveInspector::kTunnelState_NoTunnel;
+    weave_status_info.tunnel_type_ = WeaveInspector::kTunnelType_None;
+    weave_status_info.failsafe_state_ = WeaveInspector::kFailSafeState_Disarmed;
+    weave_status_info.failsafe_state_reason_ = WeaveInspector::kFailSafeReason_Init;
+    weave_status_info.pairing_state_ = WeaveInspector::kPairingState_Initialized;
+    weave_status_info.setup_state_ = WeaveInspector::kSetupState_Initialized;
+    return weave_status_info;
+  }
+
+ private:
+  WeaveInspector weave_inspector_;
+};
+
+TEST_F(WeaveInspectorTest, NotifyInit) {
+  auto& weave_inspector = GetTestWeaveInspector();
+  weave_inspector.NotifyInit();
+
+  fit::result<inspect::Hierarchy> hierarchy =
+      RunPromise(inspect::ReadFromInspector(*GetInspector()));
+  ASSERT_TRUE(hierarchy.is_ok());
+
+  auto* tunnel_status = hierarchy.value().GetByPath({kNode_TunnelStatus});
+  ASSERT_TRUE(tunnel_status);
+
+  auto* last_time_tunnel_down = tunnel_status->node().get_property<inspect::UintPropertyValue>(
+      kNode_TunnelStatus_TimeTunnelDown);
+  ASSERT_TRUE(last_time_tunnel_down);
+  EXPECT_EQ(last_time_tunnel_down->value(), 0u);
+
+  auto* last_time_tunnel_up = tunnel_status->node().get_property<inspect::UintPropertyValue>(
+      kNode_TunnelStatus_TimeTunnelEstablish);
+  ASSERT_TRUE(last_time_tunnel_up);
+  EXPECT_EQ(last_time_tunnel_up->value(), 0u);
+
+  auto* weave_status = hierarchy.value().GetByPath({kNode_WeaveStatus});
+  ASSERT_TRUE(weave_status);
+
+  auto* weave_status_node = weave_status->GetByPath({"0x0"});
+
+  ValidateWeaveStatusEntryNode(weave_status_node, GetInitializedWeaveStatusInfo());
+}
+
+TEST_F(WeaveInspectorTest, NotifyWeaveStatusChanges) {
+  auto status = GetInitializedWeaveStatusInfo();
+  auto& weave_inspector = GetTestWeaveInspector();
+
+  weave_inspector.NotifySetupStateChange(WeaveInspector::kSetupState_PASESessionEstablished);
+  weave_inspector.NotifyFailSafeStateChange(WeaveInspector::kFailSafeState_Armed,
+                                            WeaveInspector::kFailSafeReason_Nominal);
+  weave_inspector.NotifyPairingStateChange(WeaveInspector::kPairingState_FabricCreatedOrJoined);
+  weave_inspector.NotifyPairingStateChange(
+      WeaveInspector::kPairingState_ThreadNetworkCreatedOrJoined);
+  weave_inspector.NotifyTunnelStateChange(WeaveInspector::kTunnelState_PrimaryTunMode,
+                                          WeaveInspector::kTunnelType_Primary, true);
+  weave_inspector.NotifyTunnelStateChange(WeaveInspector::kTunnelState_PrimaryTunMode,
+                                          WeaveInspector::kTunnelType_Primary, false);
+  weave_inspector.NotifyFailSafeStateChange(WeaveInspector::kFailSafeState_Armed,
+                                            WeaveInspector::kFailSafeReason_FailsafeDisarmFailed);
+
+  fit::result<inspect::Hierarchy> hierarchy =
+      RunPromise(inspect::ReadFromInspector(*GetInspector()));
+  ASSERT_TRUE(hierarchy.is_ok());
+
+  auto* weave_status = hierarchy.value().GetByPath({kNode_WeaveStatus});
+  ASSERT_TRUE(weave_status);
+
+  auto* weave_status_node_0 = weave_status->GetByPath({"0x0"});
+  status.setup_state_ = WeaveInspector::kSetupState_PASESessionEstablished;
+  ValidateWeaveStatusEntryNode(weave_status_node_0, status);
+
+  auto* weave_status_node_1 = weave_status->GetByPath({"0x1"});
+  status.failsafe_state_ = WeaveInspector::kFailSafeState_Armed;
+  status.failsafe_state_reason_ = WeaveInspector::kFailSafeReason_Nominal;
+  ValidateWeaveStatusEntryNode(weave_status_node_1, status);
+
+  auto* weave_status_node_2 = weave_status->GetByPath({"0x2"});
+  status.pairing_state_ = WeaveInspector::kPairingState_FabricCreatedOrJoined;
+  ValidateWeaveStatusEntryNode(weave_status_node_2, status);
+
+  auto* weave_status_node_3 = weave_status->GetByPath({"0x3"});
+  status.pairing_state_ = WeaveInspector::kPairingState_ThreadNetworkCreatedOrJoined;
+  ValidateWeaveStatusEntryNode(weave_status_node_3, status);
+
+  auto* weave_status_node_4 = weave_status->GetByPath({"0x4"});
+  status.tunnel_state_ = WeaveInspector::kTunnelState_PrimaryTunMode;
+  status.tunnel_type_ = WeaveInspector::kTunnelType_Primary;
+  status.tunnel_restricted_ = true;
+  ValidateWeaveStatusEntryNode(weave_status_node_4, status);
+
+  auto* weave_status_node_5 = weave_status->GetByPath({"0x5"});
+  status.tunnel_state_ = WeaveInspector::kTunnelState_PrimaryTunMode;
+  status.tunnel_type_ = WeaveInspector::kTunnelType_Primary;
+  status.tunnel_restricted_ = false;
+  ValidateWeaveStatusEntryNode(weave_status_node_5, status);
+
+  auto* weave_status_node_6 = weave_status->GetByPath({"0x6"});
+  status.failsafe_state_ = WeaveInspector::kFailSafeState_Armed;
+  status.failsafe_state_reason_ = WeaveInspector::kFailSafeReason_FailsafeDisarmFailed;
+  ValidateWeaveStatusEntryNode(weave_status_node_6, status);
+}
+
+TEST_F(WeaveInspectorTest, NotifyTunnelStatusChanges) {
+  auto status = GetInitializedWeaveStatusInfo();
+  auto& weave_inspector = GetTestWeaveInspector();
+  uint64_t tunnel_down_time_value = 0;
+  uint64_t tunnel_up_time_value = 0;
+
+  {
+    weave_inspector.NotifyTunnelStateChange(WeaveInspector::kTunnelState_PrimaryTunMode,
+                                            WeaveInspector::kTunnelType_Primary, true);
+    fit::result<inspect::Hierarchy> hierarchy =
+        RunPromise(inspect::ReadFromInspector(*GetInspector()));
+    ASSERT_TRUE(hierarchy.is_ok());
+    auto* tunnel_status = hierarchy.value().GetByPath({kNode_TunnelStatus});
+    ASSERT_TRUE(tunnel_status);
+    auto* last_time_tunnel_up = tunnel_status->node().get_property<inspect::UintPropertyValue>(
+        kNode_TunnelStatus_TimeTunnelEstablish);
+    ASSERT_TRUE(last_time_tunnel_up);
+    tunnel_up_time_value = last_time_tunnel_up->value();
+    EXPECT_NE(tunnel_up_time_value, 0u);
+  }
+
+  {
+    weave_inspector.NotifyTunnelStateChange(WeaveInspector::kTunnelState_PrimaryTunMode,
+                                            WeaveInspector::kTunnelType_Primary, false);
+    fit::result<inspect::Hierarchy> hierarchy =
+        RunPromise(inspect::ReadFromInspector(*GetInspector()));
+    ASSERT_TRUE(hierarchy.is_ok());
+    auto* tunnel_status = hierarchy.value().GetByPath({kNode_TunnelStatus});
+    ASSERT_TRUE(tunnel_status);
+    auto* last_time_tunnel_up = tunnel_status->node().get_property<inspect::UintPropertyValue>(
+        kNode_TunnelStatus_TimeTunnelEstablish);
+    ASSERT_TRUE(last_time_tunnel_up);
+    auto new_tunnel_up_time_value = last_time_tunnel_up->value();
+    EXPECT_EQ(tunnel_up_time_value, new_tunnel_up_time_value);
+  }
+  {
+    weave_inspector.NotifyTunnelStateChange(WeaveInspector::kTunnelState_NoTunnel,
+                                            WeaveInspector::kTunnelType_None, false);
+
+    fit::result<inspect::Hierarchy> hierarchy =
+        RunPromise(inspect::ReadFromInspector(*GetInspector()));
+    ASSERT_TRUE(hierarchy.is_ok());
+    auto* tunnel_status = hierarchy.value().GetByPath({kNode_TunnelStatus});
+    ASSERT_TRUE(tunnel_status);
+    auto* last_time_tunnel_down = tunnel_status->node().get_property<inspect::UintPropertyValue>(
+        kNode_TunnelStatus_TimeTunnelEstablish);
+    ASSERT_TRUE(last_time_tunnel_down);
+    tunnel_down_time_value = last_time_tunnel_down->value();
+    EXPECT_NE(tunnel_down_time_value, 0u);
+  }
+}
+
+}  // namespace nl::Weave::testing
diff --git a/src/connectivity/weave/adaptation/weave_inspector.h b/src/connectivity/weave/adaptation/weave_inspector.h
index 905d8bd..f510ca7 100644
--- a/src/connectivity/weave/adaptation/weave_inspector.h
+++ b/src/connectivity/weave/adaptation/weave_inspector.h
@@ -12,6 +12,10 @@
 
 namespace nl::Weave {
 
+namespace testing {
+class WeaveInspectorTest;
+}  // namespace testing
+
 // This class defines the structure of the Inspect hierarchy for Weave. Components
 // of WeaveStack can invoke the WeaveInspector to log events pertaining to status
 // and tunnel state changes. For example:
@@ -130,6 +134,8 @@
   void NotifyTunnelStateChange(const WeaveStatus_TunnelState& new_state,
                                const WeaveStatus_TunnelType& tunnel_type, bool is_restricted);
 
+  friend class testing::WeaveInspectorTest;
+
  private:
   WeaveInspector();