SessionManagerTest.java revision ba049ae75486276fe6c8dd609ffb4ad58674148d
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.server.telecom.tests; 18 19import android.telecom.Logging.Session; 20import android.telecom.Logging.SessionManager; 21import android.test.suitebuilder.annotation.SmallTest; 22 23import java.lang.ref.WeakReference; 24 25/** 26 * Unit tests for android.telecom.Logging.SessionManager 27 */ 28 29public class SessionManagerTest extends TelecomTestCase { 30 31 private static final String TEST_PARENT_NAME = "testParent"; 32 private static final int TEST_PARENT_THREAD_ID = 0; 33 private static final String TEST_CHILD_NAME = "testChild"; 34 private static final int TEST_CHILD_THREAD_ID = 1; 35 private static final int TEST_DELAY_TIME = 100; // ms 36 37 private SessionManager mTestSessionManager; 38 // Used to verify sessionComplete callback 39 private long mfullSessionCompleteTime = Session.UNDEFINED; 40 private String mFullSessionMethodName = ""; 41 42 @Override 43 public void setUp() throws Exception { 44 super.setUp(); 45 mTestSessionManager = new SessionManager(); 46 mTestSessionManager.registerSessionListener(((sessionName, timeMs) -> { 47 mfullSessionCompleteTime = timeMs; 48 mFullSessionMethodName = sessionName; 49 })); 50 // Remove automatic stale session cleanup for testing 51 mTestSessionManager.mCleanStaleSessions = null; 52 } 53 54 @Override 55 public void tearDown() throws Exception { 56 mFullSessionMethodName = ""; 57 mfullSessionCompleteTime = Session.UNDEFINED; 58 mTestSessionManager = null; 59 super.tearDown(); 60 } 61 62 /** 63 * Starts a Session on the current thread and verifies that it exists in the HashMap 64 */ 65 @SmallTest 66 public void testStartSession() { 67 assertTrue(mTestSessionManager.mSessionMapper.isEmpty()); 68 69 // Set the thread Id to 0 70 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 71 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 72 73 Session testSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 74 assertEquals(TEST_PARENT_NAME, testSession.getShortMethodName()); 75 assertFalse(testSession.isSessionCompleted()); 76 assertFalse(testSession.isStartedFromActiveSession()); 77 } 78 79 /** 80 * Starts two sessions in the same thread. The first session will be parented to the second 81 * session and the second session will be attached to that thread ID. 82 */ 83 @SmallTest 84 public void testStartInvisibleChildSession() { 85 assertTrue(mTestSessionManager.mSessionMapper.isEmpty()); 86 87 // Set the thread Id to 0 for the parent 88 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 89 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 90 // Create invisible child session - same Thread ID as parent 91 mTestSessionManager.startSession(TEST_CHILD_NAME, null); 92 93 // There should only be one session in the mapper (the child) 94 assertEquals(1, mTestSessionManager.mSessionMapper.size()); 95 Session testChildSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 96 assertEquals( TEST_CHILD_NAME, testChildSession.getShortMethodName()); 97 assertTrue(testChildSession.isStartedFromActiveSession()); 98 assertNotNull(testChildSession.getParentSession()); 99 assertEquals(TEST_PARENT_NAME, testChildSession.getParentSession().getShortMethodName()); 100 assertFalse(testChildSession.isSessionCompleted()); 101 assertFalse(testChildSession.getParentSession().isSessionCompleted()); 102 } 103 104 /** 105 * End the active Session and verify that it is completed and removed from mSessionMapper. 106 */ 107 @SmallTest 108 public void testEndSession() { 109 assertTrue(mTestSessionManager.mSessionMapper.isEmpty()); 110 // Set the thread Id to 0 111 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 112 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 113 Session testSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 114 115 assertEquals(1, mTestSessionManager.mSessionMapper.size()); 116 try { 117 // Make sure execution time is > 0 118 Thread.sleep(1); 119 } catch (InterruptedException ignored) {} 120 mTestSessionManager.endSession(); 121 122 assertTrue(testSession.isSessionCompleted()); 123 assertTrue(testSession.getLocalExecutionTime() > 0); 124 assertTrue(mTestSessionManager.mSessionMapper.isEmpty()); 125 } 126 127 /** 128 * Ends an active invisible child session and verifies that the parent session is moved back 129 * into mSessionMapper. 130 */ 131 @SmallTest 132 public void testEndInvisibleChildSession() { 133 assertTrue(mTestSessionManager.mSessionMapper.isEmpty()); 134 // Set the thread Id to 0 for the parent 135 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 136 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 137 // Create invisible child session - same Thread ID as parent 138 mTestSessionManager.startSession(TEST_CHILD_NAME, null); 139 Session testChildSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 140 141 mTestSessionManager.endSession(); 142 143 // There should only be one session in the mapper (the parent) 144 assertEquals(1, mTestSessionManager.mSessionMapper.size()); 145 Session testParentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 146 assertEquals(TEST_PARENT_NAME, testParentSession.getShortMethodName()); 147 assertFalse(testParentSession.isStartedFromActiveSession()); 148 assertTrue(testChildSession.isSessionCompleted()); 149 assertFalse(testParentSession.isSessionCompleted()); 150 } 151 152 /** 153 * Creates a subsession (child Session) of the current session and prepares it to be continued 154 * in a different thread. 155 */ 156 @SmallTest 157 public void testCreateSubsession() { 158 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 159 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 160 161 Session testSession = mTestSessionManager.createSubsession(); 162 163 assertEquals(1, mTestSessionManager.mSessionMapper.size()); 164 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 165 assertNotNull(testSession.getParentSession()); 166 assertEquals(TEST_PARENT_NAME, testSession.getParentSession().getShortMethodName()); 167 assertEquals(TEST_PARENT_NAME, parentSession.getShortMethodName()); 168 assertTrue(parentSession.getChildSessions().contains(testSession)); 169 assertFalse(testSession.isSessionCompleted()); 170 assertFalse(testSession.isStartedFromActiveSession()); 171 assertTrue(testSession.getChildSessions().isEmpty()); 172 } 173 174 /** 175 * Cancels a subsession that was started before it was continued and verifies that it is 176 * marked as completed and never added to mSessionMapper. 177 */ 178 @SmallTest 179 public void testCancelSubsession() { 180 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 181 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 182 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 183 Session testSession = mTestSessionManager.createSubsession(); 184 185 mTestSessionManager.cancelSubsession(testSession); 186 187 assertTrue(testSession.isSessionCompleted()); 188 assertFalse(parentSession.isSessionCompleted()); 189 assertEquals(Session.UNDEFINED, testSession.getLocalExecutionTime()); 190 assertNull(testSession.getParentSession()); 191 } 192 193 194 /** 195 * Continues a subsession in a different thread and verifies that both the new subsession and 196 * its parent are in mSessionMapper. 197 */ 198 @SmallTest 199 public void testContinueSubsession() { 200 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 201 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 202 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 203 Session testSession = mTestSessionManager.createSubsession(); 204 205 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 206 mTestSessionManager.continueSession(testSession, TEST_CHILD_NAME); 207 208 assertEquals(2, mTestSessionManager.mSessionMapper.size()); 209 assertEquals(testSession, mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID)); 210 assertEquals(parentSession, testSession.getParentSession()); 211 assertFalse(parentSession.isStartedFromActiveSession()); 212 assertFalse(parentSession.isSessionCompleted()); 213 assertFalse(testSession.isSessionCompleted()); 214 assertFalse(testSession.isStartedFromActiveSession()); 215 } 216 217 /** 218 * Ends a subsession that exists in a different thread and verifies that it is completed and 219 * no longer exists in mSessionMapper. 220 */ 221 @SmallTest 222 public void testEndSubsession() { 223 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 224 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 225 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 226 Session testSession = mTestSessionManager.createSubsession(); 227 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 228 mTestSessionManager.continueSession(testSession, TEST_CHILD_NAME); 229 230 mTestSessionManager.endSession(); 231 232 assertTrue(testSession.isSessionCompleted()); 233 assertNull(mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID)); 234 assertFalse(parentSession.isSessionCompleted()); 235 assertEquals(parentSession, mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID)); 236 } 237 238 /** 239 * When there are subsessions in multiple threads, the parent session may end before the 240 * subsessions themselves. When the subsession ends, we need to recursively clean up the parent 241 * sessions that are complete as well and note the completion time of the entire chain. 242 */ 243 @SmallTest 244 public void testEndSubsessionWithParentComplete() { 245 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 246 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 247 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID); 248 Session childSession = mTestSessionManager.createSubsession(); 249 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 250 mTestSessionManager.continueSession(childSession, TEST_CHILD_NAME); 251 // Switch to the parent session ID and end the session. 252 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 253 mTestSessionManager.endSession(); 254 assertTrue(parentSession.isSessionCompleted()); 255 assertFalse(childSession.isSessionCompleted()); 256 257 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 258 try { 259 Thread.sleep(TEST_DELAY_TIME); 260 } catch (InterruptedException ignored) {} 261 mTestSessionManager.endSession(); 262 263 assertEquals(0, mTestSessionManager.mSessionMapper.size()); 264 assertTrue(parentSession.getChildSessions().isEmpty()); 265 assertNull(childSession.getParentSession()); 266 assertTrue(childSession.isSessionCompleted()); 267 assertEquals(TEST_PARENT_NAME, mFullSessionMethodName); 268 // Reduce flakiness by assuming that the true completion time is within a threshold of 269 // +-10 ms 270 assertTrue(mfullSessionCompleteTime >= TEST_DELAY_TIME - 10); 271 assertTrue(mfullSessionCompleteTime <= TEST_DELAY_TIME + 10); 272 } 273 274 /** 275 * Tests that starting an external session packages up the parent session information and 276 * correctly generates the child session. 277 */ 278 @SmallTest 279 public void testStartExternalSession() { 280 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 281 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 282 Session.Info sessionInfo = 283 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID).getInfo(); 284 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 285 286 mTestSessionManager.startExternalSession(sessionInfo, TEST_CHILD_NAME); 287 288 Session externalSession = mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID); 289 assertNotNull(externalSession); 290 assertFalse(externalSession.isSessionCompleted()); 291 assertEquals(TEST_CHILD_NAME, externalSession.getShortMethodName()); 292 // First subsession of the parent external Session, so the session will be _0. 293 assertEquals("0", externalSession.getSessionId()); 294 } 295 296 /** 297 * Verifies that ending an external session tears down the session correctly and removes the 298 * external session from mSessionMapper. 299 */ 300 @SmallTest 301 public void testEndExternalSession() { 302 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 303 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 304 Session.Info sessionInfo = 305 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID).getInfo(); 306 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 307 mTestSessionManager.startExternalSession(sessionInfo, TEST_CHILD_NAME); 308 Session externalSession = mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID); 309 310 try { 311 // Make sure execution time is > 0 312 Thread.sleep(1); 313 } catch (InterruptedException ignored) {} 314 mTestSessionManager.endSession(); 315 316 assertTrue(externalSession.isSessionCompleted()); 317 assertTrue(externalSession.getLocalExecutionTime() > 0); 318 assertNull(mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID)); 319 } 320 321 /** 322 * Verifies that the callback to inform that the top level parent Session has completed is not 323 * the external Session, but the one subsession underneath. 324 */ 325 @SmallTest 326 public void testEndExternalSessionListenerCallback() { 327 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 328 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 329 Session.Info sessionInfo = 330 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID).getInfo(); 331 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 332 mTestSessionManager.startExternalSession(sessionInfo, TEST_CHILD_NAME); 333 334 try { 335 // Make sure execution time is recorded correctly 336 Thread.sleep(TEST_DELAY_TIME); 337 } catch (InterruptedException ignored) {} 338 mTestSessionManager.endSession(); 339 340 assertEquals(TEST_CHILD_NAME, mFullSessionMethodName); 341 assertTrue(mfullSessionCompleteTime >= TEST_DELAY_TIME - 10); 342 assertTrue(mfullSessionCompleteTime <= TEST_DELAY_TIME + 10); 343 } 344 345 /** 346 * Verifies that the recursive method for getting the full ID works correctly. 347 */ 348 @SmallTest 349 public void testFullMethodPath() { 350 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 351 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 352 Session testSession = mTestSessionManager.createSubsession(); 353 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID; 354 mTestSessionManager.continueSession(testSession, TEST_CHILD_NAME); 355 356 String fullId = mTestSessionManager.getSessionId(); 357 358 assertTrue(fullId.contains(TEST_PARENT_NAME + Session.SUBSESSION_SEPARATION_CHAR 359 + TEST_CHILD_NAME)); 360 } 361 362 /** 363 * Make sure that the cleanup timer runs correctly and the GC collects the stale sessions 364 * correctly to ensure that there are no dangling sessions. 365 */ 366 @SmallTest 367 public void testStaleSessionCleanupTimer() { 368 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID; 369 mTestSessionManager.startSession(TEST_PARENT_NAME, null); 370 WeakReference<Session> sessionRef = new WeakReference<>( 371 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID)); 372 try { 373 // Make sure that the sleep time is always > delay time. 374 Thread.sleep(2 * TEST_DELAY_TIME); 375 mTestSessionManager.cleanupStaleSessions(TEST_DELAY_TIME); 376 Runtime.getRuntime().gc(); 377 // Give it a second for GC to run. 378 Thread.sleep(1000); 379 } catch (InterruptedException ignored) {} 380 381 assertTrue(mTestSessionManager.mSessionMapper.isEmpty()); 382 assertNull(sessionRef.get()); 383 } 384} 385