1/* 2 * Copyright (C) 2014 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.providers.tv; 18 19import com.google.android.collect.Sets; 20 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Intent; 24import android.content.pm.ProviderInfo; 25import android.database.Cursor; 26import android.media.tv.TvContract; 27import android.media.tv.TvContract.Channels; 28import android.media.tv.TvContract.Programs; 29import android.media.tv.TvContract.WatchedPrograms; 30import android.net.Uri; 31import android.os.Bundle; 32import android.os.SystemClock; 33import android.provider.Settings; 34import android.test.ServiceTestCase; 35import android.test.mock.MockContentProvider; 36import android.test.mock.MockContentResolver; 37 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.Collection; 41import java.util.HashSet; 42import java.util.Objects; 43import java.util.Set; 44 45public class EpgDataCleanupServiceTests extends ServiceTestCase<EpgDataCleanupService> { 46 private static final String FAKE_INPUT_ID = "EpgDataCleanupServiceTests"; 47 48 private MockContentResolver mResolver; 49 private TvProvider mProvider; 50 51 public EpgDataCleanupServiceTests() { 52 super(EpgDataCleanupService.class); 53 } 54 55 @Override 56 protected void setUp() throws Exception { 57 super.setUp(); 58 59 mResolver = new MockContentResolver(); 60 // DateUtils tries to access Settings provider to get date format string. 61 mResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() { 62 @Override 63 public Bundle call(String method, String request, Bundle args) { 64 return new Bundle(); 65 } 66 }); 67 68 mProvider = new TvProviderForTesting(); 69 mResolver.addProvider(TvContract.AUTHORITY, mProvider); 70 71 setContext(new MockTvProviderContext(mResolver, getSystemContext())); 72 73 final ProviderInfo info = new ProviderInfo(); 74 info.authority = TvContract.AUTHORITY; 75 mProvider.attachInfoForTesting(getContext(), info); 76 77 startService(new Intent(getContext(), EpgDataCleanupService.class)); 78 } 79 80 @Override 81 protected void tearDown() throws Exception { 82 mProvider.shutdown(); 83 super.tearDown(); 84 } 85 86 private static class Program { 87 long id; 88 final long startTime; 89 final long endTime; 90 91 Program(long startTime, long endTime) { 92 this(-1, startTime, endTime); 93 } 94 95 Program(long id, long startTime, long endTime) { 96 this.id = id; 97 this.startTime = startTime; 98 this.endTime = endTime; 99 } 100 101 @Override 102 public boolean equals(Object obj) { 103 if (!(obj instanceof Program)) { 104 return false; 105 } 106 Program that = (Program) obj; 107 return Objects.equals(id, that.id) 108 && Objects.equals(startTime, that.startTime) 109 && Objects.equals(endTime, that.endTime); 110 } 111 112 @Override 113 public int hashCode() { 114 return Objects.hash(id, startTime, endTime); 115 } 116 117 @Override 118 public String toString() { 119 return "Program(id=" + id + ",start=" + startTime + ",end=" + endTime + ")"; 120 } 121 } 122 123 private long insertChannel() { 124 ContentValues values = new ContentValues(); 125 values.put(Channels.COLUMN_INPUT_ID, FAKE_INPUT_ID); 126 Uri uri = mResolver.insert(Channels.CONTENT_URI, values); 127 assertNotNull(uri); 128 return ContentUris.parseId(uri); 129 } 130 131 private void insertPrograms(Program... programs) { 132 insertPrograms(Arrays.asList(programs)); 133 } 134 135 private void insertPrograms(Collection<Program> programs) { 136 long channelId = insertChannel(); 137 138 ContentValues values = new ContentValues(); 139 values.put(Programs.COLUMN_CHANNEL_ID, channelId); 140 for (Program program : programs) { 141 values.put(Programs.COLUMN_START_TIME_UTC_MILLIS, program.startTime); 142 values.put(Programs.COLUMN_END_TIME_UTC_MILLIS, program.endTime); 143 Uri uri = mResolver.insert(Programs.CONTENT_URI, values); 144 assertNotNull(uri); 145 program.id = ContentUris.parseId(uri); 146 } 147 } 148 149 private Set<Program> queryPrograms() { 150 String[] projection = new String[] { 151 Programs._ID, 152 Programs.COLUMN_START_TIME_UTC_MILLIS, 153 Programs.COLUMN_END_TIME_UTC_MILLIS, 154 }; 155 156 Cursor cursor = mResolver.query(Programs.CONTENT_URI, projection, null, null, null); 157 assertNotNull(cursor); 158 try { 159 Set<Program> programs = Sets.newHashSet(); 160 while (cursor.moveToNext()) { 161 programs.add(new Program(cursor.getLong(0), cursor.getLong(1), cursor.getLong(2))); 162 } 163 return programs; 164 } finally { 165 cursor.close(); 166 } 167 } 168 169 private void insertWatchedPrograms(Program... programs) { 170 insertWatchedPrograms(Arrays.asList(programs)); 171 } 172 173 private void insertWatchedPrograms(Collection<Program> programs) { 174 long channelId = insertChannel(); 175 176 ContentValues values = new ContentValues(); 177 values.put(WatchedPrograms.COLUMN_PACKAGE_NAME, getContext().getPackageName()); 178 values.put(WatchedPrograms.COLUMN_CHANNEL_ID, channelId); 179 for (Program program : programs) { 180 values.put(WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, program.startTime); 181 values.put(WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, program.endTime); 182 Uri uri = mResolver.insert(WatchedPrograms.CONTENT_URI, values); 183 assertNotNull(uri); 184 program.id = ContentUris.parseId(uri); 185 } 186 } 187 188 private Set<Program> queryWatchedPrograms() { 189 String[] projection = new String[] { 190 WatchedPrograms._ID, 191 WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 192 WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 193 }; 194 195 Cursor cursor = mResolver.query(WatchedPrograms.CONTENT_URI, projection, null, null, null); 196 assertNotNull(cursor); 197 try { 198 Set<Program> programs = Sets.newHashSet(); 199 while (cursor.moveToNext()) { 200 programs.add(new Program(cursor.getLong(0), cursor.getLong(1), cursor.getLong(2))); 201 } 202 return programs; 203 } finally { 204 cursor.close(); 205 } 206 } 207 208 @Override 209 public void testServiceTestCaseSetUpProperly() throws Exception { 210 assertNotNull(getService()); 211 } 212 213 public void testClearOldPrograms() { 214 Program program = new Program(1, 2); 215 insertPrograms(program); 216 217 getService().clearOldPrograms(2); 218 assertEquals("Program should NOT be deleted if it ended at given time.", 219 Sets.newHashSet(program), queryPrograms()); 220 221 getService().clearOldPrograms(3); 222 assertTrue("Program should be deleted if it ended before given time.", 223 queryPrograms().isEmpty()); 224 225 ArrayList<Program> programs = new ArrayList<Program>(); 226 for (int i = 0; i < 10; i++) { 227 programs.add(new Program(999 + i, 1000 + i)); 228 } 229 insertPrograms(programs); 230 231 getService().clearOldPrograms(1005); 232 assertEquals("Program should be deleted if and only if it ended before given time.", 233 new HashSet<Program>(programs.subList(5, 10)), queryPrograms()); 234 } 235 236 public void testClearOldWatchedPrograms() { 237 Program program = new Program(1, 2); 238 insertWatchedPrograms(program); 239 240 getService().clearOldWatchHistory(1); 241 assertEquals("Watch history should NOT be deleted if watch started at given time.", 242 Sets.newHashSet(program), queryWatchedPrograms()); 243 244 getService().clearOldWatchHistory(2); 245 assertTrue("Watch history shuold be deleted if watch started before given time.", 246 queryWatchedPrograms().isEmpty()); 247 248 ArrayList<Program> programs = new ArrayList<Program>(); 249 for (int i = 0; i < 10; i++) { 250 programs.add(new Program(1000 + i, 1001 + i)); 251 } 252 insertWatchedPrograms(programs); 253 254 getService().clearOldWatchHistory(1005); 255 assertEquals("Watch history should be deleted if and only if it started before given time.", 256 new HashSet<Program>(programs.subList(5, 10)), queryWatchedPrograms()); 257 } 258 259 public void testClearOverflowWatchHistory() { 260 ArrayList<Program> programs = new ArrayList<Program>(); 261 for (int i = 0; i < 10; i++) { 262 programs.add(new Program(1000 + i, 1001 + i)); 263 } 264 insertWatchedPrograms(programs); 265 266 getService().clearOverflowWatchHistory(5); 267 assertEquals("Watch history should be deleted in watch start time order.", 268 new HashSet<Program>(programs.subList(5, 10)), queryWatchedPrograms()); 269 270 getService().clearOverflowWatchHistory(0); 271 assertTrue("All history should be deleted.", queryWatchedPrograms().isEmpty()); 272 } 273} 274