blob: 85a9bffb72afa5a6be725771e0d5ae64ff3bfb48 [file] [log] [blame]
Brad Ebinger0d2c1e62016-10-13 15:21:11 -07001/*
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
Hall Liuc8a396b2017-12-27 18:23:28 -080019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNotNull;
22import static org.junit.Assert.assertNull;
23import static org.junit.Assert.assertTrue;
24
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070025import android.telecom.Logging.Session;
26import android.telecom.Logging.SessionManager;
27import android.test.suitebuilder.annotation.SmallTest;
28
Hall Liuc8a396b2017-12-27 18:23:28 -080029import org.junit.After;
30import org.junit.Before;
31import org.junit.Test;
32import org.junit.runner.RunWith;
33import org.junit.runners.JUnit4;
34
Brad Ebingerba049ae2016-10-21 15:44:32 -070035import java.lang.ref.WeakReference;
36
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070037/**
38 * Unit tests for android.telecom.Logging.SessionManager
39 */
40
Hall Liuc8a396b2017-12-27 18:23:28 -080041@RunWith(JUnit4.class)
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070042public class SessionManagerTest extends TelecomTestCase {
43
44 private static final String TEST_PARENT_NAME = "testParent";
45 private static final int TEST_PARENT_THREAD_ID = 0;
46 private static final String TEST_CHILD_NAME = "testChild";
47 private static final int TEST_CHILD_THREAD_ID = 1;
Brad Ebingerba049ae2016-10-21 15:44:32 -070048 private static final int TEST_DELAY_TIME = 100; // ms
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070049
50 private SessionManager mTestSessionManager;
51 // Used to verify sessionComplete callback
52 private long mfullSessionCompleteTime = Session.UNDEFINED;
53 private String mFullSessionMethodName = "";
54
55 @Override
Hall Liuc8a396b2017-12-27 18:23:28 -080056 @Before
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070057 public void setUp() throws Exception {
58 super.setUp();
59 mTestSessionManager = new SessionManager();
60 mTestSessionManager.registerSessionListener(((sessionName, timeMs) -> {
61 mfullSessionCompleteTime = timeMs;
62 mFullSessionMethodName = sessionName;
63 }));
64 // Remove automatic stale session cleanup for testing
65 mTestSessionManager.mCleanStaleSessions = null;
66 }
67
68 @Override
Hall Liuc8a396b2017-12-27 18:23:28 -080069 @After
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070070 public void tearDown() throws Exception {
71 mFullSessionMethodName = "";
72 mfullSessionCompleteTime = Session.UNDEFINED;
73 mTestSessionManager = null;
74 super.tearDown();
75 }
76
77 /**
78 * Starts a Session on the current thread and verifies that it exists in the HashMap
79 */
80 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -080081 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -070082 public void testStartSession() {
83 assertTrue(mTestSessionManager.mSessionMapper.isEmpty());
84
85 // Set the thread Id to 0
86 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
87 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
88
89 Session testSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
90 assertEquals(TEST_PARENT_NAME, testSession.getShortMethodName());
91 assertFalse(testSession.isSessionCompleted());
92 assertFalse(testSession.isStartedFromActiveSession());
93 }
94
95 /**
96 * Starts two sessions in the same thread. The first session will be parented to the second
97 * session and the second session will be attached to that thread ID.
98 */
99 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800100 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700101 public void testStartInvisibleChildSession() {
102 assertTrue(mTestSessionManager.mSessionMapper.isEmpty());
103
104 // Set the thread Id to 0 for the parent
105 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
106 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
107 // Create invisible child session - same Thread ID as parent
108 mTestSessionManager.startSession(TEST_CHILD_NAME, null);
109
110 // There should only be one session in the mapper (the child)
111 assertEquals(1, mTestSessionManager.mSessionMapper.size());
112 Session testChildSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
Brad Ebingerba049ae2016-10-21 15:44:32 -0700113 assertEquals( TEST_CHILD_NAME, testChildSession.getShortMethodName());
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700114 assertTrue(testChildSession.isStartedFromActiveSession());
115 assertNotNull(testChildSession.getParentSession());
116 assertEquals(TEST_PARENT_NAME, testChildSession.getParentSession().getShortMethodName());
117 assertFalse(testChildSession.isSessionCompleted());
118 assertFalse(testChildSession.getParentSession().isSessionCompleted());
119 }
120
121 /**
122 * End the active Session and verify that it is completed and removed from mSessionMapper.
123 */
124 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800125 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700126 public void testEndSession() {
127 assertTrue(mTestSessionManager.mSessionMapper.isEmpty());
128 // Set the thread Id to 0
129 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
130 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
131 Session testSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
132
133 assertEquals(1, mTestSessionManager.mSessionMapper.size());
134 try {
135 // Make sure execution time is > 0
136 Thread.sleep(1);
137 } catch (InterruptedException ignored) {}
138 mTestSessionManager.endSession();
139
140 assertTrue(testSession.isSessionCompleted());
141 assertTrue(testSession.getLocalExecutionTime() > 0);
142 assertTrue(mTestSessionManager.mSessionMapper.isEmpty());
143 }
144
145 /**
146 * Ends an active invisible child session and verifies that the parent session is moved back
147 * into mSessionMapper.
148 */
149 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800150 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700151 public void testEndInvisibleChildSession() {
152 assertTrue(mTestSessionManager.mSessionMapper.isEmpty());
153 // Set the thread Id to 0 for the parent
154 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
155 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
156 // Create invisible child session - same Thread ID as parent
157 mTestSessionManager.startSession(TEST_CHILD_NAME, null);
158 Session testChildSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
159
160 mTestSessionManager.endSession();
161
162 // There should only be one session in the mapper (the parent)
163 assertEquals(1, mTestSessionManager.mSessionMapper.size());
164 Session testParentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
165 assertEquals(TEST_PARENT_NAME, testParentSession.getShortMethodName());
166 assertFalse(testParentSession.isStartedFromActiveSession());
167 assertTrue(testChildSession.isSessionCompleted());
168 assertFalse(testParentSession.isSessionCompleted());
169 }
170
171 /**
172 * Creates a subsession (child Session) of the current session and prepares it to be continued
173 * in a different thread.
174 */
175 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800176 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700177 public void testCreateSubsession() {
178 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
179 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
180
181 Session testSession = mTestSessionManager.createSubsession();
182
183 assertEquals(1, mTestSessionManager.mSessionMapper.size());
184 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
185 assertNotNull(testSession.getParentSession());
186 assertEquals(TEST_PARENT_NAME, testSession.getParentSession().getShortMethodName());
187 assertEquals(TEST_PARENT_NAME, parentSession.getShortMethodName());
188 assertTrue(parentSession.getChildSessions().contains(testSession));
189 assertFalse(testSession.isSessionCompleted());
190 assertFalse(testSession.isStartedFromActiveSession());
191 assertTrue(testSession.getChildSessions().isEmpty());
192 }
193
194 /**
195 * Cancels a subsession that was started before it was continued and verifies that it is
196 * marked as completed and never added to mSessionMapper.
197 */
198 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800199 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700200 public void testCancelSubsession() {
201 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
202 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
203 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
204 Session testSession = mTestSessionManager.createSubsession();
205
206 mTestSessionManager.cancelSubsession(testSession);
207
208 assertTrue(testSession.isSessionCompleted());
209 assertFalse(parentSession.isSessionCompleted());
210 assertEquals(Session.UNDEFINED, testSession.getLocalExecutionTime());
211 assertNull(testSession.getParentSession());
212 }
213
214
215 /**
216 * Continues a subsession in a different thread and verifies that both the new subsession and
217 * its parent are in mSessionMapper.
218 */
219 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800220 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700221 public void testContinueSubsession() {
222 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
223 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
224 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
225 Session testSession = mTestSessionManager.createSubsession();
226
227 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
228 mTestSessionManager.continueSession(testSession, TEST_CHILD_NAME);
229
230 assertEquals(2, mTestSessionManager.mSessionMapper.size());
231 assertEquals(testSession, mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID));
232 assertEquals(parentSession, testSession.getParentSession());
233 assertFalse(parentSession.isStartedFromActiveSession());
234 assertFalse(parentSession.isSessionCompleted());
235 assertFalse(testSession.isSessionCompleted());
236 assertFalse(testSession.isStartedFromActiveSession());
237 }
238
239 /**
240 * Ends a subsession that exists in a different thread and verifies that it is completed and
241 * no longer exists in mSessionMapper.
242 */
243 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800244 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700245 public void testEndSubsession() {
246 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
247 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
248 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
249 Session testSession = mTestSessionManager.createSubsession();
250 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
251 mTestSessionManager.continueSession(testSession, TEST_CHILD_NAME);
252
253 mTestSessionManager.endSession();
254
255 assertTrue(testSession.isSessionCompleted());
256 assertNull(mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID));
257 assertFalse(parentSession.isSessionCompleted());
258 assertEquals(parentSession, mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID));
259 }
260
261 /**
262 * When there are subsessions in multiple threads, the parent session may end before the
263 * subsessions themselves. When the subsession ends, we need to recursively clean up the parent
264 * sessions that are complete as well and note the completion time of the entire chain.
265 */
266 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800267 @Test
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700268 public void testEndSubsessionWithParentComplete() {
269 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
270 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
271 Session parentSession = mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID);
272 Session childSession = mTestSessionManager.createSubsession();
273 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
274 mTestSessionManager.continueSession(childSession, TEST_CHILD_NAME);
275 // Switch to the parent session ID and end the session.
276 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
277 mTestSessionManager.endSession();
278 assertTrue(parentSession.isSessionCompleted());
279 assertFalse(childSession.isSessionCompleted());
280
281 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
282 try {
283 Thread.sleep(TEST_DELAY_TIME);
284 } catch (InterruptedException ignored) {}
285 mTestSessionManager.endSession();
286
287 assertEquals(0, mTestSessionManager.mSessionMapper.size());
288 assertTrue(parentSession.getChildSessions().isEmpty());
289 assertNull(childSession.getParentSession());
290 assertTrue(childSession.isSessionCompleted());
291 assertEquals(TEST_PARENT_NAME, mFullSessionMethodName);
292 // Reduce flakiness by assuming that the true completion time is within a threshold of
293 // +-10 ms
294 assertTrue(mfullSessionCompleteTime >= TEST_DELAY_TIME - 10);
295 assertTrue(mfullSessionCompleteTime <= TEST_DELAY_TIME + 10);
296 }
Brad Ebingerba049ae2016-10-21 15:44:32 -0700297
298 /**
299 * Tests that starting an external session packages up the parent session information and
300 * correctly generates the child session.
301 */
302 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800303 @Test
Brad Ebingerba049ae2016-10-21 15:44:32 -0700304 public void testStartExternalSession() {
305 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
306 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
307 Session.Info sessionInfo =
308 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID).getInfo();
309 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
310
311 mTestSessionManager.startExternalSession(sessionInfo, TEST_CHILD_NAME);
312
313 Session externalSession = mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID);
314 assertNotNull(externalSession);
315 assertFalse(externalSession.isSessionCompleted());
316 assertEquals(TEST_CHILD_NAME, externalSession.getShortMethodName());
317 // First subsession of the parent external Session, so the session will be _0.
318 assertEquals("0", externalSession.getSessionId());
319 }
320
321 /**
322 * Verifies that ending an external session tears down the session correctly and removes the
323 * external session from mSessionMapper.
324 */
325 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800326 @Test
Brad Ebingerba049ae2016-10-21 15:44:32 -0700327 public void testEndExternalSession() {
328 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
329 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
330 Session.Info sessionInfo =
331 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID).getInfo();
332 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
333 mTestSessionManager.startExternalSession(sessionInfo, TEST_CHILD_NAME);
334 Session externalSession = mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID);
335
336 try {
337 // Make sure execution time is > 0
338 Thread.sleep(1);
339 } catch (InterruptedException ignored) {}
340 mTestSessionManager.endSession();
341
342 assertTrue(externalSession.isSessionCompleted());
343 assertTrue(externalSession.getLocalExecutionTime() > 0);
344 assertNull(mTestSessionManager.mSessionMapper.get(TEST_CHILD_THREAD_ID));
345 }
346
347 /**
348 * Verifies that the callback to inform that the top level parent Session has completed is not
349 * the external Session, but the one subsession underneath.
350 */
351 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800352 @Test
Brad Ebingerba049ae2016-10-21 15:44:32 -0700353 public void testEndExternalSessionListenerCallback() {
354 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
355 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
356 Session.Info sessionInfo =
357 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID).getInfo();
358 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
359 mTestSessionManager.startExternalSession(sessionInfo, TEST_CHILD_NAME);
360
361 try {
362 // Make sure execution time is recorded correctly
363 Thread.sleep(TEST_DELAY_TIME);
364 } catch (InterruptedException ignored) {}
365 mTestSessionManager.endSession();
366
367 assertEquals(TEST_CHILD_NAME, mFullSessionMethodName);
368 assertTrue(mfullSessionCompleteTime >= TEST_DELAY_TIME - 10);
369 assertTrue(mfullSessionCompleteTime <= TEST_DELAY_TIME + 10);
370 }
371
372 /**
373 * Verifies that the recursive method for getting the full ID works correctly.
374 */
375 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800376 @Test
Brad Ebingerba049ae2016-10-21 15:44:32 -0700377 public void testFullMethodPath() {
378 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
379 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
380 Session testSession = mTestSessionManager.createSubsession();
381 mTestSessionManager.mCurrentThreadId = () -> TEST_CHILD_THREAD_ID;
382 mTestSessionManager.continueSession(testSession, TEST_CHILD_NAME);
383
384 String fullId = mTestSessionManager.getSessionId();
385
386 assertTrue(fullId.contains(TEST_PARENT_NAME + Session.SUBSESSION_SEPARATION_CHAR
387 + TEST_CHILD_NAME));
388 }
389
390 /**
391 * Make sure that the cleanup timer runs correctly and the GC collects the stale sessions
392 * correctly to ensure that there are no dangling sessions.
393 */
394 @SmallTest
Hall Liuc8a396b2017-12-27 18:23:28 -0800395 @Test
Brad Ebingerba049ae2016-10-21 15:44:32 -0700396 public void testStaleSessionCleanupTimer() {
397 mTestSessionManager.mCurrentThreadId = () -> TEST_PARENT_THREAD_ID;
398 mTestSessionManager.startSession(TEST_PARENT_NAME, null);
399 WeakReference<Session> sessionRef = new WeakReference<>(
400 mTestSessionManager.mSessionMapper.get(TEST_PARENT_THREAD_ID));
401 try {
402 // Make sure that the sleep time is always > delay time.
403 Thread.sleep(2 * TEST_DELAY_TIME);
404 mTestSessionManager.cleanupStaleSessions(TEST_DELAY_TIME);
405 Runtime.getRuntime().gc();
406 // Give it a second for GC to run.
407 Thread.sleep(1000);
408 } catch (InterruptedException ignored) {}
409
410 assertTrue(mTestSessionManager.mSessionMapper.isEmpty());
411 assertNull(sessionRef.get());
412 }
Brad Ebinger0d2c1e62016-10-13 15:21:11 -0700413}