blob: d72983367f236e11a1b1c1b20d3e0a0e97f8ed8a [file] [log] [blame]
James Kuszmaul9a816a72023-03-23 15:10:34 -07001#include "aos/starter/mock_starter.h"
2
Stephan Pleinesf581a072024-05-23 20:59:27 -07003#include <algorithm>
4#include <ostream>
5#include <string_view>
6#include <utility>
7
Austin Schuh99f7c6a2024-06-25 22:07:44 -07008#include "absl/log/check.h"
9#include "absl/log/log.h"
Stephan Pleinesf581a072024-05-23 20:59:27 -070010#include "flatbuffers/buffer.h"
11#include "flatbuffers/flatbuffer_builder.h"
12#include "flatbuffers/string.h"
13#include "flatbuffers/vector.h"
Stephan Pleinesf581a072024-05-23 20:59:27 -070014
15#include "aos/configuration.h"
16#include "aos/starter/starter_rpc_generated.h"
17#include "aos/starter/starterd_lib.h"
18
Stephan Pleinesf63bde82024-01-13 15:59:33 -080019namespace aos::starter {
James Kuszmaul9a816a72023-03-23 15:10:34 -070020
21MockStarter::MockStarter(aos::EventLoop *event_loop)
22 : event_loop_(event_loop),
23 status_sender_(event_loop_->MakeSender<aos::starter::Status>("/aos")) {
24 aos::TimerHandler *send_timer =
25 event_loop_->AddTimer([this]() { SendStatus(); });
26
27 CHECK(aos::configuration::MultiNode(event_loop_->configuration()));
28
29 for (const aos::Node *node :
30 aos::configuration::GetNodes(event_loop_->configuration())) {
31 const aos::Channel *channel = aos::starter::StarterRpcChannelForNode(
32 event_loop_->configuration(), node);
33 if (aos::configuration::ChannelIsReadableOnNode(channel,
34 event_loop_->node())) {
35 std::string_view channel_name = channel->name()->string_view();
36 event_loop_->MakeWatcher(
37 channel_name, [this](const aos::starter::StarterRpc &command) {
38 for (const flatbuffers::String *node : *command.nodes()) {
39 if (node->string_view() ==
40 event_loop_->node()->name()->string_view()) {
41 CHECK(statuses_.count(command.name()->str()) > 0)
42 << "Unable to find " << command.name()->string_view()
43 << " in our list of applications.";
44 ApplicationStatus &status = statuses_[command.name()->str()];
45 switch (command.command()) {
46 case aos::starter::Command::START:
47 if (!status.running) {
James Kuszmaul75b09352023-02-03 16:21:25 -080048 VLOG(1) << "Starting " << command.name()->string_view()
49 << " at " << event_loop_->monotonic_now();
James Kuszmaul9a816a72023-03-23 15:10:34 -070050 status.running = true;
51 status.start_time = event_loop_->monotonic_now();
52 status.id = next_id_++;
53 }
54 break;
55 case aos::starter::Command::STOP:
James Kuszmaul75b09352023-02-03 16:21:25 -080056 if (status.running) {
57 VLOG(1) << "Stopping " << command.name()->string_view()
58 << " at " << event_loop_->monotonic_now();
59 }
James Kuszmaul9a816a72023-03-23 15:10:34 -070060 status.running = false;
61 break;
62 case aos::starter::Command::RESTART:
63 status.running = true;
James Kuszmaul75b09352023-02-03 16:21:25 -080064 VLOG(1) << "Restarting " << command.name()->string_view()
65 << " at " << event_loop_->monotonic_now();
James Kuszmaul9a816a72023-03-23 15:10:34 -070066 status.start_time = event_loop_->monotonic_now();
67 status.id = next_id_++;
68 }
69 SendStatus();
70 }
71 }
72 });
73 }
74 }
75
76 event_loop_->OnRun([this, send_timer]() {
Philipp Schradera6712522023-07-05 20:25:11 -070077 send_timer->Schedule(event_loop_->monotonic_now(), std::chrono::seconds(1));
James Kuszmaul9a816a72023-03-23 15:10:34 -070078
79 for (const aos::Application *application :
80 *event_loop_->configuration()->applications()) {
81 if (aos::configuration::ApplicationShouldStart(
82 event_loop_->configuration(), event_loop_->node(), application)) {
83 statuses_[application->name()->str()] = ApplicationStatus{
84 next_id_++, application->autostart(), event_loop_->monotonic_now()};
85 }
86 }
87 });
88}
89
90void MockStarter::SendStatus() {
91 aos::Sender<aos::starter::Status>::Builder builder =
92 status_sender_.MakeBuilder();
93 std::vector<flatbuffers::Offset<aos::starter::ApplicationStatus>>
94 status_offsets;
95 for (const std::pair<const std::string, ApplicationStatus> &pair :
96 statuses_) {
97 const flatbuffers::Offset<flatbuffers::String> name_offset =
98 builder.fbb()->CreateString(pair.first);
99 aos::starter::ApplicationStatus::Builder status_builder =
100 builder.MakeBuilder<aos::starter::ApplicationStatus>();
101 status_builder.add_name(name_offset);
102 status_builder.add_state(pair.second.running
103 ? aos::starter::State::RUNNING
104 : aos::starter::State::STOPPED);
105 status_builder.add_last_exit_code(0);
106 status_builder.add_id(pair.second.id);
107 status_builder.add_last_stop_reason(
108 aos::starter::LastStopReason::STOP_REQUESTED);
109 status_builder.add_last_start_time(
110 pair.second.start_time.time_since_epoch().count());
111 if (pair.second.running) {
112 status_builder.add_pid(pair.second.id);
113 }
114 status_offsets.push_back(status_builder.Finish());
115 }
116 const flatbuffers::Offset<
117 flatbuffers::Vector<flatbuffers::Offset<aos::starter::ApplicationStatus>>>
118 statuses_offset = builder.fbb()->CreateVector(status_offsets);
119 aos::starter::Status::Builder status_builder =
120 builder.MakeBuilder<aos::starter::Status>();
121 status_builder.add_statuses(statuses_offset);
122 builder.CheckOk(builder.Send(status_builder.Finish()));
123}
124
125MockStarters::MockStarters(aos::SimulatedEventLoopFactory *event_loop_factory) {
126 CHECK(aos::configuration::MultiNode(event_loop_factory->configuration()));
127 for (const aos::Node *node :
128 aos::configuration::GetNodes(event_loop_factory->configuration())) {
129 event_loops_.emplace_back(
130 event_loop_factory->GetNodeEventLoopFactory(node)->MakeEventLoop(
131 "starterd"));
132 mock_starters_.emplace_back(
133 std::make_unique<MockStarter>(event_loops_.back().get()));
134 }
135}
136
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800137} // namespace aos::starter