11
11
import java .util .HashMap ;
12
12
import java .util .List ;
13
13
import java .util .Map ;
14
+ import java .util .concurrent .locks .ReentrantLock ;
14
15
import java .util .function .BiConsumer ;
15
16
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
+ */
17
21
public class MockTelemetryBackend implements TelemetryBackend {
18
22
/** Value for keepDuplicate() action. */
19
- public record KeepDuplicateValue (boolean value ) {}
23
+ public record KeepDuplicateValue (boolean value ) {
24
+ }
20
25
21
26
/** Value for setProperty() action. */
22
- public record SetPropertyValue (String key , String value ) {}
27
+ public record SetPropertyValue (String key , String value ) {
28
+ }
23
29
24
30
/** 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
+ }
26
33
27
34
/** 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
+ }
29
37
30
38
/** 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
+ }
32
41
33
42
/** Value for logString() action. */
34
- public record LogStringValue (String value , String typeString ) {}
43
+ public record LogStringValue (String value , String typeString ) {
44
+ }
35
45
36
46
/** Value for logRaw() action. */
37
- public record LogRawValue (byte [] value , String typeString ) {}
47
+ public record LogRawValue (byte [] value , String typeString ) {
48
+ }
38
49
39
50
/** A logged action. */
40
- public record Action (String path , Object value ) {}
51
+ public record Action (String path , Object value ) {
52
+ }
41
53
42
54
private final Map <String , Entry > m_entries = new HashMap <>();
43
55
private final List <Action > m_actions = new ArrayList <>();
@@ -53,29 +65,68 @@ public List<Action> getActions() {
53
65
54
66
/** Clear logged actions. */
55
67
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 ;
57
106
}
58
107
59
108
@ Override
60
109
public void close () {
61
- synchronized (m_entries ) {
110
+ synchronized (this ) {
62
111
m_entries .clear ();
63
112
}
64
113
}
65
114
66
115
@ Override
67
116
public TelemetryEntry getEntry (String path ) {
68
- synchronized (m_entries ) {
117
+ synchronized (this ) {
69
118
return m_entries .computeIfAbsent (path , k -> new Entry (k ));
70
119
}
71
120
}
72
121
73
122
@ Override
74
- public void setReportWarning (BiConsumer <String , StackTraceElement []> func ) {}
123
+ public void setReportWarning (BiConsumer <String , StackTraceElement []> func ) {
124
+ }
75
125
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 ));
79
130
}
80
131
}
81
132
@@ -86,19 +137,19 @@ private final class Entry implements TelemetryEntry {
86
137
87
138
@ Override
88
139
public void keepDuplicates () {
89
- log (m_path , new KeepDuplicateValue (true ));
140
+ log (this , new KeepDuplicateValue (true ));
90
141
}
91
142
92
143
@ Override
93
144
public void setProperty (String key , String value ) {
94
- log (m_path , new SetPropertyValue (key , value ));
145
+ log (this , new SetPropertyValue (key , value ));
95
146
}
96
147
97
148
@ Override
98
149
public <T > void logStruct (T value , Struct <T > struct ) {
99
150
if (struct .isImmutable ()) {
100
151
// log it directly
101
- log (m_path , new LogStructValue <T >(value , struct ));
152
+ log (this , new LogStructValue <T >(value , struct ));
102
153
} else if (struct .isCloneable ()) {
103
154
T clonedValue ;
104
155
try {
@@ -107,20 +158,20 @@ public <T> void logStruct(T value, Struct<T> struct) {
107
158
throw new UnsupportedOperationException (
108
159
"struct.isCloneable() returned true, but clone() raised exception" );
109
160
}
110
- log (m_path , new LogStructValue <T >(clonedValue , struct ));
161
+ log (this , new LogStructValue <T >(clonedValue , struct ));
111
162
} else {
112
163
// log it directly, but warn
113
164
System .err .println (
114
165
"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 ));
116
167
}
117
168
}
118
169
119
170
@ Override
120
171
public <T > void logProtobuf (T value , Protobuf <T , ?> proto ) {
121
172
if (proto .isImmutable ()) {
122
173
// log it directly
123
- log (m_path , new LogProtobufValue <T >(value , proto ));
174
+ log (this , new LogProtobufValue <T >(value , proto ));
124
175
} else if (proto .isCloneable ()) {
125
176
T clonedValue ;
126
177
try {
@@ -129,20 +180,20 @@ public <T> void logProtobuf(T value, Protobuf<T, ?> proto) {
129
180
throw new UnsupportedOperationException (
130
181
"proto.isCloneable() returned true, but clone() raised exception" );
131
182
}
132
- log (m_path , new LogProtobufValue <T >(clonedValue , proto ));
183
+ log (this , new LogProtobufValue <T >(clonedValue , proto ));
133
184
} else {
134
185
// log it directly, but warn
135
186
System .err .println (
136
187
"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 ));
138
189
}
139
190
}
140
191
141
192
@ Override
142
193
public <T > void logStructArray (T [] value , Struct <T > struct ) {
143
194
if (struct .isImmutable ()) {
144
195
// log it directly
145
- log (m_path , new LogStructArrayValue <T >(value .clone (), struct ));
196
+ log (this , new LogStructArrayValue <T >(value .clone (), struct ));
146
197
} else if (struct .isCloneable ()) {
147
198
@ SuppressWarnings ("unchecked" )
148
199
T [] clonedArray = (T []) Array .newInstance (struct .getClass (), value .length );
@@ -154,90 +205,91 @@ public <T> void logStructArray(T[] value, Struct<T> struct) {
154
205
throw new UnsupportedOperationException (
155
206
"struct.isCloneable() returned true, but clone() raised exception" );
156
207
}
157
- log (m_path , new LogStructArrayValue <T >(clonedArray , struct ));
208
+ log (this , new LogStructArrayValue <T >(clonedArray , struct ));
158
209
} else {
159
210
// log it directly, but warn
160
211
System .err .println (
161
212
"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 ));
163
214
}
164
215
}
165
216
166
217
@ Override
167
218
public void logBoolean (boolean value ) {
168
- log (m_path , value );
219
+ log (this , value );
169
220
}
170
221
171
222
@ Override
172
223
public void logShort (short value ) {
173
- log (m_path , value );
224
+ log (this , value );
174
225
}
175
226
176
227
@ Override
177
228
public void logInt (int value ) {
178
- log (m_path , value );
229
+ log (this , value );
179
230
}
180
231
181
232
@ Override
182
233
public void logLong (long value ) {
183
- log (m_path , value );
234
+ log (this , value );
184
235
}
185
236
186
237
@ Override
187
238
public void logFloat (float value ) {
188
- log (m_path , value );
239
+ log (this , value );
189
240
}
190
241
191
242
@ Override
192
243
public void logDouble (double value ) {
193
- log (m_path , value );
244
+ log (this , value );
194
245
}
195
246
196
247
@ Override
197
248
public void logString (String value , String typeString ) {
198
- log (m_path , new LogStringValue (value , typeString ));
249
+ log (this , new LogStringValue (value , typeString ));
199
250
}
200
251
201
252
@ Override
202
253
public void logBooleanArray (boolean [] value ) {
203
- log (m_path , value .clone ());
254
+ log (this , value .clone ());
204
255
}
205
256
206
257
@ Override
207
258
public void logShortArray (short [] value ) {
208
- log (m_path , value .clone ());
259
+ log (this , value .clone ());
209
260
}
210
261
211
262
@ Override
212
263
public void logIntArray (int [] value ) {
213
- log (m_path , value .clone ());
264
+ log (this , value .clone ());
214
265
}
215
266
216
267
@ Override
217
268
public void logLongArray (long [] value ) {
218
- log (m_path , value .clone ());
269
+ log (this , value .clone ());
219
270
}
220
271
221
272
@ Override
222
273
public void logFloatArray (float [] value ) {
223
- log (m_path , value .clone ());
274
+ log (this , value .clone ());
224
275
}
225
276
226
277
@ Override
227
278
public void logDoubleArray (double [] value ) {
228
- log (m_path , value .clone ());
279
+ log (this , value .clone ());
229
280
}
230
281
231
282
@ Override
232
283
public void logStringArray (String [] value ) {
233
- log (m_path , value .clone ());
284
+ log (this , value .clone ());
234
285
}
235
286
236
287
@ Override
237
288
public void logRaw (byte [] value , String typeString ) {
238
- log (m_path , new LogRawValue (value .clone (), typeString ));
289
+ log (this , new LogRawValue (value .clone (), typeString ));
239
290
}
240
291
241
292
private final String m_path ;
293
+ private int m_last = -1 ;
242
294
}
243
295
}
0 commit comments