blob: 66b7a5ac5c71e8e14e24103460cfa4141f43ed56 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.providers.tv;
import com.google.android.collect.Sets;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Channels;
import android.media.tv.TvContract.PreviewPrograms;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import com.android.providers.tv.TvProvider.DatabaseHelper;
public class TransientRowHelperTests extends AndroidTestCase {
private static final String FAKE_INPUT_ID = "TransientRowHelperTests";
private MockContentResolver mResolver;
private TvProviderForTesting mProvider;
private RebootSimulatingTransientRowHelper mTransientRowHelper;
@Override
protected void setUp() throws Exception {
super.setUp();
mResolver = new MockContentResolver();
mResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
@Override
public Bundle call(String method, String request, Bundle args) {
return new Bundle();
}
});
mProvider = new TvProviderForTesting();
mResolver.addProvider(TvContract.AUTHORITY, mProvider);
setContext(new MockTvProviderContext(mResolver, getContext()));
final ProviderInfo info = new ProviderInfo();
info.authority = TvContract.AUTHORITY;
mProvider.attachInfoForTesting(getContext(), info);
mTransientRowHelper =
new RebootSimulatingTransientRowHelper(getContext(), mProvider.getDatabaseHelper());
mProvider.setTransientRowHelper(mTransientRowHelper);
Utils.clearTvProvider(mResolver);
}
@Override
protected void tearDown() throws Exception {
Utils.clearTvProvider(mResolver);
mProvider.shutdown();
super.tearDown();
}
private static class PreviewProgram {
long id;
final boolean isTransient;
PreviewProgram(boolean isTransient) {
this(-1, isTransient);
}
PreviewProgram(long id, boolean isTransient) {
this.id = id;
this.isTransient = isTransient;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PreviewProgram)) {
return false;
}
PreviewProgram that = (PreviewProgram) obj;
return Objects.equals(id, that.id)
&& Objects.equals(isTransient, that.isTransient);
}
@Override
public int hashCode() {
return Objects.hash(id, isTransient);
}
@Override
public String toString() {
return "PreviewProgram(id=" + id + ",isTransient=" + isTransient + ")";
}
}
private long insertChannel(boolean isTransient) {
ContentValues values = new ContentValues();
values.put(Channels.COLUMN_INPUT_ID, FAKE_INPUT_ID);
values.put(Channels.COLUMN_TRANSIENT, isTransient ? 1 : 0);
Uri uri = mResolver.insert(Channels.CONTENT_URI, values);
assertNotNull(uri);
return ContentUris.parseId(uri);
}
private void insertPreviewPrograms(long channelId, PreviewProgram... programs) {
insertPreviewPrograms(channelId, Arrays.asList(programs));
}
private void insertPreviewPrograms(long channelId, Collection<PreviewProgram> programs) {
ContentValues values = new ContentValues();
values.put(PreviewPrograms.COLUMN_CHANNEL_ID, channelId);
for (PreviewProgram program : programs) {
values.put(PreviewPrograms.COLUMN_TYPE, PreviewPrograms.TYPE_MOVIE);
values.put(PreviewPrograms.COLUMN_TRANSIENT, program.isTransient ? 1 : 0);
Uri uri = mResolver.insert(PreviewPrograms.CONTENT_URI, values);
assertNotNull(uri);
program.id = ContentUris.parseId(uri);
}
}
private Set<PreviewProgram> queryPreviewPrograms() {
String[] projection = new String[] {
PreviewPrograms._ID,
PreviewPrograms.COLUMN_TRANSIENT,
};
Cursor cursor = mResolver.query(PreviewPrograms.CONTENT_URI, projection, null, null, null);
assertNotNull(cursor);
try {
Set<PreviewProgram> programs = Sets.newHashSet();
while (cursor.moveToNext()) {
programs.add(new PreviewProgram(cursor.getLong(0), cursor.getInt(1) == 1));
}
return programs;
} finally {
cursor.close();
}
}
private long getChannelCount() {
String[] projection = new String[] {
Channels._ID,
};
Cursor cursor = mResolver.query(Channels.CONTENT_URI, projection, null, null, null);
assertNotNull(cursor);
try {
return cursor.getCount();
} finally {
cursor.close();
}
}
public void testTransientRowsAreDeletedAfterReboot() {
PreviewProgram transientProgramInTransientChannel =
new PreviewProgram(true /* transient */);
PreviewProgram permanentProgramInTransientChannel =
new PreviewProgram(false /* transient */);
PreviewProgram transientProgramInPermanentChannel =
new PreviewProgram(true /* transient */);
PreviewProgram permanentProgramInPermanentChannel =
new PreviewProgram(false /* transient */);
long transientChannelId = insertChannel(true /* transient */);
long permanentChannelId = insertChannel(false /* transient */);
insertPreviewPrograms(transientChannelId, transientProgramInTransientChannel);
insertPreviewPrograms(transientChannelId, permanentProgramInTransientChannel);
insertPreviewPrograms(permanentChannelId, transientProgramInPermanentChannel);
insertPreviewPrograms(permanentChannelId, permanentProgramInPermanentChannel);
assertEquals("Before reboot all the programs inserted should exist.",
Sets.newHashSet(transientProgramInTransientChannel,
permanentProgramInTransientChannel, transientProgramInPermanentChannel,
permanentProgramInPermanentChannel),
queryPreviewPrograms());
assertEquals("Before reboot the channels inserted should exist.",
2, getChannelCount());
mTransientRowHelper.simulateReboot();
assertEquals("Transient program and programs in transient channel should be removed.",
Sets.newHashSet(permanentProgramInPermanentChannel), queryPreviewPrograms());
assertEquals("Transient channel should not be removed.",
1, getChannelCount());
}
private class RebootSimulatingTransientRowHelper extends TransientRowHelper {
private int mLastDeletionBootCount;
private int mBootCount = 1;
private RebootSimulatingTransientRowHelper(Context context, DatabaseHelper helper) {
super(context, helper);
}
@Override
protected int getBootCount() {
return mBootCount;
}
@Override
protected int getLastDeletionBootCount() {
return mLastDeletionBootCount;
}
@Override
protected void setLastDeletionBootCount() {
mLastDeletionBootCount = mBootCount;
}
private void simulateReboot() {
mTransientRowsDeleted = false;
mBootCount++;
}
}
}