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