Commit | Line | Data |
---|---|---|
c3211f0a SM |
1 | /* |
2 | * SPDX-License-Identifier: GPL-2.0-only | |
3 | * | |
4 | * Copyright (C) 2024 EfficiOS Inc. | |
5 | */ | |
6 | ||
7 | #include "cpp-common/bt2s/make-unique.hpp" | |
8 | #include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */ | |
9 | ||
10 | #include "../utils/run-in.hpp" | |
11 | #include "clk-cls-compat-postconds-triggers.hpp" | |
12 | ||
13 | namespace { | |
14 | ||
15 | /* | |
16 | * `RunIn` implementation to trigger clock (in)compatibility postcondition | |
17 | * assertions. | |
18 | */ | |
19 | class ClockClsCompatRunIn final : public RunIn | |
20 | { | |
21 | public: | |
22 | enum class MsgType | |
23 | { | |
1c5ea5eb SM |
24 | StreamBeg, |
25 | MsgIterInactivity, | |
c3211f0a SM |
26 | }; |
27 | ||
28 | using CreateClockCls = bt2::ClockClass::Shared (*)(bt2::SelfComponent); | |
29 | ||
30 | explicit ClockClsCompatRunIn(const MsgType msgType1, const CreateClockCls createClockCls1, | |
31 | const MsgType msgType2, | |
32 | const CreateClockCls createClockCls2) noexcept : | |
33 | _mMsgType1 {msgType1}, | |
34 | _mMsgType2 {msgType2}, _mCreateClockCls1 {createClockCls1}, _mCreateClockCls2 { | |
35 | createClockCls2} | |
36 | { | |
37 | } | |
38 | ||
39 | void onMsgIterNext(bt2::SelfMessageIterator self, bt2::ConstMessageArray& msgs) override | |
40 | { | |
41 | /* In case the expected assertion doesn't trigger, avoid looping indefinitely. */ | |
42 | BT_ASSERT(!_mBeenThere); | |
43 | ||
44 | const auto traceCls = self.component().createTraceClass(); | |
45 | const auto trace = traceCls->instantiate(); | |
46 | ||
47 | msgs.append(this->_createOneMsg(self, _mMsgType1, _mCreateClockCls1, *trace)); | |
48 | msgs.append(this->_createOneMsg(self, _mMsgType2, _mCreateClockCls2, *trace)); | |
49 | _mBeenThere = true; | |
50 | } | |
51 | ||
52 | private: | |
53 | static bt2::Message::Shared _createOneMsg(const bt2::SelfMessageIterator self, | |
54 | const MsgType msgType, | |
55 | const CreateClockCls createClockCls, | |
56 | const bt2::Trace trace) | |
57 | { | |
58 | const auto clockCls = createClockCls(self.component()); | |
59 | ||
60 | switch (msgType) { | |
1c5ea5eb | 61 | case MsgType::StreamBeg: |
c3211f0a SM |
62 | { |
63 | const auto streamCls = trace.cls().createStreamClass(); | |
64 | ||
65 | if (clockCls) { | |
66 | streamCls->defaultClockClass(*clockCls); | |
67 | } | |
68 | ||
69 | return self.createStreamBeginningMessage(*streamCls->instantiate(trace)); | |
70 | } | |
71 | ||
1c5ea5eb | 72 | case MsgType::MsgIterInactivity: |
c3211f0a SM |
73 | BT_ASSERT(clockCls); |
74 | return self.createMessageIteratorInactivityMessage(*clockCls, 12); | |
75 | }; | |
76 | ||
77 | bt_common_abort(); | |
78 | } | |
79 | ||
80 | MsgType _mMsgType1, _mMsgType2; | |
81 | CreateClockCls _mCreateClockCls1, _mCreateClockCls2; | |
82 | bool _mBeenThere = false; | |
83 | }; | |
84 | ||
85 | __attribute__((used)) const char *format_as(const ClockClsCompatRunIn::MsgType msgType) | |
86 | { | |
87 | switch (msgType) { | |
1c5ea5eb | 88 | case ClockClsCompatRunIn::MsgType::StreamBeg: |
c3211f0a SM |
89 | return "sb"; |
90 | ||
1c5ea5eb | 91 | case ClockClsCompatRunIn::MsgType::MsgIterInactivity: |
c3211f0a SM |
92 | return "mii"; |
93 | } | |
94 | ||
95 | bt_common_abort(); | |
96 | } | |
97 | ||
98 | bt2::ClockClass::Shared noClockClass(bt2::SelfComponent) noexcept | |
99 | { | |
100 | return bt2::ClockClass::Shared {}; | |
101 | } | |
102 | ||
103 | const bt2c::Uuid uuidA {"f00aaf65-ebec-4eeb-85b2-fc255cf1aa8a"}; | |
104 | const bt2c::Uuid uuidB {"03482981-a77b-4d7b-94c4-592bf9e91785"}; | |
105 | ||
106 | } /* namespace */ | |
107 | ||
108 | /* | |
109 | * Add clock class compatibility postcondition failures triggers. | |
110 | * | |
111 | * Each trigger below makes a message iterator return two messages with | |
112 | * incompatible clock classes, leading to a postcondition failure. | |
113 | */ | |
114 | void addClkClsCompatTriggers(CondTriggers& triggers) | |
115 | { | |
116 | const auto addValidCases = [&triggers]( | |
117 | const ClockClsCompatRunIn::CreateClockCls createClockCls1, | |
118 | const ClockClsCompatRunIn::CreateClockCls createClockCls2, | |
119 | const char * const condId) { | |
120 | /* | |
121 | * Add triggers for all possible combinations of message types. | |
122 | * | |
123 | * It's not possible to create message iterator inactivity messages | |
124 | * without a clock class. | |
125 | */ | |
126 | static constexpr std::array<ClockClsCompatRunIn::MsgType, 2> msgTypes { | |
1c5ea5eb SM |
127 | ClockClsCompatRunIn::MsgType::StreamBeg, |
128 | ClockClsCompatRunIn::MsgType::MsgIterInactivity, | |
c3211f0a SM |
129 | }; |
130 | ||
131 | const auto isInvalidCase = [](const ClockClsCompatRunIn::MsgType msgType, | |
132 | const ClockClsCompatRunIn::CreateClockCls createClockCls) { | |
1c5ea5eb | 133 | return msgType == ClockClsCompatRunIn::MsgType::MsgIterInactivity && |
c3211f0a SM |
134 | createClockCls == noClockClass; |
135 | }; | |
136 | ||
137 | for (const auto msgType1 : msgTypes) { | |
138 | if (isInvalidCase(msgType1, createClockCls1)) { | |
139 | continue; | |
140 | } | |
141 | ||
142 | for (const auto msgType2 : msgTypes) { | |
143 | if (isInvalidCase(msgType2, createClockCls2)) { | |
144 | continue; | |
145 | } | |
146 | ||
147 | triggers.emplace_back(bt2s::make_unique<RunInCondTrigger<ClockClsCompatRunIn>>( | |
148 | ClockClsCompatRunIn {msgType1, createClockCls1, msgType2, createClockCls2}, | |
1c5ea5eb | 149 | CondTrigger::Type::Post, condId, fmt::format("{}-{}", msgType1, msgType2))); |
c3211f0a SM |
150 | } |
151 | } | |
152 | }; | |
153 | ||
154 | addValidCases( | |
155 | noClockClass, | |
156 | [](const bt2::SelfComponent self) { | |
157 | return self.createClockClass(); | |
158 | }, | |
159 | "message-iterator-class-next-method:stream-class-has-no-clock-class"); | |
160 | ||
161 | addValidCases( | |
162 | [](const bt2::SelfComponent self) { | |
163 | return self.createClockClass(); | |
164 | }, | |
165 | noClockClass, | |
166 | "message-iterator-class-next-method:stream-class-has-clock-class-with-unix-epoch-origin"); | |
167 | ||
168 | addValidCases( | |
169 | [](const bt2::SelfComponent self) { | |
170 | return self.createClockClass(); | |
171 | }, | |
172 | [](const bt2::SelfComponent self) { | |
173 | const auto clockCls = self.createClockClass(); | |
174 | ||
175 | clockCls->originIsUnixEpoch(false); | |
176 | return clockCls; | |
177 | }, | |
178 | "message-iterator-class-next-method:clock-class-has-unix-epoch-origin"); | |
179 | ||
180 | addValidCases( | |
181 | [](const bt2::SelfComponent self) { | |
182 | const auto clockCls = self.createClockClass(); | |
183 | ||
184 | clockCls->originIsUnixEpoch(false).uuid(uuidA); | |
185 | return clockCls; | |
186 | }, | |
187 | noClockClass, "message-iterator-class-next-method:stream-class-has-clock-class-with-uuid"); | |
188 | ||
189 | addValidCases( | |
190 | [](const bt2::SelfComponent self) { | |
191 | const auto clockCls = self.createClockClass(); | |
192 | ||
193 | clockCls->originIsUnixEpoch(false).uuid(uuidA); | |
194 | return clockCls; | |
195 | }, | |
196 | [](const bt2::SelfComponent self) { | |
197 | return self.createClockClass(); | |
198 | }, | |
199 | "message-iterator-class-next-method:clock-class-has-non-unix-epoch-origin"); | |
200 | ||
201 | addValidCases( | |
202 | [](const bt2::SelfComponent self) { | |
203 | const auto clockCls = self.createClockClass(); | |
204 | ||
205 | clockCls->originIsUnixEpoch(false).uuid(uuidA); | |
206 | return clockCls; | |
207 | }, | |
208 | [](const bt2::SelfComponent self) { | |
209 | const auto clockCls = self.createClockClass(); | |
210 | ||
211 | clockCls->originIsUnixEpoch(false); | |
212 | return clockCls; | |
213 | }, | |
214 | "message-iterator-class-next-method:clock-class-has-uuid"); | |
215 | ||
216 | addValidCases( | |
217 | [](const bt2::SelfComponent self) { | |
218 | const auto clockCls = self.createClockClass(); | |
219 | ||
220 | clockCls->originIsUnixEpoch(false).uuid(uuidA); | |
221 | return clockCls; | |
222 | }, | |
223 | [](const bt2::SelfComponent self) { | |
224 | const auto clockCls = self.createClockClass(); | |
225 | ||
226 | clockCls->originIsUnixEpoch(false).uuid(uuidB); | |
227 | return clockCls; | |
228 | }, | |
229 | "message-iterator-class-next-method:clock-class-has-expected-uuid"); | |
230 | ||
231 | addValidCases( | |
232 | [](const bt2::SelfComponent self) { | |
233 | const auto clockCls = self.createClockClass(); | |
234 | ||
235 | clockCls->originIsUnixEpoch(false); | |
236 | return clockCls; | |
237 | }, | |
238 | noClockClass, "message-iterator-class-next-method:stream-class-has-clock-class"); | |
239 | ||
240 | addValidCases( | |
241 | [](const bt2::SelfComponent self) { | |
242 | const auto clockCls = self.createClockClass(); | |
243 | ||
244 | clockCls->originIsUnixEpoch(false); | |
245 | return clockCls; | |
246 | }, | |
247 | [](const bt2::SelfComponent self) { | |
248 | const auto clockCls = self.createClockClass(); | |
249 | ||
250 | clockCls->originIsUnixEpoch(false); | |
251 | return clockCls; | |
252 | }, | |
253 | "message-iterator-class-next-method:clock-class-is-expected"); | |
254 | } |