1816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/*
2816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Copyright (C) 2015 The Android Open Source Project
3816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko *
4816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
5816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * you may not use this file except in compliance with the License.
6816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * You may obtain a copy of the License at
7816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko *
8816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
9816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko *
10816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Unless required by applicable law or agreed to in writing, software
11816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
12816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * See the License for the specific language governing permissions and
14816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * limitations under the License.
15816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */
16816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
17816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopackage com.android.tv.recommendation;
18816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport static org.junit.Assert.assertTrue;
206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.test.filters.SmallTest;
2207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko
236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport org.junit.Test;
246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
25816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.HashMap;
26816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.List;
27816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Map;
28816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.concurrent.TimeUnit;
29816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
30816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/**
31816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Unit tests for {@link RecentChannelEvaluator}.
32816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */
3307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko@SmallTest
34816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopublic class RecentChannelEvaluatorTest extends EvaluatorTestCase<RecentChannelEvaluator> {
35816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int DEFAULT_NUMBER_OF_CHANNELS = 4;
36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final long DEFAULT_WATCH_START_TIME_MS =
37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2);
38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final long DEFAULT_WATCH_END_TIME_MS =
39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final long DEFAULT_MAX_WATCH_DURATION_MS = TimeUnit.HOURS.toMillis(1);
41816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
4207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    @Override
43816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public RecentChannelEvaluator createEvaluator() {
44816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return new RecentChannelEvaluator();
45816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
46816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
48816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testOneChannelWithNoWatchLog() {
49816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        long channelId = addChannel().getId();
50816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
51816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        assertEqualScores(Recommender.Evaluator.NOT_RECOMMENDED,
53816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                mEvaluator.evaluateChannel(channelId));
54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
57816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testOneChannelWithRandomWatchLogs() {
58816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addChannel();
59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS,
60816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                DEFAULT_MAX_WATCH_DURATION_MS);
61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        assertChannelScoresValid();
64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
65816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testMultiChannelsWithNoWatchLog() {
68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addChannels(DEFAULT_NUMBER_OF_CHANNELS);
69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        List<Long> channelIdList = getChannelIdListSorted();
72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (long channelId : channelIdList) {
736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            assertEqualScores(Recommender.Evaluator.NOT_RECOMMENDED,
74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    mEvaluator.evaluateChannel(channelId));
75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testMultiChannelsWithRandomWatchLogs() {
80816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addChannels(DEFAULT_NUMBER_OF_CHANNELS);
81816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS,
82816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                DEFAULT_MAX_WATCH_DURATION_MS);
83816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
84816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
85816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        assertChannelScoresValid();
86816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
87816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testMultiChannelsWithSimpleWatchLogs() {
90816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addChannels(DEFAULT_NUMBER_OF_CHANNELS);
91816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        // Every channel has one watch log with 1 hour. Also, for two channels
92816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        // which has ID x and y (x < y), the channel y is watched later than the channel x.
93816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        long latestWatchEndTimeMs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2);
94816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        List<Long> channelIdList = getChannelIdListSorted();
95816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (long channelId : channelIdList) {
96816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            addWatchLog(channelId, latestWatchEndTimeMs, TimeUnit.HOURS.toMillis(1));
97816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            latestWatchEndTimeMs += TimeUnit.HOURS.toMillis(1);
98816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
99816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
100816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
101816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        assertChannelScoresValid();
102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        // Channel score must be increased as channel ID increased.
103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        double previousScore = Recommender.Evaluator.NOT_RECOMMENDED;
104816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (long channelId : channelIdList) {
105816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            double score = mEvaluator.evaluateChannel(channelId);
106816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            assertTrue(previousScore <= score);
107816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            previousScore = score;
108816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
109816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
110816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
1116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
112816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testScoreIncreasesWithNewWatchLog() {
113816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addChannels(DEFAULT_NUMBER_OF_CHANNELS);
114816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS,
115816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                DEFAULT_MAX_WATCH_DURATION_MS);
116816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
117816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
118816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        List<Long> channelIdList = getChannelIdListSorted();
119816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        long latestWatchEndTimeMs = getLatestWatchEndTimeMs();
120816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (long channelId : channelIdList) {
121816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            double previousScore = mEvaluator.evaluateChannel(channelId);
122816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
123816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            long durationMs = TimeUnit.MINUTES.toMillis(10);
124816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            addWatchLog(channelId, latestWatchEndTimeMs, durationMs);
125816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            latestWatchEndTimeMs += durationMs;
126816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
127816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            // Score must be increased because recentness of the log increases.
128816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            assertTrue(previousScore <= mEvaluator.evaluateChannel(channelId));
129816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
130816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
131816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
1326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Test
133816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void testScoreDecreasesWithIncrementOfWatchedLogUpdatedTime() {
134816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addChannels(DEFAULT_NUMBER_OF_CHANNELS);
135816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addRandomWatchLogs(DEFAULT_WATCH_START_TIME_MS, DEFAULT_WATCH_END_TIME_MS,
136816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                DEFAULT_MAX_WATCH_DURATION_MS);
137816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        notifyChannelAndWatchLogLoaded();
138816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
139816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        Map<Long, Double> scores = new HashMap<>();
140816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        List<Long> channelIdList = getChannelIdListSorted();
141816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        long latestWatchedEndTimeMs = getLatestWatchEndTimeMs();
142816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
143816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (long channelId : channelIdList) {
144816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            scores.put(channelId, mEvaluator.evaluateChannel(channelId));
145816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
146816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
147816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        long newChannelId = addChannel().getId();
148816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        addWatchLog(newChannelId, latestWatchedEndTimeMs, TimeUnit.MINUTES.toMillis(10));
149816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
150816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (long channelId : channelIdList) {
151816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            // Score must be decreased because LastWatchLogUpdateTime increases by new log.
152816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            assertTrue(mEvaluator.evaluateChannel(channelId) <= scores.get(channelId));
153816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
154816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
155816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko}
156