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