Test a multi-node configuration with 1 node

While we are here, make it so we
don't require the message bridge messages if there is only one node,
since they don't really make sense.

Change-Id: Id1608da0b4048729c298bc963fa1da3155f89ea2
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index 344ffe2..fef834b 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -795,6 +795,19 @@
     deps = ["//aos/events:aos_config"],
 )
 
+aos_config(
+    name = "multinode_single_node_config",
+    src = "multinode_single_node.json",
+    flatbuffers = [
+        "//aos/network:message_bridge_client_fbs",
+        "//aos/network:message_bridge_server_fbs",
+        "//aos/network:remote_message_fbs",
+        "//aos/network:timestamp_fbs",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = ["//aos/events:aos_config"],
+)
+
 cc_test(
     name = "realtime_replay_test",
     srcs = ["realtime_replay_test.cc"],
@@ -848,6 +861,7 @@
         ":multinode_pingpong_split4_reliable_config",
         ":multinode_pingpong_split_config",
         ":multinode_pingpong_triangle_split_config",
+        ":multinode_single_node_config",
         "//aos/events:pingpong_config",
     ],
     shard_count = 10,
diff --git a/aos/events/logging/log_reader.cc b/aos/events/logging/log_reader.cc
index 50fddb0..5b437ba 100644
--- a/aos/events/logging/log_reader.cc
+++ b/aos/events/logging/log_reader.cc
@@ -546,7 +546,7 @@
   // off.  Otherwise messages replayed will get forwarded across to the other
   // nodes, and also replayed on the other nodes.  This may not satisfy all
   // our users, but it'll start the discussion.
-  if (configuration::MultiNode(event_loop_factory_->configuration())) {
+  if (configuration::NodesCount(event_loop_factory_->configuration()) > 1u) {
     for (size_t i = 0; i < logged_configuration()->channels()->size(); ++i) {
       const Channel *channel = logged_configuration()->channels()->Get(i);
       const Node *node = configuration::GetNode(
diff --git a/aos/events/logging/log_writer.cc b/aos/events/logging/log_writer.cc
index e8b8819..bc81a4b 100644
--- a/aos/events/logging/log_writer.cc
+++ b/aos/events/logging/log_writer.cc
@@ -31,7 +31,7 @@
         DoLogData(event_loop_->monotonic_now() - logging_delay_, true);
       })),
       server_statistics_fetcher_(
-          configuration::MultiNode(event_loop_->configuration())
+          configuration::NodesCount(event_loop_->configuration()) > 1u
               ? event_loop_->MakeFetcher<message_bridge::ServerStatistics>(
                     "/aos")
               : aos::Fetcher<message_bridge::ServerStatistics>()) {
@@ -152,7 +152,7 @@
     const bool log_message = is_logged && is_readable;
 
     bool log_delivery_times = false;
-    if (configuration::MultiNode(configuration_)) {
+    if (configuration::NodesCount(configuration_) > 1u) {
       const aos::Connection *connection =
           configuration::ConnectionToNode(config_channel, node_);
 
@@ -467,7 +467,7 @@
 
 void Logger::WriteHeader(aos::monotonic_clock::time_point monotonic_start_time,
                          aos::realtime_clock::time_point realtime_start_time) {
-  if (configuration::MultiNode(configuration_)) {
+  if (configuration::NodesCount(configuration_) > 1u) {
     server_statistics_fetcher_.Fetch();
   }
 
@@ -490,7 +490,7 @@
 }
 
 void Logger::WriteMissingTimestamps() {
-  if (configuration::MultiNode(configuration_)) {
+  if (configuration::NodesCount(configuration_) > 1u) {
     server_statistics_fetcher_.Fetch();
   } else {
     return;
diff --git a/aos/events/logging/multinode_logger_test.cc b/aos/events/logging/multinode_logger_test.cc
index 4980b50..b8d07a2 100644
--- a/aos/events/logging/multinode_logger_test.cc
+++ b/aos/events/logging/multinode_logger_test.cc
@@ -4318,6 +4318,51 @@
   auto result = ConfirmReadable(filenames);
 }
 
+// Tests that we call OnEnd without --skip_missing_forwarding_entries.
+TEST(MultinodeLoggerConfigTest, SingleNode) {
+  util::UnlinkRecursive(aos::testing::TestTmpDir() + "/logs");
+  std::filesystem::create_directory(aos::testing::TestTmpDir() + "/logs");
+
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(
+          ArtifactPath("aos/events/logging/multinode_single_node_config.json"));
+  message_bridge::TestingTimeConverter time_converter(
+      configuration::NodesCount(&config.message()));
+  SimulatedEventLoopFactory event_loop_factory(&config.message());
+  event_loop_factory.SetTimeConverter(&time_converter);
+
+  time_converter.StartEqual();
+
+  const std::string kLogfile1_1 =
+      aos::testing::TestTmpDir() + "/logs/multi_logfile1/";
+
+  NodeEventLoopFactory *const pi1 =
+      event_loop_factory.GetNodeEventLoopFactory("pi1");
+
+  std::vector<std::string> filenames;
+
+  {
+    // Now start a receiving node first.  This sets up 2 tight bounds between
+    // 2 of the nodes.
+    LoggerState pi1_logger = MakeLoggerState(
+        pi1, &event_loop_factory, SupportedCompressionAlgorithms()[0],
+        FileStrategy::kKeepSeparate);
+    pi1_logger.StartLogger(kLogfile1_1);
+
+    event_loop_factory.RunFor(chrono::seconds(10));
+
+    pi1_logger.AppendAllFilenames(&filenames);
+  }
+
+  // Make sure we can read this.
+  const std::vector<LogFile> sorted_parts = SortParts(filenames);
+  EXPECT_TRUE(AllPartsMatchOutOfOrderDuration(sorted_parts));
+  auto result = ConfirmReadable(filenames);
+
+  // TODO(austin): Probably want to stop caring about ServerStatistics,
+  // ClientStatistics, and Timestamp since they don't really make sense.
+}
+
 // Tests that when we have evidence of 2 boots, and then start logging, the
 // max_out_of_order_duration ends up reasonable on the boot with the start time.
 TEST(MultinodeLoggerLoopTest, PreviousBootData) {
diff --git a/aos/events/logging/multinode_single_node.json b/aos/events/logging/multinode_single_node.json
new file mode 100644
index 0000000..d3a1090
--- /dev/null
+++ b/aos/events/logging/multinode_single_node.json
@@ -0,0 +1,33 @@
+{
+  "channels": [
+    {
+      "name": "/aos",
+      "type": "aos.logging.LogMessageFbs",
+      "source_node": "pi1",
+      "frequency": 200,
+      "num_senders": 20,
+      "max_size": 2048
+    },
+    {
+      "name": "/aos",
+      "type": "aos.timing.Report",
+      "source_node": "pi1",
+      "frequency": 50,
+      "num_senders": 20,
+      "max_size": 2048
+    },
+    {
+      "name": "/aos",
+      "type": "aos.logging.DynamicLogCommand",
+      "logger": "LOCAL_LOGGER",
+      "source_node": "pi1"
+    }
+  ],
+  "nodes": [
+    {
+      "name": "pi1",
+      "hostname": "raspberrypi",
+      "port": 9971
+    }
+  ]
+}
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index 59d8d7a..7b84380 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -1342,7 +1342,7 @@
         new NodeEventLoopFactory(&scheduler_scheduler_, this, node));
   }
 
-  if (configuration::MultiNode(configuration)) {
+  if (configuration::NodesCount(configuration) > 1u) {
     bridge_ = std::make_unique<message_bridge::SimulatedMessageBridge>(this);
   }
 }