• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base.test.metrics;
6 
7 import androidx.annotation.IntDef;
8 
9 import org.junit.Assert;
10 
11 import org.chromium.base.library_loader.LibraryLoader;
12 import org.chromium.base.metrics.RecordHistogram;
13 import org.chromium.base.test.util.HistogramWatcher;
14 
15 /**
16  * Tests the {@link HistogramWatcher} test util in the following contexts:
17  * - Before native load
18  * - Transitioning from CachingUmaRecorder (before native load) to NativeUmaRecorder (after).
19  * - After native load
20  *
21  * Tests are split into multiple classes so they can be batched by scenario.
22  */
23 public class HistogramWatcherTestBase {
24     protected static final String TIMES_HISTOGRAM_1 = "TimesHistogram1";
25     protected static final String BOOLEAN_HISTOGRAM = "BooleanHistogram";
26     protected static final String EXACT_LINEAR_HISTOGRAM_1 = "ExactLinearHistogram"; // max 10
27     protected static final String EXACT_LINEAR_HISTOGRAM_2 = "ExactLinearHistogram2"; // max 20
28     protected static final String EXACT_LINEAR_HISTOGRAM_3 = "ExactLinearHistogram3"; // max 30
29     protected static final String ENUM_HISTOGRAM = "EnumHistogram"; // max 10
30 
31     @IntDef({
32         TestScenario.WITHOUT_NATIVE,
33         TestScenario.TRANSITION_TO_NATIVE,
34         TestScenario.WITH_NATIVE
35     })
36     protected @interface TestScenario {
37         int WITHOUT_NATIVE = 0;
38         int TRANSITION_TO_NATIVE = 1;
39         int WITH_NATIVE = 2;
40     }
41 
42     protected HistogramWatcher mWatcher;
43 
doTestSingleRecordMissing_failure(@estScenario int scenario)44     protected void doTestSingleRecordMissing_failure(@TestScenario int scenario) {
45         // Arrange
46         maybeLoadNativeFirst(scenario);
47         mWatcher = HistogramWatcher.newSingleRecordWatcher(TIMES_HISTOGRAM_1, 6000);
48 
49         // Act
50         maybeLoadNativeAfterRecord(scenario);
51 
52         // Assert
53         try {
54             mWatcher.assertExpected();
55         } catch (AssertionError e) {
56             assertContains(TIMES_HISTOGRAM_1, e.getMessage());
57             assertContains("1 record(s) expected: [6000]", e.getMessage());
58             assertContains("0 record(s) seen: []", e.getMessage());
59             return;
60         }
61         Assert.fail("Expected AssertionError");
62     }
63 
doTestFourTimesHistograms_success(@estScenario int scenario)64     protected void doTestFourTimesHistograms_success(@TestScenario int scenario) {
65         // Arrange
66         maybeLoadNativeFirst(scenario);
67         mWatcher =
68                 HistogramWatcher.newBuilder()
69                         .expectIntRecord(TIMES_HISTOGRAM_1, 6000)
70                         .expectIntRecord(TIMES_HISTOGRAM_1, 7000)
71                         .expectIntRecordTimes(TIMES_HISTOGRAM_1, 8000, 2)
72                         .build();
73 
74         // Act
75         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 6000);
76         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 7000);
77         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
78         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
79         maybeLoadNativeAfterRecord(scenario);
80 
81         // Assert
82         mWatcher.assertExpected();
83     }
84 
doTestExtraRecord_failure(@estScenario int scenario)85     protected void doTestExtraRecord_failure(@TestScenario int scenario) {
86         // Arrange
87         maybeLoadNativeFirst(scenario);
88         mWatcher =
89                 HistogramWatcher.newBuilder()
90                         .expectIntRecord(TIMES_HISTOGRAM_1, 6000)
91                         .expectIntRecord(TIMES_HISTOGRAM_1, 7000)
92                         .expectIntRecordTimes(TIMES_HISTOGRAM_1, 8000, 2)
93                         .build();
94 
95         // Act
96         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 6000);
97         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 7000);
98         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
99         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
100         // Extra record that should break the test
101         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
102         maybeLoadNativeAfterRecord(scenario);
103 
104         // Assert
105         try {
106             mWatcher.assertExpected();
107         } catch (AssertionError e) {
108             assertContains(TIMES_HISTOGRAM_1, e.getMessage());
109             assertContains("4 record(s) expected: [6000, 7000, 8000 (2 times)]", e.getMessage());
110             // Exact histogram buckets can be arbitrary
111             assertContains("5 record(s) seen: [", e.getMessage());
112             return;
113         }
114         Assert.fail("Expected AssertionError");
115     }
116 
doTestExtraRecordAllowed_success(@estScenario int scenario)117     protected void doTestExtraRecordAllowed_success(@TestScenario int scenario) {
118         // Arrange
119         maybeLoadNativeFirst(scenario);
120         mWatcher =
121                 HistogramWatcher.newBuilder()
122                         .expectIntRecord(ENUM_HISTOGRAM, 6)
123                         .expectIntRecord(ENUM_HISTOGRAM, 7)
124                         .expectIntRecordTimes(ENUM_HISTOGRAM, 8, 2)
125                         .allowExtraRecordsForHistogramsAbove()
126                         .build();
127 
128         // Act
129         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 6, 10);
130         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 7, 10);
131         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 8, 10);
132         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 8, 10);
133         // Extra record that should not break the test
134         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 8, 10);
135         maybeLoadNativeAfterRecord(scenario);
136 
137         // Assert
138         mWatcher.assertExpected();
139     }
140 
doTestExtraRecordAllowed_failure(@estScenario int scenario)141     protected void doTestExtraRecordAllowed_failure(@TestScenario int scenario) {
142         // Arrange
143         maybeLoadNativeFirst(scenario);
144         mWatcher =
145                 HistogramWatcher.newBuilder()
146                         .expectIntRecord(ENUM_HISTOGRAM, 6)
147                         .expectIntRecord(ENUM_HISTOGRAM, 7)
148                         .expectIntRecordTimes(ENUM_HISTOGRAM, 8, 2)
149                         .allowExtraRecordsForHistogramsAbove()
150                         .build();
151 
152         // Act
153         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 6, 10);
154         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 7, 10);
155         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 8, 10);
156         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 9, 10);
157         maybeLoadNativeAfterRecord(scenario);
158 
159         // Assert
160         try {
161             mWatcher.assertExpected();
162         } catch (AssertionError e) {
163             assertContains(ENUM_HISTOGRAM, e.getMessage());
164             assertContains("4 record(s) expected: [6, 7, 8 (2 times)]", e.getMessage());
165             // Exact histogram buckets can be arbitrary
166             assertContains("4 record(s) seen: [6, 7, 8, 9]", e.getMessage());
167             return;
168         }
169         Assert.fail("Expected AssertionError");
170     }
171 
doTestExtraRecordAllowedAny_success(@estScenario int scenario)172     protected void doTestExtraRecordAllowedAny_success(@TestScenario int scenario) {
173         // Arrange
174         maybeLoadNativeFirst(scenario);
175         mWatcher =
176                 HistogramWatcher.newBuilder()
177                         .expectAnyRecordTimes(BOOLEAN_HISTOGRAM, 3)
178                         .allowExtraRecordsForHistogramsAbove()
179                         .build();
180 
181         // Act
182         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
183         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
184         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, true);
185         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, true);
186         maybeLoadNativeAfterRecord(scenario);
187 
188         // Assert
189         mWatcher.assertExpected();
190     }
191 
doTestExtraRecordAllowedAny_failure(@estScenario int scenario)192     protected void doTestExtraRecordAllowedAny_failure(@TestScenario int scenario) {
193         // Arrange
194         maybeLoadNativeFirst(scenario);
195         mWatcher =
196                 HistogramWatcher.newBuilder()
197                         .expectAnyRecordTimes(BOOLEAN_HISTOGRAM, 3)
198                         .allowExtraRecordsForHistogramsAbove()
199                         .build();
200 
201         // Act
202         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
203         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
204         maybeLoadNativeAfterRecord(scenario);
205 
206         // Assert
207         try {
208             mWatcher.assertExpected();
209         } catch (AssertionError e) {
210             assertContains(BOOLEAN_HISTOGRAM, e.getMessage());
211             assertContains("3 record(s) expected: [Any (3 times)]", e.getMessage());
212             assertContains("2 record(s) seen: [0 (2 times)]", e.getMessage());
213             return;
214         }
215         Assert.fail("Expected AssertionError");
216     }
217 
doTestMissingLastRecord_failure(@estScenario int scenario)218     protected void doTestMissingLastRecord_failure(@TestScenario int scenario) {
219         // Arrange
220         maybeLoadNativeFirst(scenario);
221         mWatcher =
222                 HistogramWatcher.newBuilder()
223                         .expectIntRecord(TIMES_HISTOGRAM_1, 6000)
224                         .expectIntRecord(TIMES_HISTOGRAM_1, 7000)
225                         .expectIntRecordTimes(TIMES_HISTOGRAM_1, 8000, 2)
226                         .build();
227 
228         // Act
229         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 6000);
230         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 7000);
231         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
232         maybeLoadNativeAfterRecord(scenario);
233 
234         // Assert
235         try {
236             mWatcher.assertExpected();
237         } catch (AssertionError e) {
238             assertContains(TIMES_HISTOGRAM_1, e.getMessage());
239             assertContains("4 record(s) expected: [6000, 7000, 8000 (2 times)]", e.getMessage());
240             // Exact histogram buckets can be arbitrary
241             assertContains("3 record(s) seen: [", e.getMessage());
242             return;
243         }
244         Assert.fail("Expected AssertionError");
245     }
246 
doTestExpectNoRecords_failure(@estScenario int scenario)247     protected void doTestExpectNoRecords_failure(@TestScenario int scenario) {
248         // Arrange
249         maybeLoadNativeFirst(scenario);
250         mWatcher = HistogramWatcher.newBuilder().expectNoRecords(ENUM_HISTOGRAM).build();
251 
252         // Act
253         RecordHistogram.recordEnumeratedHistogram(ENUM_HISTOGRAM, 5, 10);
254         maybeLoadNativeAfterRecord(scenario);
255 
256         // Assert
257         try {
258             mWatcher.assertExpected();
259         } catch (AssertionError e) {
260             assertContains(ENUM_HISTOGRAM, e.getMessage());
261             assertContains("0 record(s) expected: []", e.getMessage());
262             assertContains("1 record(s) seen: [5]", e.getMessage());
263             return;
264         }
265         Assert.fail("Expected AssertionError");
266     }
267 
doTestExpectAnyRecords_missing_failure(@estScenario int scenario)268     protected void doTestExpectAnyRecords_missing_failure(@TestScenario int scenario) {
269         // Arrange
270         maybeLoadNativeFirst(scenario);
271         mWatcher = HistogramWatcher.newBuilder().expectAnyRecordTimes(BOOLEAN_HISTOGRAM, 3).build();
272 
273         // Act
274         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
275         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
276         maybeLoadNativeAfterRecord(scenario);
277 
278         // Assert
279         try {
280             mWatcher.assertExpected();
281         } catch (AssertionError e) {
282             assertContains(BOOLEAN_HISTOGRAM, e.getMessage());
283             assertContains("3 record(s) expected: [Any (3 times)]", e.getMessage());
284             assertContains("2 record(s) seen: [0 (2 times)]", e.getMessage());
285             return;
286         }
287         Assert.fail("Expected AssertionError");
288     }
289 
doTestExpectAnyRecords_extras_failure(@estScenario int scenario)290     protected void doTestExpectAnyRecords_extras_failure(@TestScenario int scenario) {
291         // Arrange
292         maybeLoadNativeFirst(scenario);
293         mWatcher = HistogramWatcher.newBuilder().expectAnyRecordTimes(BOOLEAN_HISTOGRAM, 3).build();
294 
295         // Act
296         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
297         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
298         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, true);
299         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, true);
300         maybeLoadNativeAfterRecord(scenario);
301 
302         // Assert
303         try {
304             mWatcher.assertExpected();
305         } catch (AssertionError e) {
306             assertContains(BOOLEAN_HISTOGRAM, e.getMessage());
307             assertContains("3 record(s) expected: [Any (3 times)]", e.getMessage());
308             assertContains("4 record(s) seen: [0 (2 times), 1 (2 times)]", e.getMessage());
309             return;
310         }
311         Assert.fail("Expected AssertionError");
312     }
313 
doTestExpectAnyRecords_success(@estScenario int scenario)314     protected void doTestExpectAnyRecords_success(@TestScenario int scenario) {
315         // Arrange
316         maybeLoadNativeFirst(scenario);
317         mWatcher = HistogramWatcher.newBuilder().expectAnyRecordTimes(BOOLEAN_HISTOGRAM, 3).build();
318 
319         // Act
320         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
321         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, false);
322         RecordHistogram.recordBooleanHistogram(BOOLEAN_HISTOGRAM, true);
323         maybeLoadNativeAfterRecord(scenario);
324 
325         // Assert
326         mWatcher.assertExpected();
327     }
328 
doTestMultipleHistograms_success(@estScenario int scenario)329     protected void doTestMultipleHistograms_success(@TestScenario int scenario) {
330         // Arrange
331         maybeLoadNativeFirst(scenario);
332         mWatcher =
333                 HistogramWatcher.newBuilder()
334                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_1, 5)
335                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_1, 6)
336                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_2, 15)
337                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_2, 16)
338                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_3, 25)
339                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_3, 26)
340                         .build();
341 
342         // Act
343         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 5, 10);
344         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_2, 15, 20);
345         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_3, 25, 30);
346         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 6, 10);
347         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_2, 16, 20);
348         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_3, 26, 30);
349         maybeLoadNativeAfterRecord(scenario);
350 
351         // Assert
352         mWatcher.assertExpected();
353     }
354 
doTestMultipleHistograms_failure(@estScenario int scenario)355     protected void doTestMultipleHistograms_failure(@TestScenario int scenario) {
356         // Arrange
357         maybeLoadNativeFirst(scenario);
358         mWatcher =
359                 HistogramWatcher.newBuilder()
360                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_1, 5)
361                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_1, 6)
362                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_2, 15)
363                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_2, 16)
364                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_3, 25)
365                         .expectIntRecord(EXACT_LINEAR_HISTOGRAM_3, 26)
366                         .build();
367 
368         // Act
369         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 5, 10);
370         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_2, 15, 20);
371         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_3, 25, 30);
372         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 6, 10);
373         // Miss recording EXACT_LINEAR_HISTOGRAM_2 with value 16.
374         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_3, 26, 30);
375         maybeLoadNativeAfterRecord(scenario);
376 
377         // Assert
378         try {
379             mWatcher.assertExpected();
380         } catch (AssertionError e) {
381             assertContains(EXACT_LINEAR_HISTOGRAM_2, e.getMessage());
382             assertContains("2 record(s) expected: [15, 16]", e.getMessage());
383             assertContains("1 record(s) seen: [15]", e.getMessage());
384             return;
385         }
386         Assert.fail("Expected AssertionError");
387     }
388 
doTestExpectIntRecords_success(@estScenario int scenario)389     protected void doTestExpectIntRecords_success(@TestScenario int scenario) {
390         // Arrange
391         maybeLoadNativeFirst(scenario);
392         mWatcher =
393                 HistogramWatcher.newBuilder()
394                         .expectIntRecords(EXACT_LINEAR_HISTOGRAM_1, 5, 7, 6, 5)
395                         .build();
396 
397         // Act
398         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 6, 10);
399         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 5, 10);
400         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 7, 10);
401         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 5, 10);
402         maybeLoadNativeAfterRecord(scenario);
403 
404         // Assert
405         mWatcher.assertExpected();
406     }
407 
doTestExpectIntRecords_failure(@estScenario int scenario)408     protected void doTestExpectIntRecords_failure(@TestScenario int scenario) {
409         // Arrange
410         maybeLoadNativeFirst(scenario);
411         mWatcher =
412                 HistogramWatcher.newBuilder()
413                         .expectIntRecords(EXACT_LINEAR_HISTOGRAM_1, 5, 7, 6, 5)
414                         .build();
415 
416         // Act
417         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 6, 10);
418         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 5, 10);
419         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 7, 10);
420         // Miss recording EXACT_LINEAR_HISTOGRAM_1 with value 5.
421         maybeLoadNativeAfterRecord(scenario);
422 
423         // Assert
424         try {
425             mWatcher.assertExpected();
426         } catch (AssertionError e) {
427             assertContains(EXACT_LINEAR_HISTOGRAM_1, e.getMessage());
428             assertContains("4 record(s) expected: [5 (2 times), 6, 7]", e.getMessage());
429             assertContains("3 record(s) seen: [5, 6, 7]", e.getMessage());
430             return;
431         }
432         Assert.fail("Expected AssertionError");
433     }
434 
doTestIgnoreOtherHistograms_success(@estScenario int scenario)435     protected void doTestIgnoreOtherHistograms_success(@TestScenario int scenario) {
436         // Arrange
437         maybeLoadNativeFirst(scenario);
438         mWatcher =
439                 HistogramWatcher.newBuilder().expectIntRecord(EXACT_LINEAR_HISTOGRAM_1, 5).build();
440 
441         // Act
442         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_1, 5, 10);
443         RecordHistogram.recordExactLinearHistogram(EXACT_LINEAR_HISTOGRAM_2, 15, 20);
444         maybeLoadNativeAfterRecord(scenario);
445 
446         // Assert
447         mWatcher.assertExpected();
448     }
449 
doTestMissingFirstRecord_failure(@estScenario int scenario)450     protected void doTestMissingFirstRecord_failure(@TestScenario int scenario) {
451         // Arrange
452         maybeLoadNativeFirst(scenario);
453         mWatcher =
454                 HistogramWatcher.newBuilder()
455                         .expectIntRecord(TIMES_HISTOGRAM_1, 6000)
456                         .expectIntRecord(TIMES_HISTOGRAM_1, 7000)
457                         .expectIntRecord(TIMES_HISTOGRAM_1, 8000)
458                         .build();
459 
460         // Act
461         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 7000);
462         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
463         maybeLoadNativeAfterRecord(scenario);
464 
465         // Assert
466         try {
467             mWatcher.assertExpected();
468         } catch (AssertionError e) {
469             assertContains(TIMES_HISTOGRAM_1, e.getMessage());
470             assertContains("3 record(s) expected: [6000, 7000, 8000]", e.getMessage());
471             // Exact histogram buckets can be arbitrary
472             assertContains("2 record(s) seen: [", e.getMessage());
473             return;
474         }
475         Assert.fail("Expected AssertionError");
476     }
477 
doTestMissingMiddleRecord_failure(@estScenario int scenario)478     protected void doTestMissingMiddleRecord_failure(@TestScenario int scenario) {
479         // Arrange
480         maybeLoadNativeFirst(scenario);
481         mWatcher =
482                 HistogramWatcher.newBuilder()
483                         .expectIntRecord(TIMES_HISTOGRAM_1, 6000)
484                         .expectIntRecord(TIMES_HISTOGRAM_1, 7000)
485                         .expectIntRecord(TIMES_HISTOGRAM_1, 8000)
486                         .build();
487 
488         // Act
489         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 6000);
490         RecordHistogram.recordTimesHistogram(TIMES_HISTOGRAM_1, 8000);
491         maybeLoadNativeAfterRecord(scenario);
492 
493         // Assert
494         try {
495             mWatcher.assertExpected();
496         } catch (AssertionError e) {
497             assertContains(TIMES_HISTOGRAM_1, e.getMessage());
498             assertContains("3 record(s) expected: [6000, 7000, 8000]", e.getMessage());
499             // Exact histogram buckets can be arbitrary
500             assertContains("2 record(s) seen: [", e.getMessage());
501             return;
502         }
503         Assert.fail("Expected AssertionError");
504     }
505 
maybeLoadNativeAfterRecord(int scenario)506     protected void maybeLoadNativeAfterRecord(int scenario) {
507         if (scenario == TestScenario.TRANSITION_TO_NATIVE) {
508             LibraryLoader.getInstance().ensureInitialized();
509         }
510     }
511 
maybeLoadNativeFirst(int scenario)512     protected void maybeLoadNativeFirst(int scenario) {
513         if (scenario == TestScenario.WITH_NATIVE) {
514             LibraryLoader.getInstance().ensureInitialized();
515         }
516     }
517 
assertContains(String expectedSubstring, String actualString)518     protected static void assertContains(String expectedSubstring, String actualString) {
519         Assert.assertNotNull(actualString);
520         if (!actualString.contains(expectedSubstring)) {
521             Assert.fail(
522                     String.format(
523                             "Substring <%s> not found in string <%s>",
524                             expectedSubstring, actualString));
525         }
526     }
527 }
528