1 // Copyright 2017 The Chromium Authors. All rights reserved. 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; 6 7 import android.os.Process; 8 import android.support.test.filters.SmallTest; 9 10 import org.junit.Assert; 11 import org.junit.Before; 12 import org.junit.Test; 13 import org.junit.runner.RunWith; 14 15 import org.chromium.base.EarlyTraceEvent.AsyncEvent; 16 import org.chromium.base.EarlyTraceEvent.Event; 17 import org.chromium.base.library_loader.LibraryLoader; 18 import org.chromium.base.test.BaseJUnit4ClassRunner; 19 import org.chromium.base.test.util.Feature; 20 21 import java.util.ArrayList; 22 import java.util.List; 23 24 /** 25 * Tests for {@link EarlyTraceEvent}. 26 * 27 * TODO(lizeb): Move to roboelectric tests. 28 */ 29 @RunWith(BaseJUnit4ClassRunner.class) 30 public class EarlyTraceEventTest { 31 private static final String EVENT_NAME = "MyEvent"; 32 private static final String EVENT_NAME2 = "MyOtherEvent"; 33 private static final long EVENT_ID = 1; 34 private static final long EVENT_ID2 = 2; 35 getMatchingCompletedEventCount(String eventName)36 int getMatchingCompletedEventCount(String eventName) { 37 int count = 0; 38 for (Event evt : EarlyTraceEvent.sCompletedEvents) { 39 if (evt.mName.equals(eventName)) { 40 count++; 41 } 42 } 43 return count; 44 } 45 getMatchingCompletedEvent(int idx, String eventName)46 Event getMatchingCompletedEvent(int idx, String eventName) { 47 int currIdx = idx; 48 for (Event evt : EarlyTraceEvent.sCompletedEvents) { 49 if (currIdx == 0 && evt.mName.equals(eventName)) { 50 return evt; 51 } 52 currIdx--; 53 } 54 Assert.fail("No event " + eventName + " at index " + idx); 55 return null; 56 } 57 pendingEventsContain(String eventName)58 boolean pendingEventsContain(String eventName) { 59 return EarlyTraceEvent.sPendingEventByKey.containsKey( 60 EarlyTraceEvent.makeEventKeyForCurrentThread(eventName)); 61 } 62 63 @Before setUp()64 public void setUp() { 65 LibraryLoader.getInstance().ensureInitialized(); 66 EarlyTraceEvent.resetForTesting(); 67 } 68 69 @Test 70 @SmallTest 71 @Feature({"Android-AppBase"}) testCanRecordEvent()72 public void testCanRecordEvent() { 73 EarlyTraceEvent.enable(); 74 long myThreadId = Process.myTid(); 75 long beforeNanos = Event.elapsedRealtimeNanos(); 76 EarlyTraceEvent.begin(EVENT_NAME); 77 EarlyTraceEvent.end(EVENT_NAME); 78 long afterNanos = Event.elapsedRealtimeNanos(); 79 80 Assert.assertEquals(1, getMatchingCompletedEventCount(EVENT_NAME)); 81 Assert.assertFalse(pendingEventsContain(EVENT_NAME)); 82 Event event = getMatchingCompletedEvent(0, EVENT_NAME); 83 Assert.assertEquals(EVENT_NAME, event.mName); 84 Assert.assertEquals(myThreadId, event.mThreadId); 85 Assert.assertTrue( 86 beforeNanos <= event.mBeginTimeNanos && event.mBeginTimeNanos <= afterNanos); 87 Assert.assertTrue(event.mBeginTimeNanos <= event.mEndTimeNanos); 88 Assert.assertTrue(beforeNanos <= event.mEndTimeNanos && event.mEndTimeNanos <= afterNanos); 89 } 90 91 @Test 92 @SmallTest 93 @Feature({"Android-AppBase"}) testCanRecordAsyncEvent()94 public void testCanRecordAsyncEvent() { 95 EarlyTraceEvent.enable(); 96 long beforeNanos = Event.elapsedRealtimeNanos(); 97 EarlyTraceEvent.startAsync(EVENT_NAME, EVENT_ID); 98 EarlyTraceEvent.finishAsync(EVENT_NAME, EVENT_ID); 99 long afterNanos = Event.elapsedRealtimeNanos(); 100 101 List<AsyncEvent> matchingEvents = new ArrayList<AsyncEvent>(); 102 for (AsyncEvent evt : EarlyTraceEvent.sAsyncEvents) { 103 if (evt.mName.equals(EVENT_NAME)) { 104 matchingEvents.add(evt); 105 } 106 } 107 Assert.assertEquals(2, matchingEvents.size()); 108 Assert.assertFalse(pendingEventsContain(EVENT_NAME)); 109 AsyncEvent eventStart = matchingEvents.get(0); 110 AsyncEvent eventEnd = matchingEvents.get(1); 111 Assert.assertEquals(EVENT_NAME, eventStart.mName); 112 Assert.assertEquals(EVENT_ID, eventStart.mId); 113 Assert.assertEquals(EVENT_NAME, eventEnd.mName); 114 Assert.assertEquals(EVENT_ID, eventEnd.mId); 115 Assert.assertTrue(beforeNanos <= eventStart.mTimestampNanos 116 && eventEnd.mTimestampNanos <= afterNanos); 117 Assert.assertTrue(eventStart.mTimestampNanos <= eventEnd.mTimestampNanos); 118 } 119 120 @Test 121 @SmallTest 122 @Feature({"Android-AppBase"}) testRecordAsyncFinishEventWhenFinishing()123 public void testRecordAsyncFinishEventWhenFinishing() { 124 EarlyTraceEvent.enable(); 125 EarlyTraceEvent.startAsync(EVENT_NAME, EVENT_ID); 126 EarlyTraceEvent.disable(); 127 128 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHING, EarlyTraceEvent.sState); 129 for (AsyncEvent evt : EarlyTraceEvent.sAsyncEvents) { 130 Assert.assertNotEquals(EVENT_NAME, evt.mName); 131 } 132 int pendingCount = 0; 133 for (String name : EarlyTraceEvent.sPendingAsyncEvents) { 134 if (name.equals(EVENT_NAME)) { 135 ++pendingCount; 136 } 137 } 138 Assert.assertEquals(1, pendingCount); 139 EarlyTraceEvent.finishAsync(EVENT_NAME, EVENT_ID); 140 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState); 141 } 142 143 @Test 144 @SmallTest 145 @Feature({"Android-AppBase"}) testCanRecordEventUsingTryWith()146 public void testCanRecordEventUsingTryWith() { 147 EarlyTraceEvent.enable(); 148 long myThreadId = Process.myTid(); 149 long beforeNanos = Event.elapsedRealtimeNanos(); 150 try (TraceEvent e = TraceEvent.scoped(EVENT_NAME)) { 151 // Required comment to pass presubmit checks. 152 } 153 long afterNanos = Event.elapsedRealtimeNanos(); 154 155 Assert.assertEquals(1, getMatchingCompletedEventCount(EVENT_NAME)); 156 Assert.assertFalse(pendingEventsContain(EVENT_NAME)); 157 Event event = getMatchingCompletedEvent(0, EVENT_NAME); 158 Assert.assertEquals(EVENT_NAME, event.mName); 159 Assert.assertEquals(myThreadId, event.mThreadId); 160 Assert.assertTrue( 161 beforeNanos <= event.mBeginTimeNanos && event.mBeginTimeNanos <= afterNanos); 162 Assert.assertTrue(event.mBeginTimeNanos <= event.mEndTimeNanos); 163 Assert.assertTrue(beforeNanos <= event.mEndTimeNanos && event.mEndTimeNanos <= afterNanos); 164 } 165 166 @Test 167 @SmallTest 168 @Feature({"Android-AppBase"}) testIncompleteEvent()169 public void testIncompleteEvent() { 170 EarlyTraceEvent.enable(); 171 EarlyTraceEvent.begin(EVENT_NAME); 172 173 Assert.assertEquals(0, getMatchingCompletedEventCount(EVENT_NAME)); 174 Assert.assertTrue(pendingEventsContain(EVENT_NAME)); 175 EarlyTraceEvent.Event event = EarlyTraceEvent.sPendingEventByKey.get( 176 EarlyTraceEvent.makeEventKeyForCurrentThread(EVENT_NAME)); 177 Assert.assertEquals(EVENT_NAME, event.mName); 178 } 179 180 @Test 181 @SmallTest 182 @Feature({"Android-AppBase"}) testNoDuplicatePendingEventsFromSameThread()183 public void testNoDuplicatePendingEventsFromSameThread() { 184 EarlyTraceEvent.enable(); 185 EarlyTraceEvent.begin(EVENT_NAME); 186 try { 187 EarlyTraceEvent.begin(EVENT_NAME); 188 } catch (IllegalArgumentException e) { 189 // Expected. 190 return; 191 } 192 Assert.fail(); 193 } 194 195 @Test 196 @SmallTest 197 @Feature({"Android-AppBase"}) testDuplicatePendingEventsFromDifferentThreads()198 public void testDuplicatePendingEventsFromDifferentThreads() throws Exception { 199 EarlyTraceEvent.enable(); 200 201 Thread otherThread = new Thread(() -> { EarlyTraceEvent.begin(EVENT_NAME); }); 202 otherThread.start(); 203 otherThread.join(); 204 205 // At this point we have a pending event with EVENT_NAME name. But events are per 206 // thread, so we should be able to start EVENT_NAME event in a different thread. 207 EarlyTraceEvent.begin(EVENT_NAME); 208 } 209 210 @Test 211 @SmallTest 212 @Feature({"Android-AppBase"}) testIgnoreEventsWhenDisabled()213 public void testIgnoreEventsWhenDisabled() { 214 EarlyTraceEvent.begin(EVENT_NAME); 215 EarlyTraceEvent.end(EVENT_NAME); 216 try (TraceEvent e = TraceEvent.scoped(EVENT_NAME2)) { 217 // Required comment to pass presubmit checks. 218 } 219 Assert.assertNull(EarlyTraceEvent.sCompletedEvents); 220 } 221 222 @Test 223 @SmallTest 224 @Feature({"Android-AppBase"}) testIgnoreAsyncEventsWhenDisabled()225 public void testIgnoreAsyncEventsWhenDisabled() { 226 EarlyTraceEvent.startAsync(EVENT_NAME, EVENT_ID); 227 EarlyTraceEvent.finishAsync(EVENT_NAME, EVENT_ID); 228 Assert.assertNull(EarlyTraceEvent.sAsyncEvents); 229 } 230 231 @Test 232 @SmallTest 233 @Feature({"Android-AppBase"}) testIgnoreNewEventsWhenFinishing()234 public void testIgnoreNewEventsWhenFinishing() { 235 EarlyTraceEvent.enable(); 236 EarlyTraceEvent.begin(EVENT_NAME); 237 EarlyTraceEvent.disable(); 238 239 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHING, EarlyTraceEvent.sState); 240 EarlyTraceEvent.begin(EVENT_NAME2); 241 EarlyTraceEvent.end(EVENT_NAME2); 242 243 Assert.assertTrue(pendingEventsContain(EVENT_NAME)); 244 Assert.assertFalse(pendingEventsContain(EVENT_NAME2)); 245 Assert.assertEquals(0, getMatchingCompletedEventCount(EVENT_NAME)); 246 Assert.assertEquals(0, getMatchingCompletedEventCount(EVENT_NAME2)); 247 } 248 249 @Test 250 @SmallTest 251 @Feature({"Android-AppBase"}) testIgnoreNewAsyncEventsWhenFinishing()252 public void testIgnoreNewAsyncEventsWhenFinishing() { 253 EarlyTraceEvent.enable(); 254 EarlyTraceEvent.startAsync(EVENT_NAME, EVENT_ID); 255 EarlyTraceEvent.disable(); 256 257 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHING, EarlyTraceEvent.sState); 258 EarlyTraceEvent.startAsync(EVENT_NAME2, EVENT_ID2); 259 260 int pendingCount = 0; 261 for (String name : EarlyTraceEvent.sPendingAsyncEvents) { 262 if (name.equals(EVENT_NAME)) { 263 ++pendingCount; 264 } 265 } 266 Assert.assertEquals(1, pendingCount); 267 268 for (AsyncEvent evt : EarlyTraceEvent.sAsyncEvents) { 269 Assert.assertNotEquals(EVENT_NAME, evt.mName); 270 } 271 } 272 273 @Test 274 @SmallTest 275 @Feature({"Android-AppBase"}) testFinishingToFinished()276 public void testFinishingToFinished() { 277 EarlyTraceEvent.enable(); 278 EarlyTraceEvent.begin(EVENT_NAME); 279 EarlyTraceEvent.disable(); 280 281 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHING, EarlyTraceEvent.sState); 282 EarlyTraceEvent.begin(EVENT_NAME2); 283 EarlyTraceEvent.end(EVENT_NAME2); 284 EarlyTraceEvent.end(EVENT_NAME); 285 286 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState); 287 } 288 289 @Test 290 @SmallTest 291 @Feature({"Android-AppBase"}) testCannotBeReenabledOnceFinished()292 public void testCannotBeReenabledOnceFinished() { 293 EarlyTraceEvent.enable(); 294 EarlyTraceEvent.begin(EVENT_NAME); 295 EarlyTraceEvent.end(EVENT_NAME); 296 EarlyTraceEvent.disable(); 297 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState); 298 299 EarlyTraceEvent.enable(); 300 Assert.assertEquals(EarlyTraceEvent.STATE_FINISHED, EarlyTraceEvent.sState); 301 } 302 303 @Test 304 @SmallTest 305 @Feature({"Android-AppBase"}) testThreadIdIsRecorded()306 public void testThreadIdIsRecorded() throws Exception { 307 EarlyTraceEvent.enable(); 308 final long[] threadId = {0}; 309 310 Thread thread = new Thread() { 311 @Override 312 public void run() { 313 TraceEvent.begin(EVENT_NAME); 314 threadId[0] = Process.myTid(); 315 TraceEvent.end(EVENT_NAME); 316 } 317 }; 318 thread.start(); 319 thread.join(); 320 321 Assert.assertEquals(1, getMatchingCompletedEventCount(EVENT_NAME)); 322 EarlyTraceEvent.Event event = getMatchingCompletedEvent(0, EVENT_NAME); 323 Assert.assertEquals(threadId[0], event.mThreadId); 324 } 325 326 @Test 327 @SmallTest 328 @Feature({"Android-AppBase"}) testEnableAtStartup()329 public void testEnableAtStartup() { 330 ThreadUtils.setThreadAssertsDisabledForTesting(true); 331 EarlyTraceEvent.maybeEnable(); 332 Assert.assertFalse(EarlyTraceEvent.enabled()); 333 EarlyTraceEvent.setBackgroundStartupTracingFlag(false); 334 Assert.assertFalse(EarlyTraceEvent.enabled()); 335 336 EarlyTraceEvent.setBackgroundStartupTracingFlag(true); 337 EarlyTraceEvent.maybeEnable(); 338 Assert.assertTrue(EarlyTraceEvent.getBackgroundStartupTracingFlag()); 339 Assert.assertTrue(EarlyTraceEvent.enabled()); 340 EarlyTraceEvent.disable(); 341 EarlyTraceEvent.setBackgroundStartupTracingFlag(false); 342 } 343 344 @Test 345 @SmallTest 346 @Feature({"Android-AppBase"}) testUserOverrideBackgroundTracing()347 public void testUserOverrideBackgroundTracing() { 348 ThreadUtils.setThreadAssertsDisabledForTesting(true); 349 // Setting command line should disable the background tracing flag. 350 CommandLine.getInstance().appendSwitch("trace-startup"); 351 EarlyTraceEvent.setBackgroundStartupTracingFlag(true); 352 EarlyTraceEvent.maybeEnable(); 353 Assert.assertFalse(EarlyTraceEvent.getBackgroundStartupTracingFlag()); 354 Assert.assertTrue(EarlyTraceEvent.enabled()); 355 EarlyTraceEvent.disable(); 356 EarlyTraceEvent.setBackgroundStartupTracingFlag(false); 357 } 358 } 359