• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
17 package com.android.tv.dvr;
18 
19 import static org.mockito.Matchers.any;
20 import static org.mockito.Matchers.anyLong;
21 import static org.mockito.Matchers.eq;
22 import static org.mockito.Mockito.after;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.timeout;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27 
28 import android.app.AlarmManager;
29 import android.media.tv.TvInputInfo;
30 import android.os.Build;
31 import android.os.Handler;
32 import android.os.Looper;
33 import android.support.test.filters.SdkSuppress;
34 import android.support.test.filters.SmallTest;
35 import android.test.AndroidTestCase;
36 
37 import com.android.tv.InputSessionManager;
38 import com.android.tv.data.Channel;
39 import com.android.tv.data.ChannelDataManager;
40 import com.android.tv.dvr.InputTaskScheduler.RecordingTaskFactory;
41 import com.android.tv.testing.FakeClock;
42 import com.android.tv.testing.dvr.RecordingTestUtils;
43 import com.android.tv.util.Clock;
44 import com.android.tv.util.TestUtils;
45 
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 
49 import java.util.ArrayList;
50 import java.util.List;
51 import java.util.concurrent.TimeUnit;
52 
53 /**
54  * Tests for {@link InputTaskScheduler}.
55  */
56 @SmallTest
57 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
58 public class InputTaskSchedulerTest extends AndroidTestCase {
59     private static final String INPUT_ID = "input_id";
60     private static final int CHANNEL_ID = 1;
61     private static final long LISTENER_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
62     private static final int TUNER_COUNT_ONE = 1;
63     private static final int TUNER_COUNT_TWO = 2;
64     private static final long LOW_PRIORITY = 1;
65     private static final long HIGH_PRIORITY = 2;
66 
67     private FakeClock mFakeClock;
68     private InputTaskScheduler mScheduler;
69     @Mock private DvrManager mDvrManager;
70     @Mock private WritableDvrDataManager mDataManager;
71     @Mock private InputSessionManager mSessionManager;
72     @Mock private AlarmManager mMockAlarmManager;
73     @Mock private ChannelDataManager mChannelDataManager;
74     private List<RecordingTask> mRecordingTasks;
75 
76     @Override
setUp()77     protected void setUp() throws Exception {
78         super.setUp();
79         if (Looper.myLooper() == null) {
80             Looper.prepare();
81         }
82         Handler fakeMainHandler = new Handler();
83         Handler workerThreadHandler = new Handler();
84         mRecordingTasks = new ArrayList();
85         MockitoAnnotations.initMocks(this);
86         mFakeClock = FakeClock.createWithCurrentTime();
87         TvInputInfo input = createTvInputInfo(TUNER_COUNT_ONE);
88         mScheduler = new InputTaskScheduler(getContext(), input, Looper.myLooper(),
89                 mChannelDataManager, mDvrManager, mDataManager, mSessionManager, mFakeClock,
90                 fakeMainHandler, workerThreadHandler, new RecordingTaskFactory() {
91                     @Override
92                     public RecordingTask createRecordingTask(ScheduledRecording scheduledRecording,
93                             Channel channel, DvrManager dvrManager,
94                             InputSessionManager sessionManager, WritableDvrDataManager dataManager,
95                             Clock clock) {
96                         RecordingTask task = mock(RecordingTask.class);
97                         when(task.getPriority()).thenReturn(scheduledRecording.getPriority());
98                         when(task.getEndTimeMs()).thenReturn(scheduledRecording.getEndTimeMs());
99                         mRecordingTasks.add(task);
100                         return task;
101                     }
102                 });
103     }
104 
105     @Override
tearDown()106     protected void tearDown() throws Exception {
107         super.tearDown();
108     }
109 
testAddSchedule_past()110     public void testAddSchedule_past() throws Exception {
111         ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID,
112                 CHANNEL_ID, 0L, 1L);
113         when(mDataManager.getScheduledRecording(anyLong())).thenReturn(r);
114         mScheduler.handleAddSchedule(r);
115         mScheduler.handleBuildSchedule();
116         verify(mDataManager, timeout((int) LISTENER_TIMEOUT_MS).times(1))
117                 .changeState(any(ScheduledRecording.class),
118                         eq(ScheduledRecording.STATE_RECORDING_FAILED));
119     }
120 
testAddSchedule_start()121     public void testAddSchedule_start() throws Exception {
122         mScheduler.handleAddSchedule(RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID,
123                 CHANNEL_ID, mFakeClock.currentTimeMillis(),
124                 mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)));
125         mScheduler.handleBuildSchedule();
126         verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
127     }
128 
testAddSchedule_consecutiveNoStop()129     public void testAddSchedule_consecutiveNoStop() throws Exception {
130         long startTimeMs = mFakeClock.currentTimeMillis();
131         long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
132         long id = 0;
133         mScheduler.handleAddSchedule(
134                 RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID,
135                         LOW_PRIORITY, startTimeMs, endTimeMs));
136         mScheduler.handleBuildSchedule();
137         startTimeMs = endTimeMs;
138         endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
139         mScheduler.handleAddSchedule(
140                 RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID,
141                         HIGH_PRIORITY, startTimeMs, endTimeMs));
142         mScheduler.handleBuildSchedule();
143         verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
144         // The first schedule should not be stopped because the second one should wait for the end
145         // of the first schedule.
146         verify(mRecordingTasks.get(0), after((int) LISTENER_TIMEOUT_MS).never()).stop();
147     }
148 
testAddSchedule_consecutiveNoFail()149     public void testAddSchedule_consecutiveNoFail() throws Exception {
150         long startTimeMs = mFakeClock.currentTimeMillis();
151         long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
152         long id = 0;
153         when(mDataManager.getScheduledRecording(anyLong())).thenReturn(ScheduledRecording
154                 .builder(INPUT_ID, CHANNEL_ID, 0L, 0L).build());
155         mScheduler.handleAddSchedule(
156                 RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID,
157                         HIGH_PRIORITY, startTimeMs, endTimeMs));
158         mScheduler.handleBuildSchedule();
159         startTimeMs = endTimeMs;
160         endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
161         mScheduler.handleAddSchedule(
162                 RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID,
163                         LOW_PRIORITY, startTimeMs, endTimeMs));
164         mScheduler.handleBuildSchedule();
165         verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
166         verify(mRecordingTasks.get(0), after((int) LISTENER_TIMEOUT_MS).never()).stop();
167         // The second schedule should not fail because it can starts after the first one finishes.
168         verify(mDataManager, after((int) LISTENER_TIMEOUT_MS).never())
169                 .changeState(any(ScheduledRecording.class),
170                         eq(ScheduledRecording.STATE_RECORDING_FAILED));
171     }
172 
testAddSchedule_consecutiveUseLessSession()173     public void testAddSchedule_consecutiveUseLessSession() throws Exception {
174         TvInputInfo input = createTvInputInfo(TUNER_COUNT_TWO);
175         mScheduler.updateTvInputInfo(input);
176         long startTimeMs = mFakeClock.currentTimeMillis();
177         long endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
178         long id = 0;
179         mScheduler.handleAddSchedule(
180                 RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID,
181                         LOW_PRIORITY, startTimeMs, endTimeMs));
182         mScheduler.handleBuildSchedule();
183         startTimeMs = endTimeMs;
184         endTimeMs = startTimeMs + TimeUnit.SECONDS.toMillis(1);
185         mScheduler.handleAddSchedule(
186                 RecordingTestUtils.createTestRecordingWithIdAndPriorityAndPeriod(++id, CHANNEL_ID,
187                         HIGH_PRIORITY, startTimeMs, endTimeMs));
188         mScheduler.handleBuildSchedule();
189         verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).start();
190         verify(mRecordingTasks.get(0), after((int) LISTENER_TIMEOUT_MS).never()).stop();
191         // The second schedule should wait until the first one finishes rather than creating a new
192         // session even though there are available tuners.
193         assertTrue(mRecordingTasks.size() == 1);
194     }
195 
testUpdateSchedule_noCancel()196     public void testUpdateSchedule_noCancel() throws Exception {
197         ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID,
198                 CHANNEL_ID, mFakeClock.currentTimeMillis(),
199                 mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1));
200         mScheduler.handleAddSchedule(r);
201         mScheduler.handleBuildSchedule();
202         mScheduler.handleUpdateSchedule(r);
203         verify(mRecordingTasks.get(0), after((int) LISTENER_TIMEOUT_MS).never()).cancel();
204     }
205 
testUpdateSchedule_cancel()206     public void testUpdateSchedule_cancel() throws Exception {
207         ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID,
208                 CHANNEL_ID, mFakeClock.currentTimeMillis(),
209                 mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(2));
210         mScheduler.handleAddSchedule(r);
211         mScheduler.handleBuildSchedule();
212         mScheduler.handleUpdateSchedule(ScheduledRecording.buildFrom(r)
213                 .setStartTimeMs(mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1))
214                 .build());
215         verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).times(1)).cancel();
216     }
217 
createTvInputInfo(int tunerCount)218     private TvInputInfo createTvInputInfo(int tunerCount) throws Exception {
219         return TestUtils.createTvInputInfo(null, null, null, 0, false, true, tunerCount);
220     }
221 }
222