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 :
25 : namespace chip {
26 : namespace Testing {
27 :
28 : /// Keeps a queue of generated events that can be acquired later for testing purposes
29 : class LogOnlyEvents : public app::DataModel::EventsGenerator
30 : {
31 : public:
32 : // struct to hold information about a generated event
33 : struct EventInformation
34 : {
35 : EventNumber eventNumber;
36 : app::EventOptions eventOptions;
37 : bool wasDeliveredUrgently{ false };
38 9 : ByteSpan GetEncodeByteSpan() const { return ByteSpan(mEventEncodeBuffer, mEncodedLength); }
39 :
40 : // This relies on the default encoding of events which uses
41 : // DataModel::Encode on a EventDataIB::Tag::kData
42 : // The caller MUST ensure that T is the correct type for the event
43 : // Use app::Clusters::<ClusterName>::Events::<EventName>::DecodableType to be spec compliant
44 : template <typename T>
45 9 : CHIP_ERROR GetEventData(T & dest)
46 : {
47 : // attempt to decode the last encoded event
48 9 : TLV::TLVReader reader;
49 : TLV::TLVType outerType;
50 :
51 9 : reader.Init(GetEncodeByteSpan());
52 :
53 9 : ReturnErrorOnFailure(reader.Next());
54 9 : ReturnErrorOnFailure(reader.EnterContainer(outerType));
55 :
56 9 : ReturnErrorOnFailure(reader.Next()); // MUST be positioned on the first element
57 9 : ReturnErrorOnFailure(app::DataModel::Decode(reader, dest));
58 :
59 9 : ReturnErrorOnFailure(reader.ExitContainer(outerType));
60 :
61 9 : return CHIP_NO_ERROR;
62 : }
63 :
64 : private:
65 : uint8_t mEventEncodeBuffer[128];
66 : uint32_t mEncodedLength;
67 :
68 : friend class LogOnlyEvents;
69 : };
70 :
71 : // Marks the last event (that has the given fabric index if given any) as delivered urgently.
72 0 : void ScheduleUrgentEventDeliverySync(std::optional<FabricIndex> fabricIndex = std::nullopt) override
73 : {
74 0 : for (auto it = mEventQueue.rbegin(); it != mEventQueue.rend(); ++it)
75 : {
76 0 : if (!fabricIndex.has_value() || it->eventOptions.mFabricIndex == fabricIndex.value())
77 : {
78 0 : it->wasDeliveredUrgently = true;
79 0 : break;
80 : }
81 : }
82 0 : }
83 :
84 42 : CHIP_ERROR GenerateEvent(app::EventLoggingDelegate * eventContentWriter, const app::EventOptions & options,
85 : EventNumber & generatedEventNumber) override
86 : {
87 42 : TLV::TLVWriter writer;
88 : TLV::TLVType outerType;
89 :
90 42 : EventInformation eventInfo;
91 42 : writer.Init(eventInfo.mEventEncodeBuffer);
92 :
93 42 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
94 42 : ReturnErrorOnFailure(eventContentWriter->WriteEvent(writer));
95 42 : ReturnErrorOnFailure(writer.EndContainer(outerType));
96 42 : ReturnErrorOnFailure(writer.Finalize());
97 42 : eventInfo.mEncodedLength = writer.GetLengthWritten();
98 42 : eventInfo.eventOptions = options;
99 42 : eventInfo.eventNumber = generatedEventNumber = ++mCurrentEventNumber;
100 :
101 42 : mEventQueue.push_back(eventInfo);
102 :
103 42 : return CHIP_NO_ERROR;
104 : }
105 :
106 : // Returns next event in the event queue, removing it from the queue.
107 : // Returns `std::nullopt` if no event is in the queue (i.e. no event was generated after consuming last generated one).
108 13 : [[nodiscard]] std::optional<EventInformation> GetNextEvent()
109 : {
110 13 : if (mEventQueue.empty())
111 : {
112 2 : return std::nullopt;
113 : }
114 11 : std::optional<EventInformation> info{ std::move(mEventQueue.front()) };
115 11 : mEventQueue.pop_front();
116 11 : return info;
117 : }
118 :
119 : private:
120 : std::deque<EventInformation> mEventQueue;
121 : EventNumber mCurrentEventNumber = 0;
122 : };
123 :
124 : } // namespace Testing
125 : } // namespace chip
|