1 /* 2 * Copyright (C) 2017 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 17 package com.android.net.module.util; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 24 import androidx.test.filters.SmallTest; 25 import androidx.test.runner.AndroidJUnit4; 26 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 30 import java.io.ByteArrayOutputStream; 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.function.Consumer; 37 38 @RunWith(AndroidJUnit4.class) 39 @SmallTest 40 public class SharedLogTest { 41 private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}"; 42 private static final String TIMESTAMP = "HH:MM:SS"; 43 private static final String TAG = "top"; 44 45 @Test testBasicOperation()46 public void testBasicOperation() { 47 final SharedLog logTop = new SharedLog(TAG); 48 assertTrue(TAG.equals(logTop.getTag())); 49 50 logTop.mark("first post!"); 51 52 final SharedLog logLevel2a = logTop.forSubComponent("twoA"); 53 final SharedLog logLevel2b = logTop.forSubComponent("twoB"); 54 logLevel2b.e("2b or not 2b"); 55 logLevel2b.e("No exception", null); 56 logLevel2b.e("Wait, here's one", new Exception("Test")); 57 logLevel2a.w("second post?"); 58 59 final SharedLog logLevel3 = logLevel2a.forSubComponent("three"); 60 logTop.log("still logging"); 61 logLevel2b.e(new Exception("Got another exception")); 62 logLevel3.i("3 >> 2"); 63 logLevel2a.mark("ok: last post"); 64 logTop.logf("finished!"); 65 66 final String[] expected = { 67 " - MARK first post!", 68 " - [twoB] ERROR 2b or not 2b", 69 " - [twoB] ERROR No exception", 70 // No stacktrace in shared log, only in logcat 71 " - [twoB] ERROR Wait, here's one: Test", 72 " - [twoA] WARN second post?", 73 " - still logging", 74 " - [twoB] ERROR java.lang.Exception: Got another exception", 75 " - [twoA.three] 3 >> 2", 76 " - [twoA] MARK ok: last post", 77 " - finished!", 78 }; 79 // Verify the logs are all there and in the correct order. 80 assertDumpLogs(expected, logTop); 81 82 // In fact, because they all share the same underlying LocalLog, 83 // every subcomponent SharedLog's dump() is identical. 84 assertDumpLogs(expected, logLevel2a); 85 assertDumpLogs(expected, logLevel2b); 86 assertDumpLogs(expected, logLevel3); 87 } 88 assertDumpLogs(String[] expected, SharedLog log)89 private static void assertDumpLogs(String[] expected, SharedLog log) { 90 verifyLogLines(expected, dump(log)); 91 verifyLogLines(reverse(expected), reverseDump(log)); 92 } 93 dump(SharedLog log)94 private static String dump(SharedLog log) { 95 return getSharedLogString(pw -> log.dump(null /* fd */, pw, null /* args */)); 96 } 97 reverseDump(SharedLog log)98 private static String reverseDump(SharedLog log) { 99 return getSharedLogString(pw -> log.reverseDump(pw)); 100 } 101 reverse(String[] ary)102 private static String[] reverse(String[] ary) { 103 final List<String> ls = new ArrayList<>(Arrays.asList(ary)); 104 Collections.reverse(ls); 105 return ls.toArray(new String[ary.length]); 106 } 107 getSharedLogString(Consumer<PrintWriter> functor)108 private static String getSharedLogString(Consumer<PrintWriter> functor) { 109 final ByteArrayOutputStream ostream = new ByteArrayOutputStream(); 110 final PrintWriter pw = new PrintWriter(ostream, true); 111 functor.accept(pw); 112 113 final String dumpOutput = ostream.toString(); 114 assertNotNull(dumpOutput); 115 assertFalse("".equals(dumpOutput)); 116 return dumpOutput; 117 } 118 verifyLogLines(String[] expected, String gottenLogs)119 private static void verifyLogLines(String[] expected, String gottenLogs) { 120 final String[] lines = gottenLogs.split("\n"); 121 assertEquals(expected.length, lines.length); 122 123 for (int i = 0; i < expected.length; i++) { 124 String got = lines[i]; 125 String want = expected[i]; 126 assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want)); 127 assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP), 128 got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP)); 129 } 130 } 131 } 132