blob: 9ad6986f2f90e138afd8f76566f53465cd17ed84 [file] [log] [blame]
Julia Reynoldse261db32019-10-21 11:37:35 -04001/*
2 * Copyright (C) 2019 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 */
16package com.android.server.notification;
17
18import static com.google.common.truth.Truth.assertThat;
19
20import static org.mockito.ArgumentMatchers.any;
Julia Reynolds96951fc2019-11-13 16:04:33 -050021import static org.mockito.ArgumentMatchers.anyInt;
Julia Reynoldse261db32019-10-21 11:37:35 -040022import static org.mockito.ArgumentMatchers.anyLong;
23import static org.mockito.Mockito.mock;
24import static org.mockito.Mockito.never;
25import static org.mockito.Mockito.times;
26import static org.mockito.Mockito.verify;
27import static org.mockito.Mockito.when;
28
Julia Reynolds96951fc2019-11-13 16:04:33 -050029import android.app.AlarmManager;
Julia Reynoldsb317ff72019-11-26 14:20:51 -050030import android.app.NotificationHistory;
Julia Reynoldse261db32019-10-21 11:37:35 -040031import android.app.NotificationHistory.HistoricalNotification;
Julia Reynolds96951fc2019-11-13 16:04:33 -050032import android.content.Context;
Julia Reynoldse261db32019-10-21 11:37:35 -040033import android.graphics.drawable.Icon;
34import android.os.Handler;
35import android.util.AtomicFile;
36
37import androidx.test.InstrumentationRegistry;
38import androidx.test.runner.AndroidJUnit4;
39
40import com.android.server.UiServiceTestCase;
41
42import org.junit.Before;
43import org.junit.Test;
44import org.junit.runner.RunWith;
45import org.mockito.Mock;
46import org.mockito.MockitoAnnotations;
47
48import java.io.File;
Julia Reynolds96951fc2019-11-13 16:04:33 -050049import java.util.ArrayList;
Julia Reynoldse261db32019-10-21 11:37:35 -040050import java.util.Calendar;
51import java.util.GregorianCalendar;
Julia Reynolds96951fc2019-11-13 16:04:33 -050052import java.util.HashMap;
53import java.util.List;
54import java.util.Map;
Julia Reynoldse261db32019-10-21 11:37:35 -040055
56@RunWith(AndroidJUnit4.class)
57public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
58
59 File mRootDir;
60 @Mock
61 Handler mFileWriteHandler;
Julia Reynolds96951fc2019-11-13 16:04:33 -050062 @Mock
63 Context mContext;
64 @Mock
65 AlarmManager mAlarmManager;
66 TestFileAttrProvider mFileAttrProvider;
Julia Reynoldse261db32019-10-21 11:37:35 -040067
68 NotificationHistoryDatabase mDataBase;
69
70 private HistoricalNotification getHistoricalNotification(int index) {
71 return getHistoricalNotification("package" + index, index);
72 }
73
74 private HistoricalNotification getHistoricalNotification(String packageName, int index) {
75 String expectedChannelName = "channelName" + index;
76 String expectedChannelId = "channelId" + index;
77 int expectedUid = 1123456 + index;
78 int expectedUserId = 11 + index;
79 long expectedPostTime = 987654321 + index;
80 String expectedTitle = "title" + index;
81 String expectedText = "text" + index;
82 Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
83 index);
84
85 return new HistoricalNotification.Builder()
86 .setPackage(packageName)
87 .setChannelName(expectedChannelName)
88 .setChannelId(expectedChannelId)
89 .setUid(expectedUid)
90 .setUserId(expectedUserId)
91 .setPostedTimeMs(expectedPostTime)
92 .setTitle(expectedTitle)
93 .setText(expectedText)
94 .setIcon(expectedIcon)
95 .build();
96 }
97
98 @Before
99 public void setUp() {
100 MockitoAnnotations.initMocks(this);
Julia Reynolds96951fc2019-11-13 16:04:33 -0500101 when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
102 when(mContext.getUser()).thenReturn(getContext().getUser());
103 when(mContext.getPackageName()).thenReturn(getContext().getPackageName());
Julia Reynoldse261db32019-10-21 11:37:35 -0400104
Julia Reynolds96951fc2019-11-13 16:04:33 -0500105 mFileAttrProvider = new TestFileAttrProvider();
Julia Reynoldse261db32019-10-21 11:37:35 -0400106 mRootDir = new File(mContext.getFilesDir(), "NotificationHistoryDatabaseTest");
107
Julia Reynoldsa614c272019-11-15 16:43:29 -0500108 mDataBase = new NotificationHistoryDatabase(
109 mContext, mFileWriteHandler, mRootDir, mFileAttrProvider);
110 mDataBase.init();
Julia Reynoldse261db32019-10-21 11:37:35 -0400111 }
112
113 @Test
Julia Reynolds96951fc2019-11-13 16:04:33 -0500114 public void testDeletionReceiver() {
115 verify(mContext, times(1)).registerReceiver(any(), any());
116 }
117
118 @Test
119 public void testPrune() throws Exception {
120 GregorianCalendar cal = new GregorianCalendar();
121 cal.setTimeInMillis(10);
Julia Reynoldse261db32019-10-21 11:37:35 -0400122 int retainDays = 1;
Julia Reynolds96951fc2019-11-13 16:04:33 -0500123
124 List<AtomicFile> expectedFiles = new ArrayList<>();
125
126 // add 5 files with a creation date of "today"
127 for (long i = cal.getTimeInMillis(); i >= 5; i--) {
Julia Reynoldse261db32019-10-21 11:37:35 -0400128 File file = mock(File.class);
Julia Reynolds96951fc2019-11-13 16:04:33 -0500129 mFileAttrProvider.creationDates.put(file, i);
Julia Reynoldse261db32019-10-21 11:37:35 -0400130 AtomicFile af = new AtomicFile(file);
Julia Reynolds96951fc2019-11-13 16:04:33 -0500131 expectedFiles.add(af);
Julia Reynoldse261db32019-10-21 11:37:35 -0400132 mDataBase.mHistoryFiles.addLast(af);
133 }
Julia Reynolds96951fc2019-11-13 16:04:33 -0500134
Julia Reynoldse261db32019-10-21 11:37:35 -0400135 cal.add(Calendar.DATE, -1 * retainDays);
Julia Reynolds96951fc2019-11-13 16:04:33 -0500136 // Add 5 more files more than retainDays old
Julia Reynoldse261db32019-10-21 11:37:35 -0400137 for (int i = 5; i >= 0; i--) {
138 File file = mock(File.class);
Julia Reynolds96951fc2019-11-13 16:04:33 -0500139 mFileAttrProvider.creationDates.put(file, cal.getTimeInMillis() - i);
Julia Reynoldse261db32019-10-21 11:37:35 -0400140 AtomicFile af = new AtomicFile(file);
141 mDataBase.mHistoryFiles.addLast(af);
142 }
Julia Reynoldse261db32019-10-21 11:37:35 -0400143
Julia Reynolds96951fc2019-11-13 16:04:33 -0500144 // back to today; trim everything a day + old
145 cal.add(Calendar.DATE, 1 * retainDays);
146 mDataBase.prune(retainDays, cal.getTimeInMillis());
147
148 assertThat(mDataBase.mHistoryFiles).containsExactlyElementsIn(expectedFiles);
149
150 verify(mAlarmManager, times(6)).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
151
Julia Reynoldse261db32019-10-21 11:37:35 -0400152 }
153
154 @Test
155 public void testOnPackageRemove_posts() {
156 mDataBase.onPackageRemoved("test");
157 verify(mFileWriteHandler, times(1)).post(any());
158 }
159
160 @Test
161 public void testForceWriteToDisk() {
162 mDataBase.forceWriteToDisk();
163 verify(mFileWriteHandler, times(1)).post(any());
164 }
165
166 @Test
167 public void testOnlyOneWriteRunnableInQueue() {
168 when(mFileWriteHandler.hasCallbacks(any())).thenReturn(true);
169 mDataBase.forceWriteToDisk();
170 verify(mFileWriteHandler, never()).post(any());
171 }
172
173 @Test
174 public void testAddNotification() {
175 HistoricalNotification n = getHistoricalNotification(1);
176 HistoricalNotification n2 = getHistoricalNotification(2);
177
178 mDataBase.addNotification(n);
179 assertThat(mDataBase.mBuffer.getNotificationsToWrite()).contains(n);
180 verify(mFileWriteHandler, times(1)).postDelayed(any(), anyLong());
181
182 // second add should not trigger another write
183 mDataBase.addNotification(n2);
184 assertThat(mDataBase.mBuffer.getNotificationsToWrite()).contains(n2);
185 verify(mFileWriteHandler, times(1)).postDelayed(any(), anyLong());
186 }
187
188 @Test
189 public void testReadNotificationHistory_readsAllFiles() throws Exception {
190 for (long i = 10; i >= 5; i--) {
191 AtomicFile af = mock(AtomicFile.class);
192 mDataBase.mHistoryFiles.addLast(af);
193 }
194
195 mDataBase.readNotificationHistory();
196
197 for (AtomicFile file : mDataBase.mHistoryFiles) {
198 verify(file, times(1)).openRead();
199 }
200 }
201
202 @Test
Julia Reynoldsb317ff72019-11-26 14:20:51 -0500203 public void testReadNotificationHistory_readsBuffer() throws Exception {
204 HistoricalNotification hn = getHistoricalNotification(1);
205 mDataBase.addNotification(hn);
206
207 NotificationHistory nh = mDataBase.readNotificationHistory();
208
209 assertThat(nh.getNotificationsToWrite()).contains(hn);
210 }
211
212 @Test
Julia Reynoldse261db32019-10-21 11:37:35 -0400213 public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception {
214 AtomicFile af = mock(AtomicFile.class);
215 when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
216 mDataBase.mHistoryFiles.addLast(af);
217
218 AtomicFile af2 = mock(AtomicFile.class);
219 when(af2.getBaseFile()).thenReturn(new File(mRootDir, "af2"));
220 mDataBase.mHistoryFiles.addLast(af2);
221
222 mDataBase.readNotificationHistory(null, null, 0);
223
224 verify(af, times(1)).openRead();
225 verify(af2, never()).openRead();
226 }
227
Julia Reynolds96951fc2019-11-13 16:04:33 -0500228 private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider {
229 public Map<File, Long> creationDates = new HashMap<>();
230
231 @Override
232 public long getCreationTime(File file) {
233 return creationDates.get(file);
234 }
235 }
Julia Reynoldse261db32019-10-21 11:37:35 -0400236}