blob: cb38846a0514ecfe614145d2bec9a6fda56e2007 [file] [log] [blame]
Ned Burns51aa7432020-05-18 19:40:13 -04001/*
2 * Copyright (C) 2020 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.systemui.dump
18
19import androidx.test.filters.SmallTest
20import com.android.systemui.SysuiTestCase
21import com.android.systemui.util.io.FakeBasicFileAttributes
22import com.android.systemui.util.io.Files
23import com.android.systemui.util.mockito.any
24import com.android.systemui.util.mockito.eq
25import com.android.systemui.util.time.FakeSystemClock
26import org.junit.Assert.assertEquals
27import org.junit.Assert.assertTrue
28import org.junit.Before
29import org.junit.Test
30import org.mockito.Mock
31import org.mockito.Mockito
32import org.mockito.Mockito.never
33import org.mockito.Mockito.verify
34import org.mockito.MockitoAnnotations
35import java.io.BufferedWriter
36import java.io.ByteArrayOutputStream
37import java.io.IOException
38import java.io.OutputStreamWriter
39import java.io.PrintWriter
40import java.nio.file.LinkOption
41import java.nio.file.OpenOption
42import java.nio.file.Paths
43import java.nio.file.attribute.BasicFileAttributes
44import java.util.Arrays
45
46@SmallTest
47class LogEulogizerTest : SysuiTestCase() {
48
49 lateinit var eulogizer: LogBufferEulogizer
50
51 @Mock
52 lateinit var dumpManager: DumpManager
53
54 @Mock
55 lateinit var files: Files
56
57 private val clock = FakeSystemClock()
58
59 private val path = Paths.get("/foo/bar/baz.txt")
60 private val fileAttrs = FakeBasicFileAttributes()
61 private val fileStream = ByteArrayOutputStream()
62 private val fileWriter = BufferedWriter(OutputStreamWriter(fileStream))
63
64 private val dumpStream = ByteArrayOutputStream()
65 private val dumpWriter = PrintWriter(OutputStreamWriter(dumpStream))
66
67 @Before
68 fun setUp() {
69 MockitoAnnotations.initMocks(this)
70
71 eulogizer =
72 LogBufferEulogizer(dumpManager, clock, files, path, MIN_WRITE_GAP, MAX_READ_AGE)
73
74 Mockito.`when`(files.newBufferedWriter(eq(path), any(OpenOption::class.java)))
75 .thenReturn(fileWriter)
76
77 Mockito.`when`(
78 files.readAttributes(eq(path),
79 eq(BasicFileAttributes::class.java),
80 any(LinkOption::class.java))
81 ).thenReturn(fileAttrs)
82
83 Mockito.`when`(files.lines(eq(path))).thenReturn(Arrays.stream(FAKE_LINES))
84 }
85
86 @Test
87 fun testFileIsCreated() {
88 // GIVEN that the log file doesn't already exist
89 Mockito.`when`(
90 files.readAttributes(eq(path),
91 eq(BasicFileAttributes::class.java),
92 any(LinkOption::class.java))
93 ).thenThrow(IOException("File not found"))
94
95 // WHEN .record() is called
96 val exception = RuntimeException("Something bad happened")
97 assertEquals(exception, eulogizer.record(exception))
98
99 // THEN the buffers are dumped to the file
100 verify(dumpManager).dumpBuffers(any(PrintWriter::class.java), Mockito.anyInt())
101 assertTrue(fileStream.toString().isNotEmpty())
102 }
103
104 @Test
105 fun testExistingFileIsOverwritten() {
106 // GIVEN that the log file already exists but hasn't been modified in a while
107 fileAttrs.setLastModifiedTime(clock.currentTimeMillis() - MIN_WRITE_GAP - 20)
108
109 // WHEN .record() is called
110 val exception = RuntimeException("Something bad happened")
111 assertEquals(exception, eulogizer.record(exception))
112
113 // THEN the buffers are dumped to the file
114 verify(dumpManager).dumpBuffers(any(PrintWriter::class.java), Mockito.anyInt())
115 assertTrue(fileStream.toString().isNotEmpty())
116 }
117
118 @Test
119 fun testYoungFileIsNotOverwritten() {
120 // GIVEN that the log file has been modified recently
121 fileAttrs.setLastModifiedTime(clock.currentTimeMillis() - MIN_WRITE_GAP + 7)
122
123 // WHEN .record() is called
124 val exception = RuntimeException("Something bad happened")
125 assertEquals(exception, eulogizer.record(exception))
126
127 // THEN the file isn't written to
128 verify(dumpManager, never()).dumpBuffers(any(PrintWriter::class.java), Mockito.anyInt())
129 assertTrue(fileStream.toString().isEmpty())
130 }
131
132 @Test
133 fun testRecentFileIsDumped() {
134 // GIVEN that the log file was written to "recently"
135 fileAttrs.setLastModifiedTime(clock.currentTimeMillis() - MAX_READ_AGE + 7)
136
137 // WHEN we're asked to eulogize the log
138 eulogizer.readEulogyIfPresent(dumpWriter)
139 dumpWriter.close()
140
141 // THEN the log file is written to the output stream
142 verify(files).lines(eq(path))
143 assertTrue(dumpStream.toString().isNotBlank())
144 }
145
146 @Test
147 fun testOldFileIsNotDumped() {
148 // GIVEN that the log file was written to a long time ago
149 fileAttrs.setLastModifiedTime(clock.currentTimeMillis() - MAX_READ_AGE - 7)
150
151 // WHEN we're asked to eulogize the log
152 eulogizer.readEulogyIfPresent(dumpWriter)
153 dumpWriter.close()
154
155 // THEN the log file is NOT written to the output stream
156 verify(files, never()).lines(eq(path))
157 assertTrue(dumpStream.toString().isEmpty())
158 }
159}
160
161private const val MIN_WRITE_GAP = 10L
162private const val MAX_READ_AGE = 100L
163
164private val FAKE_LINES =
165 arrayOf(
166 "First line",
167 "Second line",
168 "Third line"
169 )