aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java')
-rw-r--r--tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java542
1 files changed, 0 insertions, 542 deletions
diff --git a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java b/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
deleted file mode 100644
index 5457051f..00000000
--- a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (C) 2015 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.tv.data;
-
-import static android.support.test.InstrumentationRegistry.getTargetContext;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.media.tv.TvContract;
-import android.net.Uri;
-import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.test.mock.MockContentProvider;
-import android.test.mock.MockContentResolver;
-import android.test.mock.MockCursor;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.tv.testing.Constants;
-import com.android.tv.testing.FakeClock;
-import com.android.tv.testing.ProgramInfo;
-import com.android.tv.util.Utils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test for {@link com.android.tv.data.ProgramDataManager}
- */
-@SmallTest
-public class ProgramDataManagerTest {
- private static final boolean DEBUG = false;
- private static final String TAG = "ProgramDataManagerTest";
-
- // Wait time for expected success.
- private static final long WAIT_TIME_OUT_MS = 1000L;
- // Wait time for expected failure.
- private static final long FAILURE_TIME_OUT_MS = 300L;
-
- // TODO: Use TvContract constants, once they become public.
- private static final String PARAM_CHANNEL = "channel";
- private static final String PARAM_START_TIME = "start_time";
- private static final String PARAM_END_TIME = "end_time";
-
- private ProgramDataManager mProgramDataManager;
- private FakeClock mClock;
- private HandlerThread mHandlerThread;
- private TestProgramDataManagerListener mListener;
- private FakeContentResolver mContentResolver;
- private FakeContentProvider mContentProvider;
-
- @Before
- public void setUp() {
- mClock = FakeClock.createWithCurrentTime();
- mListener = new TestProgramDataManagerListener();
- mContentProvider = new FakeContentProvider(getTargetContext());
- mContentResolver = new FakeContentResolver();
- mContentResolver.addProvider(TvContract.AUTHORITY, mContentProvider);
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mProgramDataManager = new ProgramDataManager(
- mContentResolver, mClock, mHandlerThread.getLooper());
- mProgramDataManager.setPrefetchEnabled(true);
- mProgramDataManager.addListener(mListener);
- }
-
- @After
- public void tearDown() {
- mHandlerThread.quitSafely();
- mProgramDataManager.stop();
- }
-
- private void startAndWaitForComplete() throws InterruptedException {
- mProgramDataManager.start();
- assertTrue(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
- }
-
- /**
- * Test for {@link ProgramInfo#getIndex} and {@link ProgramInfo#getStartTimeMs}.
- */
- @Test
- public void testProgramUtils() {
- ProgramInfo stub = ProgramInfo.create();
- for (long channelId = 1; channelId < Constants.UNIT_TEST_CHANNEL_COUNT; channelId++) {
- int index = stub.getIndex(mClock.currentTimeMillis(), channelId);
- long startTimeMs = stub.getStartTimeMs(index, channelId);
- ProgramInfo programAt = stub.build(InstrumentationRegistry.getContext(), index);
- assertTrue(startTimeMs <= mClock.currentTimeMillis());
- assertTrue(mClock.currentTimeMillis() < startTimeMs + programAt.durationMs);
- }
- }
-
- /**
- * Test for following methods.
- *
- * <p>
- * {@link ProgramDataManager#getCurrentProgram(long)},
- * {@link ProgramDataManager#getPrograms(long, long)},
- * {@link ProgramDataManager#setPrefetchTimeRange(long)}.
- * </p>
- */
- @Test
- public void testGetPrograms() throws InterruptedException {
- // Initial setup to test {@link ProgramDataManager#setPrefetchTimeRange(long)}.
- long preventSnapDelayMs = ProgramDataManager.PROGRAM_GUIDE_SNAP_TIME_MS * 2;
- long prefetchTimeRangeStartMs = System.currentTimeMillis() + preventSnapDelayMs;
- mClock.setCurrentTimeMillis(prefetchTimeRangeStartMs + preventSnapDelayMs);
- mProgramDataManager.setPrefetchTimeRange(prefetchTimeRangeStartMs);
-
- startAndWaitForComplete();
-
- for (long channelId = 1; channelId <= Constants.UNIT_TEST_CHANNEL_COUNT; channelId++) {
- Program currentProgram = mProgramDataManager.getCurrentProgram(channelId);
- // Test {@link ProgramDataManager#getCurrentProgram(long)}.
- assertTrue(currentProgram.getStartTimeUtcMillis() <= mClock.currentTimeMillis()
- && mClock.currentTimeMillis() <= currentProgram.getEndTimeUtcMillis());
-
- // Test {@link ProgramDataManager#getPrograms(long)}.
- // Case #1: Normal case
- List<Program> programs =
- mProgramDataManager.getPrograms(channelId, mClock.currentTimeMillis());
- ProgramInfo stub = ProgramInfo.create();
- int index = stub.getIndex(mClock.currentTimeMillis(), channelId);
- for (Program program : programs) {
- ProgramInfo programInfoAt = stub.build(InstrumentationRegistry.getContext(), index);
- long startTimeMs = stub.getStartTimeMs(index, channelId);
- assertProgramEquals(startTimeMs, programInfoAt, program);
- index++;
- }
- // Case #2: Corner cases where there's a program that starts at the start of the range.
- long startTimeMs = programs.get(0).getStartTimeUtcMillis();
- programs = mProgramDataManager.getPrograms(channelId, startTimeMs);
- assertEquals(startTimeMs, programs.get(0).getStartTimeUtcMillis());
-
- // Test {@link ProgramDataManager#setPrefetchTimeRange(long)}.
- programs = mProgramDataManager.getPrograms(channelId,
- prefetchTimeRangeStartMs - TimeUnit.HOURS.toMillis(1));
- for (Program program : programs) {
- assertTrue(program.getEndTimeUtcMillis() >= prefetchTimeRangeStartMs);
- }
- }
- }
-
- /**
- * Test for following methods.
- *
- * <p>
- * {@link ProgramDataManager#addOnCurrentProgramUpdatedListener},
- * {@link ProgramDataManager#removeOnCurrentProgramUpdatedListener}.
- * </p>
- */
- @Test
- public void testCurrentProgramListener() throws InterruptedException {
- final long testChannelId = 1;
- ProgramInfo stub = ProgramInfo.create();
- int index = stub.getIndex(mClock.currentTimeMillis(), testChannelId);
- // Set current time to few seconds before the current program ends,
- // so we can see if callback is called as expected.
- long nextProgramStartTimeMs = stub.getStartTimeMs(index + 1, testChannelId);
- ProgramInfo nextProgramInfo = stub.build(InstrumentationRegistry.getContext(), index + 1);
- mClock.setCurrentTimeMillis(nextProgramStartTimeMs - (WAIT_TIME_OUT_MS / 2));
-
- startAndWaitForComplete();
- // Note that changing current time doesn't affect the current program
- // because current program is updated after waiting for the program's duration.
- // See {@link ProgramDataManager#updateCurrentProgram}.
- mClock.setCurrentTimeMillis(mClock.currentTimeMillis() + WAIT_TIME_OUT_MS);
- TestProgramDataManagerOnCurrentProgramUpdatedListener listener =
- new TestProgramDataManagerOnCurrentProgramUpdatedListener();
- mProgramDataManager.addOnCurrentProgramUpdatedListener(testChannelId, listener);
- assertTrue(
- listener.currentProgramUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
- assertEquals(testChannelId, listener.updatedChannelId);
- Program currentProgram = mProgramDataManager.getCurrentProgram(testChannelId);
- assertProgramEquals(nextProgramStartTimeMs, nextProgramInfo, currentProgram);
- assertEquals(listener.updatedProgram, currentProgram);
- }
-
- /**
- * Test if program data is refreshed after the program insertion.
- */
- @Test
- public void testContentProviderUpdate() throws InterruptedException {
- final long testChannelId = 1;
- startAndWaitForComplete();
- // Force program data manager to update program data whenever it's changes.
- mProgramDataManager.setProgramPrefetchUpdateWait(0);
- mListener.reset();
- List<Program> programList =
- mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis());
- assertNotNull(programList);
- long lastProgramEndTime = programList.get(programList.size() - 1).getEndTimeUtcMillis();
- // Make change in content provider
- mContentProvider.simulateAppend(testChannelId);
- assertTrue(mListener.programUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
- programList = mProgramDataManager.getPrograms(testChannelId, mClock.currentTimeMillis());
- assertTrue(
- lastProgramEndTime < programList.get(programList.size() - 1).getEndTimeUtcMillis());
- }
-
- /**
- * Test for {@link ProgramDataManager#setPauseProgramUpdate(boolean)}.
- */
- @Test
- public void testSetPauseProgramUpdate() throws InterruptedException {
- final long testChannelId = 1;
- startAndWaitForComplete();
- // Force program data manager to update program data whenever it's changes.
- mProgramDataManager.setProgramPrefetchUpdateWait(0);
- mListener.reset();
- mProgramDataManager.setPauseProgramUpdate(true);
- mContentProvider.simulateAppend(testChannelId);
- assertFalse(mListener.programUpdatedLatch.await(FAILURE_TIME_OUT_MS,
- TimeUnit.MILLISECONDS));
- }
-
- public static void assertProgramEquals(long expectedStartTime, ProgramInfo expectedInfo,
- Program actualProgram) {
- assertEquals("title", expectedInfo.title, actualProgram.getTitle());
- assertEquals("episode", expectedInfo.episode, actualProgram.getEpisodeTitle());
- assertEquals("description", expectedInfo.description, actualProgram.getDescription());
- assertEquals("startTime", expectedStartTime, actualProgram.getStartTimeUtcMillis());
- assertEquals("endTime", expectedStartTime + expectedInfo.durationMs,
- actualProgram.getEndTimeUtcMillis());
- }
-
- private class FakeContentResolver extends MockContentResolver {
- @Override
- public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
- super.notifyChange(uri, observer, syncToNetwork);
- if (DEBUG) {
- Log.d(TAG, "onChanged(uri=" + uri + ")");
- }
- if (observer != null) {
- observer.dispatchChange(false, uri);
- } else {
- mProgramDataManager.getContentObserver().dispatchChange(false, uri);
- }
- }
- }
-
- private static class ProgramInfoWrapper {
- private final int index;
- private final long startTimeMs;
- private final ProgramInfo programInfo;
-
- public ProgramInfoWrapper(int index, long startTimeMs, ProgramInfo programInfo) {
- this.index = index;
- this.startTimeMs = startTimeMs;
- this.programInfo = programInfo;
- }
- }
-
- // This implements the minimal methods in content resolver
- // and detailed assumptions are written in each method.
- private class FakeContentProvider extends MockContentProvider {
- private final SparseArray<List<ProgramInfoWrapper>> mProgramInfoList = new SparseArray<>();
-
- /**
- * Constructor for FakeContentProvider
- * <p>
- * This initializes program info assuming that
- * channel IDs are 1, 2, 3, ... {@link Constants#UNIT_TEST_CHANNEL_COUNT}.
- * </p>
- */
- public FakeContentProvider(Context context) {
- super(context);
- long startTimeMs = Utils.floorTime(
- mClock.currentTimeMillis() - ProgramDataManager.PROGRAM_GUIDE_SNAP_TIME_MS,
- ProgramDataManager.PROGRAM_GUIDE_SNAP_TIME_MS);
- long endTimeMs = startTimeMs + (ProgramDataManager.PROGRAM_GUIDE_MAX_TIME_RANGE / 2);
- for (int i = 1; i <= Constants.UNIT_TEST_CHANNEL_COUNT; i++) {
- List<ProgramInfoWrapper> programInfoList = new ArrayList<>();
- ProgramInfo stub = ProgramInfo.create();
- int index = stub.getIndex(startTimeMs, i);
- long programStartTimeMs = stub.getStartTimeMs(index, i);
- while (programStartTimeMs < endTimeMs) {
- ProgramInfo programAt = stub.build(InstrumentationRegistry.getContext(), index);
- programInfoList.add(
- new ProgramInfoWrapper(index, programStartTimeMs, programAt));
- index++;
- programStartTimeMs += programAt.durationMs;
- }
- mProgramInfoList.put(i, programInfoList);
- }
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- if (DEBUG) {
- Log.d(TAG, "dump query");
- Log.d(TAG, " uri=" + uri);
- Log.d(TAG, " projection=" + Arrays.toString(projection));
- Log.d(TAG, " selection=" + selection);
- }
- long startTimeMs = Long.parseLong(uri.getQueryParameter(PARAM_START_TIME));
- long endTimeMs = Long.parseLong(uri.getQueryParameter(PARAM_END_TIME));
- if (startTimeMs == 0 || endTimeMs == 0) {
- throw new UnsupportedOperationException();
- }
- assertProgramUri(uri);
- long channelId;
- try {
- channelId = Long.parseLong(uri.getQueryParameter(PARAM_CHANNEL));
- } catch (NumberFormatException e) {
- channelId = -1;
- }
- return new FakeCursor(projection, channelId, startTimeMs, endTimeMs);
- }
-
- /**
- * Simulate program data appends at the end of the existing programs.
- * This appends programs until the maximum program query range
- * ({@link ProgramDataManager#PROGRAM_GUIDE_MAX_TIME_RANGE})
- * where we started with the inserting half of it.
- */
- public void simulateAppend(long channelId) {
- long endTimeMs =
- mClock.currentTimeMillis() + ProgramDataManager.PROGRAM_GUIDE_MAX_TIME_RANGE;
- List<ProgramInfoWrapper> programList = mProgramInfoList.get((int) channelId);
- if (mProgramInfoList == null) {
- return;
- }
- ProgramInfo stub = ProgramInfo.create();
- ProgramInfoWrapper last = programList.get(programList.size() - 1);
- while (last.startTimeMs < endTimeMs) {
- ProgramInfo nextProgramInfo = stub.build(InstrumentationRegistry.getContext(),
- last.index + 1);
- ProgramInfoWrapper next = new ProgramInfoWrapper(last.index + 1,
- last.startTimeMs + last.programInfo.durationMs, nextProgramInfo);
- programList.add(next);
- last = next;
- }
- mContentResolver.notifyChange(TvContract.Programs.CONTENT_URI, null);
- }
-
- private void assertProgramUri(Uri uri) {
- assertTrue("Uri(" + uri + ") isn't channel uri",
- uri.toString().startsWith(TvContract.Programs.CONTENT_URI.toString()));
- }
-
- public ProgramInfoWrapper get(long channelId, int position) {
- List<ProgramInfoWrapper> programList = mProgramInfoList.get((int) channelId);
- if (programList == null || position >= programList.size()) {
- return null;
- }
- return programList.get(position);
- }
- }
-
- private class FakeCursor extends MockCursor {
- private final String[] ALL_COLUMNS = {
- TvContract.Programs.COLUMN_CHANNEL_ID,
- TvContract.Programs.COLUMN_TITLE,
- TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
- TvContract.Programs.COLUMN_EPISODE_TITLE,
- TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
- TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS};
- private final String[] mColumns;
- private final boolean mIsQueryForSingleChannel;
- private final long mStartTimeMs;
- private final long mEndTimeMs;
- private final int mCount;
- private long mChannelId;
- private int mProgramPosition;
- private ProgramInfoWrapper mCurrentProgram;
-
- /**
- * Constructor
- * @param columns the same as projection passed from {@link FakeContentProvider#query}.
- * Can be null for query all.
- * @param channelId channel ID to query programs belongs to the specified channel.
- * Can be negative to indicate all channels.
- * @param startTimeMs start of the time range to query programs.
- * @param endTimeMs end of the time range to query programs.
- */
- public FakeCursor(String[] columns, long channelId, long startTimeMs, long endTimeMs) {
- mColumns = (columns == null) ? ALL_COLUMNS : columns;
- mIsQueryForSingleChannel = (channelId > 0);
- mChannelId = channelId;
- mProgramPosition = -1;
- mStartTimeMs = startTimeMs;
- mEndTimeMs = endTimeMs;
- int count = 0;
- while (moveToNext()) {
- count++;
- }
- mCount = count;
- // Rewind channel Id and program index.
- mChannelId = channelId;
- mProgramPosition = -1;
- if (DEBUG) {
- Log.d(TAG, "FakeCursor(columns=" + Arrays.toString(columns)
- + ", channelId=" + channelId + ", startTimeMs=" + startTimeMs
- + ", endTimeMs=" + endTimeMs + ") has mCount=" + mCount);
- }
- }
-
- @Override
- public String getColumnName(int columnIndex) {
- return mColumns[columnIndex];
- }
-
- @Override
- public int getColumnIndex(String columnName) {
- for (int i = 0; i < mColumns.length; i++) {
- if (mColumns[i].equalsIgnoreCase(columnName)) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public int getInt(int columnIndex) {
- if (DEBUG) {
- Log.d(TAG, "Column (" + getColumnName(columnIndex) + ") is ignored in getInt()");
- }
- return 0;
- }
-
- @Override
- public long getLong(int columnIndex) {
- String columnName = getColumnName(columnIndex);
- switch (columnName) {
- case TvContract.Programs.COLUMN_CHANNEL_ID:
- return mChannelId;
- case TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS:
- return mCurrentProgram.startTimeMs;
- case TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS:
- return mCurrentProgram.startTimeMs + mCurrentProgram.programInfo.durationMs;
- }
- if (DEBUG) {
- Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()");
- }
- return 0;
- }
-
- @Override
- public String getString(int columnIndex) {
- String columnName = getColumnName(columnIndex);
- switch (columnName) {
- case TvContract.Programs.COLUMN_TITLE:
- return mCurrentProgram.programInfo.title;
- case TvContract.Programs.COLUMN_SHORT_DESCRIPTION:
- return mCurrentProgram.programInfo.description;
- case TvContract.Programs.COLUMN_EPISODE_TITLE:
- return mCurrentProgram.programInfo.episode;
- }
- if (DEBUG) {
- Log.d(TAG, "Column (" + columnName + ") is ignored in getString()");
- }
- return null;
- }
-
- @Override
- public int getCount() {
- return mCount;
- }
-
- @Override
- public boolean moveToNext() {
- while (true) {
- ProgramInfoWrapper program = mContentProvider.get(mChannelId, ++mProgramPosition);
- if (program == null || program.startTimeMs >= mEndTimeMs) {
- if (mIsQueryForSingleChannel) {
- return false;
- } else {
- if (++mChannelId > Constants.UNIT_TEST_CHANNEL_COUNT) {
- return false;
- }
- mProgramPosition = -1;
- }
- } else if (program.startTimeMs + program.programInfo.durationMs >= mStartTimeMs) {
- mCurrentProgram = program;
- break;
- }
- }
- return true;
- }
-
- @Override
- public void close() {
- // No-op.
- }
- }
-
- private class TestProgramDataManagerListener implements ProgramDataManager.Listener {
- public CountDownLatch programUpdatedLatch = new CountDownLatch(1);
-
- @Override
- public void onProgramUpdated() {
- programUpdatedLatch.countDown();
- }
-
- public void reset() {
- programUpdatedLatch = new CountDownLatch(1);
- }
- }
-
- private class TestProgramDataManagerOnCurrentProgramUpdatedListener implements
- OnCurrentProgramUpdatedListener {
- public final CountDownLatch currentProgramUpdatedLatch = new CountDownLatch(1);
- public long updatedChannelId = -1;
- public Program updatedProgram = null;
-
- @Override
- public void onCurrentProgramUpdated(long channelId, Program program) {
- updatedChannelId = channelId;
- updatedProgram = program;
- currentProgramUpdatedLatch.countDown();
- }
- }
-}