1111import java .util .HashMap ;
1212import java .util .List ;
1313import java .util .Map ;
14+ import java .util .concurrent .locks .ReentrantLock ;
1415import java .util .function .BiConsumer ;
1516
16- /** A telemetry backend that saves logged data to an array for unit testing purposes. */
17+ /**
18+ * A telemetry backend that saves logged data to an array for unit testing
19+ * purposes.
20+ */
1721public class MockTelemetryBackend implements TelemetryBackend {
1822 /** Value for keepDuplicate() action. */
19- public record KeepDuplicateValue (boolean value ) {}
23+ public record KeepDuplicateValue (boolean value ) {
24+ }
2025
2126 /** Value for setProperty() action. */
22- public record SetPropertyValue (String key , String value ) {}
27+ public record SetPropertyValue (String key , String value ) {
28+ }
2329
2430 /** Value for logStruct() action. */
25- public record LogStructValue <T >(T value , Struct <T > struct ) {}
31+ public record LogStructValue <T >(T value , Struct <T > struct ) {
32+ }
2633
2734 /** Value for logProtobuf() action. */
28- public record LogProtobufValue <T >(T value , Protobuf <T , ?> protobuf ) {}
35+ public record LogProtobufValue <T >(T value , Protobuf <T , ?> protobuf ) {
36+ }
2937
3038 /** Value for logStructArray() action. */
31- public record LogStructArrayValue <T >(T [] value , Struct <T > struct ) {}
39+ public record LogStructArrayValue <T >(T [] value , Struct <T > struct ) {
40+ }
3241
3342 /** Value for logString() action. */
34- public record LogStringValue (String value , String typeString ) {}
43+ public record LogStringValue (String value , String typeString ) {
44+ }
3545
3646 /** Value for logRaw() action. */
37- public record LogRawValue (byte [] value , String typeString ) {}
47+ public record LogRawValue (byte [] value , String typeString ) {
48+ }
3849
3950 /** A logged action. */
40- public record Action (String path , Object value ) {}
51+ public record Action (String path , Object value ) {
52+ }
4153
4254 private final Map <String , Entry > m_entries = new HashMap <>();
4355 private final List <Action > m_actions = new ArrayList <>();
@@ -53,29 +65,68 @@ public List<Action> getActions() {
5365
5466 /** Clear logged actions. */
5567 public void clear () {
56- m_actions .clear ();
68+ synchronized (this ) {
69+ for (Entry entry : m_entries .values ()) {
70+ entry .m_last = -1 ;
71+ }
72+ m_actions .clear ();
73+ }
74+ }
75+
76+ /**
77+ * Get the last action for a particular path.
78+ *
79+ * @param path path
80+ * @return Action, or null if no update to that path
81+ */
82+ public Action getLastAction (String path ) {
83+ synchronized (this ) {
84+ Entry entry = m_entries .get (path );
85+ if (entry == null || entry .m_last == -1 ) {
86+ return null ;
87+ }
88+ return m_actions .get (entry .m_last );
89+ }
90+ }
91+
92+ /**
93+ * Get the last action value for a particular path.
94+ *
95+ * @param path path
96+ * @return Value, or null if no update to that path
97+ */
98+ public <T > T getLastValue (String path , Class <T > cls ) {
99+ Action action = getLastAction (path );
100+ if (action == null || !action .value .getClass ().equals (cls )) {
101+ return null ;
102+ }
103+ @ SuppressWarnings ("unchecked" )
104+ T result = (T ) action .value ;
105+ return result ;
57106 }
58107
59108 @ Override
60109 public void close () {
61- synchronized (m_entries ) {
110+ synchronized (this ) {
62111 m_entries .clear ();
63112 }
64113 }
65114
66115 @ Override
67116 public TelemetryEntry getEntry (String path ) {
68- synchronized (m_entries ) {
117+ synchronized (this ) {
69118 return m_entries .computeIfAbsent (path , k -> new Entry (k ));
70119 }
71120 }
72121
73122 @ Override
74- public void setReportWarning (BiConsumer <String , StackTraceElement []> func ) {}
123+ public void setReportWarning (BiConsumer <String , StackTraceElement []> func ) {
124+ }
75125
76- private void log (String path , Object value ) {
77- synchronized (m_actions ) {
78- m_actions .add (new Action (path , value ));
126+ private void log (Entry entry , Object value ) {
127+ synchronized (this ) {
128+ entry .m_last = m_actions .size ();
129+ m_actions .add (new Action (entry .m_path , value ));
79130 }
80131 }
81132
@@ -86,19 +137,19 @@ private final class Entry implements TelemetryEntry {
86137
87138 @ Override
88139 public void keepDuplicates () {
89- log (m_path , new KeepDuplicateValue (true ));
140+ log (this , new KeepDuplicateValue (true ));
90141 }
91142
92143 @ Override
93144 public void setProperty (String key , String value ) {
94- log (m_path , new SetPropertyValue (key , value ));
145+ log (this , new SetPropertyValue (key , value ));
95146 }
96147
97148 @ Override
98149 public <T > void logStruct (T value , Struct <T > struct ) {
99150 if (struct .isImmutable ()) {
100151 // log it directly
101- log (m_path , new LogStructValue <T >(value , struct ));
152+ log (this , new LogStructValue <T >(value , struct ));
102153 } else if (struct .isCloneable ()) {
103154 T clonedValue ;
104155 try {
@@ -107,20 +158,20 @@ public <T> void logStruct(T value, Struct<T> struct) {
107158 throw new UnsupportedOperationException (
108159 "struct.isCloneable() returned true, but clone() raised exception" );
109160 }
110- log (m_path , new LogStructValue <T >(clonedValue , struct ));
161+ log (this , new LogStructValue <T >(clonedValue , struct ));
111162 } else {
112163 // log it directly, but warn
113164 System .err .println (
114165 "warning: logging non-immutable and non-cloneable struct to '" + m_path + "'" );
115- log (m_path , new LogStructValue <T >(value , struct ));
166+ log (this , new LogStructValue <T >(value , struct ));
116167 }
117168 }
118169
119170 @ Override
120171 public <T > void logProtobuf (T value , Protobuf <T , ?> proto ) {
121172 if (proto .isImmutable ()) {
122173 // log it directly
123- log (m_path , new LogProtobufValue <T >(value , proto ));
174+ log (this , new LogProtobufValue <T >(value , proto ));
124175 } else if (proto .isCloneable ()) {
125176 T clonedValue ;
126177 try {
@@ -129,20 +180,20 @@ public <T> void logProtobuf(T value, Protobuf<T, ?> proto) {
129180 throw new UnsupportedOperationException (
130181 "proto.isCloneable() returned true, but clone() raised exception" );
131182 }
132- log (m_path , new LogProtobufValue <T >(clonedValue , proto ));
183+ log (this , new LogProtobufValue <T >(clonedValue , proto ));
133184 } else {
134185 // log it directly, but warn
135186 System .err .println (
136187 "warning: logging non-immutable and non-cloneable proto to '" + m_path + "'" );
137- log (m_path , new LogProtobufValue <T >(value , proto ));
188+ log (this , new LogProtobufValue <T >(value , proto ));
138189 }
139190 }
140191
141192 @ Override
142193 public <T > void logStructArray (T [] value , Struct <T > struct ) {
143194 if (struct .isImmutable ()) {
144195 // log it directly
145- log (m_path , new LogStructArrayValue <T >(value .clone (), struct ));
196+ log (this , new LogStructArrayValue <T >(value .clone (), struct ));
146197 } else if (struct .isCloneable ()) {
147198 @ SuppressWarnings ("unchecked" )
148199 T [] clonedArray = (T []) Array .newInstance (struct .getClass (), value .length );
@@ -154,90 +205,91 @@ public <T> void logStructArray(T[] value, Struct<T> struct) {
154205 throw new UnsupportedOperationException (
155206 "struct.isCloneable() returned true, but clone() raised exception" );
156207 }
157- log (m_path , new LogStructArrayValue <T >(clonedArray , struct ));
208+ log (this , new LogStructArrayValue <T >(clonedArray , struct ));
158209 } else {
159210 // log it directly, but warn
160211 System .err .println (
161212 "warning: logging non-immutable and non-cloneable struct to '" + m_path + "'" );
162- log (m_path , new LogStructArrayValue <T >(value .clone (), struct ));
213+ log (this , new LogStructArrayValue <T >(value .clone (), struct ));
163214 }
164215 }
165216
166217 @ Override
167218 public void logBoolean (boolean value ) {
168- log (m_path , value );
219+ log (this , value );
169220 }
170221
171222 @ Override
172223 public void logShort (short value ) {
173- log (m_path , value );
224+ log (this , value );
174225 }
175226
176227 @ Override
177228 public void logInt (int value ) {
178- log (m_path , value );
229+ log (this , value );
179230 }
180231
181232 @ Override
182233 public void logLong (long value ) {
183- log (m_path , value );
234+ log (this , value );
184235 }
185236
186237 @ Override
187238 public void logFloat (float value ) {
188- log (m_path , value );
239+ log (this , value );
189240 }
190241
191242 @ Override
192243 public void logDouble (double value ) {
193- log (m_path , value );
244+ log (this , value );
194245 }
195246
196247 @ Override
197248 public void logString (String value , String typeString ) {
198- log (m_path , new LogStringValue (value , typeString ));
249+ log (this , new LogStringValue (value , typeString ));
199250 }
200251
201252 @ Override
202253 public void logBooleanArray (boolean [] value ) {
203- log (m_path , value .clone ());
254+ log (this , value .clone ());
204255 }
205256
206257 @ Override
207258 public void logShortArray (short [] value ) {
208- log (m_path , value .clone ());
259+ log (this , value .clone ());
209260 }
210261
211262 @ Override
212263 public void logIntArray (int [] value ) {
213- log (m_path , value .clone ());
264+ log (this , value .clone ());
214265 }
215266
216267 @ Override
217268 public void logLongArray (long [] value ) {
218- log (m_path , value .clone ());
269+ log (this , value .clone ());
219270 }
220271
221272 @ Override
222273 public void logFloatArray (float [] value ) {
223- log (m_path , value .clone ());
274+ log (this , value .clone ());
224275 }
225276
226277 @ Override
227278 public void logDoubleArray (double [] value ) {
228- log (m_path , value .clone ());
279+ log (this , value .clone ());
229280 }
230281
231282 @ Override
232283 public void logStringArray (String [] value ) {
233- log (m_path , value .clone ());
284+ log (this , value .clone ());
234285 }
235286
236287 @ Override
237288 public void logRaw (byte [] value , String typeString ) {
238- log (m_path , new LogRawValue (value .clone (), typeString ));
289+ log (this , new LogRawValue (value .clone (), typeString ));
239290 }
240291
241292 private final String m_path ;
293+ private int m_last = -1 ;
242294 }
243295}
0 commit comments