Line data Source code
1 : /*
2 : * Copyright (c) 2025 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <app/EventLoggingDelegate.h>
20 : #include <app/EventLoggingTypes.h>
21 : #include <app/data-model-provider/EventsGenerator.h>
22 : #include <app/data-model/Decode.h>
23 : #include <deque>
24 : #include <system/SystemClock.h>
25 :
26 : namespace chip {
27 : namespace Testing {
28 :
29 : /// Keeps a queue of generated events that can be acquired later for testing purposes
30 : class LogOnlyEvents : public app::DataModel::EventsGenerator
31 : {
32 : public:
33 : // struct to hold information about a generated event
34 : struct EventInformation
35 : {
36 : EventNumber eventNumber;
37 : app::EventOptions eventOptions;
38 : bool wasDeliveredUrgently{ false };
39 11 : ByteSpan GetEncodeByteSpan() const { return ByteSpan(mEventEncodeBuffer, mEncodedLength); }
40 :
41 : // This relies on the default encoding of events which uses
42 : // DataModel::Encode on a EventDataIB::Tag::kData
43 : // The caller MUST ensure that T is the correct type for the event
44 : // Use app::Clusters::<ClusterName>::Events::<EventName>::DecodableType to be spec compliant
45 : template <typename T>
46 11 : CHIP_ERROR GetEventData(T & dest)
47 : {
48 : // attempt to decode the last encoded event
49 11 : TLV::TLVReader reader;
50 : TLV::TLVType outerType;
51 :
52 11 : reader.Init(GetEncodeByteSpan());
53 :
54 11 : ReturnErrorOnFailure(reader.Next());
55 11 : ReturnErrorOnFailure(reader.EnterContainer(outerType));
56 :
57 11 : ReturnErrorOnFailure(reader.Next()); // MUST be positioned on the first element
58 11 : ReturnErrorOnFailure(app::DataModel::Decode(reader, dest));
59 :
60 11 : ReturnErrorOnFailure(reader.ExitContainer(outerType));
61 :
62 11 : return CHIP_NO_ERROR;
63 : }
64 :
65 : private:
66 : uint8_t mEventEncodeBuffer[128];
67 : uint32_t mEncodedLength;
68 :
69 : friend class LogOnlyEvents;
70 : };
71 :
72 : // Marks the last event (that has the given fabric index if given any) as delivered urgently.
73 0 : void ScheduleUrgentEventDeliverySync(std::optional<FabricIndex> fabricIndex = std::nullopt) override
74 : {
75 0 : for (auto it = mEventQueue.rbegin(); it != mEventQueue.rend(); ++it)
76 : {
77 0 : if (!fabricIndex.has_value() || it->eventOptions.mFabricIndex == fabricIndex.value())
78 : {
79 0 : it->wasDeliveredUrgently = true;
80 0 : break;
81 : }
82 : }
83 0 : }
84 :
85 55 : CHIP_ERROR GenerateEvent(app::EventLoggingDelegate * eventContentWriter, const app::EventOptions & options,
86 : EventNumber & generatedEventNumber) override
87 : {
88 55 : TLV::TLVWriter writer;
89 : TLV::TLVType outerType;
90 :
91 55 : EventInformation eventInfo;
92 55 : writer.Init(eventInfo.mEventEncodeBuffer);
93 :
94 55 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
95 55 : ReturnErrorOnFailure(eventContentWriter->WriteEvent(writer));
96 55 : ReturnErrorOnFailure(writer.EndContainer(outerType));
97 55 : ReturnErrorOnFailure(writer.Finalize());
98 55 : eventInfo.mEncodedLength = writer.GetLengthWritten();
99 55 : eventInfo.eventOptions = options;
100 55 : eventInfo.eventNumber = generatedEventNumber = ++mCurrentEventNumber;
101 :
102 55 : mEventQueue.push_back(eventInfo);
103 :
104 55 : return CHIP_NO_ERROR;
105 : }
106 :
107 4 : System::Clock::Milliseconds64 GetMonotonicStartupTime() const override { return mStartupTimestamp; }
108 :
109 : void SetStartupTimestamp(System::Clock::Milliseconds64 timestamp) { mStartupTimestamp = timestamp; }
110 :
111 : // Returns next event in the event queue, removing it from the queue.
112 : // Returns `std::nullopt` if no event is in the queue (i.e. no event was generated after consuming last generated one).
113 15 : [[nodiscard]] std::optional<EventInformation> GetNextEvent()
114 : {
115 15 : if (mEventQueue.empty())
116 : {
117 2 : return std::nullopt;
118 : }
119 13 : std::optional<EventInformation> info{ std::move(mEventQueue.front()) };
120 13 : mEventQueue.pop_front();
121 13 : return info;
122 : }
123 :
124 : private:
125 : std::deque<EventInformation> mEventQueue;
126 : EventNumber mCurrentEventNumber = 0;
127 : System::Clock::Milliseconds64 mStartupTimestamp = System::Clock::Milliseconds64(0);
128 : };
129 :
130 : } // namespace Testing
131 : } // namespace chip
|