Merge pull request #3654 from ByteHamster/emulator-test
Run integration tests on CI
This commit is contained in:
commit
707fcdbc7f
29
.github/workflows/android-emulator.yml
vendored
Normal file
29
.github/workflows/android-emulator.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: Android Emulator test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew assemblePlayDebugAndroidTest
|
||||
- name: Android Emulator test
|
||||
uses: ReactiveCircus/android-emulator-runner@v1.0.1
|
||||
with:
|
||||
api-level: 28
|
||||
headless: true
|
||||
disable-animations: true
|
||||
script: ./gradlew connectedPlayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.notAnnotation=de.test.antennapod.IgnoreOnCi
|
||||
- uses: actions/upload-artifact@v1
|
||||
if: failure()
|
||||
with:
|
||||
name: test-report
|
||||
path: app/build/reports/androidTests/connected/flavors/PLAY/
|
@ -1,6 +1,8 @@
|
||||
package de.test.antennapod;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.espresso.PerformException;
|
||||
@ -14,11 +16,16 @@ import androidx.test.espresso.util.TreeIterables;
|
||||
import android.view.View;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.dialog.RatingDialog;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.awaitility.core.ConditionTimeoutException;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
@ -76,6 +83,31 @@ public class EspressoTestUtils {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform action of waiting for a specific view id.
|
||||
* https://stackoverflow.com/a/30338665/
|
||||
* @param id The id of the child to click.
|
||||
*/
|
||||
public static ViewAction clickChildViewWithId(final @IdRes int id) {
|
||||
return new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Click on a child view with specified id.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
View v = view.findViewById(id);
|
||||
v.performClick();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all app databases
|
||||
*/
|
||||
@ -127,12 +159,37 @@ public class EspressoTestUtils {
|
||||
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
|
||||
}
|
||||
|
||||
public static void closeNavDrawer() {
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.drawer_layout), 1000));
|
||||
onView(withId(R.id.drawer_layout)).perform(DrawerActions.close());
|
||||
}
|
||||
|
||||
public static ViewInteraction onDrawerItem(Matcher<View> viewMatcher) {
|
||||
return onView(allOf(viewMatcher, withId(R.id.txtvTitle)));
|
||||
}
|
||||
|
||||
public static void tryKillPlaybackService() {
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
context.stopService(new Intent(context, PlaybackService.class));
|
||||
try {
|
||||
// Android has no reliable way to stop a service instantly.
|
||||
// Calling stopSelf marks allows the system to destroy the service but the actual call
|
||||
// to onDestroy takes until the next GC of the system, which we can not influence.
|
||||
// Try to wait for the service at least a bit.
|
||||
Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> !PlaybackService.isRunning);
|
||||
} catch (ConditionTimeoutException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
|
||||
public static void tryKillDownloadService() {
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
context.stopService(new Intent(context, DownloadService.class));
|
||||
try {
|
||||
// Android has no reliable way to stop a service instantly.
|
||||
// Calling stopSelf marks allows the system to destroy the service but the actual call
|
||||
// to onDestroy takes until the next GC of the system, which we can not influence.
|
||||
// Try to wait for the service at least a bit.
|
||||
Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> !DownloadService.isRunning);
|
||||
} catch (ConditionTimeoutException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
}
|
||||
}
|
||||
|
15
app/src/androidTest/java/de/test/antennapod/IgnoreOnCi.java
Normal file
15
app/src/androidTest/java/de/test/antennapod/IgnoreOnCi.java
Normal file
@ -0,0 +1,15 @@
|
||||
package de.test.antennapod;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Tests with this annotation are ignored on CI. This could be reasonable
|
||||
* if the performance of the CI server is not enough to provide a reliable result.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface IgnoreOnCi {
|
||||
}
|
@ -11,10 +11,6 @@ public class NthMatcher {
|
||||
return nth(matcher, 1);
|
||||
}
|
||||
|
||||
public static <T> Matcher<T> second(final Matcher<T> matcher) {
|
||||
return nth(matcher, 2);
|
||||
}
|
||||
|
||||
public static <T> Matcher<T> nth(final Matcher<T> matcher, final int index) {
|
||||
return new BaseMatcher<T>() {
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
@ -31,7 +27,8 @@ public class NthMatcher {
|
||||
|
||||
@Override
|
||||
public void describeTo(final Description description) {
|
||||
description.appendText("should return first matching item");
|
||||
description.appendText("Item #" + index + " ");
|
||||
description.appendDescriptionOf(matcher);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
package de.test.antennapod.playback;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
|
||||
*/
|
||||
@LargeTest
|
||||
public class PlaybackBuiltinTest extends PlaybackTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
UserPreferences.enableBuiltin();
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package de.test.antennapod.playback;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
|
||||
*/
|
||||
@LargeTest
|
||||
public class PlaybackExoplayerTest extends PlaybackTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
UserPreferences.enableExoplayer();
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package de.test.antennapod.playback;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
|
||||
*/
|
||||
@LargeTest
|
||||
public class PlaybackSonicTest extends PlaybackTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
UserPreferences.enableSonic();
|
||||
}
|
||||
}
|
@ -4,55 +4,79 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.test.antennapod.EspressoTestUtils;
|
||||
import de.test.antennapod.IgnoreOnCi;
|
||||
import de.test.antennapod.ui.UITestUtils;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasMinimumChildCount;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static de.test.antennapod.EspressoTestUtils.clickChildViewWithId;
|
||||
import static de.test.antennapod.EspressoTestUtils.onDrawerItem;
|
||||
import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
|
||||
import static de.test.antennapod.EspressoTestUtils.waitForView;
|
||||
import static de.test.antennapod.NthMatcher.first;
|
||||
import static de.test.antennapod.NthMatcher.nth;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
|
||||
*/
|
||||
public abstract class PlaybackTest {
|
||||
|
||||
@LargeTest
|
||||
@IgnoreOnCi
|
||||
@RunWith(Parameterized.class)
|
||||
public class PlaybackTest {
|
||||
@Rule
|
||||
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class, false, false);
|
||||
|
||||
@Parameterized.Parameter(value = 0)
|
||||
public String playerToUse;
|
||||
private UITestUtils uiTestUtils;
|
||||
protected Context context;
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
public static Collection<Object[]> initParameters() {
|
||||
return Arrays.asList(new Object[][] { { "exoplayer" }, { "builtin" }, { "sonic" } });
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
context = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
@ -60,6 +84,9 @@ public abstract class PlaybackTest {
|
||||
EspressoTestUtils.clearDatabase();
|
||||
EspressoTestUtils.makeNotFirstRun();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
prefs.edit().putString(UserPreferences.PREF_MEDIA_PLAYER, playerToUse).apply();
|
||||
|
||||
uiTestUtils = new UITestUtils(context);
|
||||
uiTestUtils.setup();
|
||||
}
|
||||
@ -67,10 +94,8 @@ public abstract class PlaybackTest {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
activityTestRule.finishActivity();
|
||||
EspressoTestUtils.tryKillPlaybackService();
|
||||
uiTestUtils.tearDown();
|
||||
// shut down playback service
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||
Awaitility.await().until(() -> !PlaybackService.isRunning);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -78,23 +103,9 @@ public abstract class PlaybackTest {
|
||||
setContinuousPlaybackPreference(false);
|
||||
uiTestUtils.addLocalFeedData(true);
|
||||
activityTestRule.launchActivity(new Intent());
|
||||
List<FeedItem> queue = DBReader.getQueue();
|
||||
final FeedItem first = queue.get(0);
|
||||
playFromQueue(0);
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getPlaybackController(getActivity()).getStatus()
|
||||
!= PlayerStatus.PLAYING) {
|
||||
return true;
|
||||
} else if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId()
|
||||
!= first.getMedia().getId();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(1000);
|
||||
assertNotEquals(PlayerStatus.PLAYING, uiTestUtils.getPlaybackController(getActivity()).getStatus());
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(
|
||||
() -> uiTestUtils.getPlaybackController(getActivity()).getStatus() == PlayerStatus.INITIALIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -108,22 +119,10 @@ public abstract class PlaybackTest {
|
||||
final FeedItem second = queue.get(1);
|
||||
|
||||
playFromQueue(0);
|
||||
Awaitility.await().atMost(2, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId()
|
||||
== first.getMedia().getId();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId()
|
||||
== second.getMedia().getId();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Awaitility.await().atMost(2, TimeUnit.SECONDS).until(
|
||||
() -> first.getMedia().equals(uiTestUtils.getCurrentMedia()));
|
||||
Awaitility.await().atMost(6, TimeUnit.SECONDS).until(
|
||||
() -> second.getMedia().equals(uiTestUtils.getCurrentMedia()));
|
||||
}
|
||||
|
||||
|
||||
@ -213,33 +212,27 @@ public abstract class PlaybackTest {
|
||||
}
|
||||
|
||||
private void skipEpisode() {
|
||||
Intent skipIntent = new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
|
||||
context.sendBroadcast(skipIntent);
|
||||
IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
|
||||
}
|
||||
|
||||
protected void pauseEpisode() {
|
||||
Intent pauseIntent = new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
|
||||
context.sendBroadcast(pauseIntent);
|
||||
IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
|
||||
}
|
||||
|
||||
protected void startLocalPlayback() {
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(R.string.episodes_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.emptyViewTitle), 1000));
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.all_episodes_short_label), 1000));
|
||||
onView(withText(R.string.all_episodes_short_label)).perform(click());
|
||||
|
||||
final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.butSecondaryAction), 1000));
|
||||
Matcher<View> allEpisodesMatcher = allOf(withId(android.R.id.list), isDisplayed(), hasMinimumChildCount(2));
|
||||
onView(isRoot()).perform(waitForView(allEpisodesMatcher, 1000));
|
||||
onView(allEpisodesMatcher).perform(actionOnItemAtPosition(0, clickChildViewWithId(R.id.butSecondaryAction)));
|
||||
|
||||
onView(first(withId(R.id.butSecondaryAction))).perform(click());
|
||||
long mediaId = episodes.get(0).getMedia().getId();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
FeedMedia media = episodes.get(0).getMedia();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(
|
||||
() -> media.equals(uiTestUtils.getCurrentMedia()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,16 +242,14 @@ public abstract class PlaybackTest {
|
||||
protected void playFromQueue(int itemIdx) {
|
||||
final List<FeedItem> queue = DBReader.getQueue();
|
||||
|
||||
onView(nth(withId(R.id.butSecondaryAction), itemIdx + 1)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.butPlay), 1000));
|
||||
long mediaId = queue.get(itemIdx).getMedia().getId();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Matcher<View> queueMatcher = allOf(withId(R.id.recyclerView), isDisplayed(), hasMinimumChildCount(2));
|
||||
onView(isRoot()).perform(waitForView(queueMatcher, 1000));
|
||||
onView(queueMatcher).perform(actionOnItemAtPosition(itemIdx, clickChildViewWithId(R.id.butSecondaryAction)));
|
||||
|
||||
FeedMedia media = queue.get(itemIdx).getMedia();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(
|
||||
() -> media.equals(uiTestUtils.getCurrentMedia()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,42 +263,36 @@ public abstract class PlaybackTest {
|
||||
final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
|
||||
|
||||
startLocalPlayback();
|
||||
long mediaId = episodes.get(0).getMedia().getId();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
FeedMedia media = episodes.get(0).getMedia();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(
|
||||
() -> media.equals(uiTestUtils.getCurrentMedia()));
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() ->
|
||||
uiTestUtils.getCurrentMedia(getActivity()) == null
|
||||
|| uiTestUtils.getCurrentMedia(getActivity()).getId() != mediaId);
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(
|
||||
() -> !media.equals(uiTestUtils.getCurrentMedia()));
|
||||
|
||||
startLocalPlayback();
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
|
||||
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
|
||||
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(
|
||||
() -> media.equals(uiTestUtils.getCurrentMedia()));
|
||||
}
|
||||
|
||||
protected void doTestSmartMarkAsPlayed_Skip_ForEpisode(int itemIdxNegAllowed) throws Exception {
|
||||
setSmartMarkAsPlayedPreference(60);
|
||||
// ensure when an episode is skipped, it is removed due to smart as played
|
||||
setSkipKeepsEpisodePreference(false);
|
||||
uiTestUtils.setMediaFileName("30sec.mp3");
|
||||
uiTestUtils.addLocalFeedData(true);
|
||||
|
||||
LongList queue = DBReader.getQueueIDList();
|
||||
int fiIdx;
|
||||
if (itemIdxNegAllowed >= 0) {
|
||||
fiIdx = itemIdxNegAllowed;
|
||||
} else { // negative index: count from the end, with -1 being the last one, etc.
|
||||
fiIdx = DBReader.getQueue().size() + itemIdxNegAllowed;
|
||||
fiIdx = queue.size() + itemIdxNegAllowed;
|
||||
}
|
||||
final FeedItem feedItem = DBReader.getQueue().get(fiIdx);
|
||||
final long feedItemId = queue.get(fiIdx);
|
||||
queue.removeIndex(fiIdx);
|
||||
assertFalse(queue.contains(feedItemId)); // Verify that episode is in queue only once
|
||||
|
||||
activityTestRule.launchActivity(new Intent());
|
||||
playFromQueue(fiIdx);
|
||||
@ -316,8 +301,8 @@ public abstract class PlaybackTest {
|
||||
|
||||
// assert item no longer in queue (needs to wait till skip is asynchronously processed)
|
||||
Awaitility.await()
|
||||
.atMost(1000, MILLISECONDS)
|
||||
.until(() -> !DBReader.getQueue().contains(feedItem));
|
||||
assertTrue(DBReader.getFeedItem(feedItem.getId()).isPlayed());
|
||||
.atMost(5000, MILLISECONDS)
|
||||
.until(() -> !DBReader.getQueueIDList().contains(feedItemId));
|
||||
assertTrue(DBReader.getFeedItem(feedItemId).isPlayed());
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package de.test.antennapod.service.download;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import de.test.antennapod.EspressoTestUtils;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.awaitility.core.ConditionTimeoutException;
|
||||
import org.junit.After;
|
||||
@ -53,6 +56,8 @@ public class DownloadServiceTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
EspressoTestUtils.clearDatabase();
|
||||
EspressoTestUtils.clearPreferences();
|
||||
origFactory = DownloadService.getDownloaderFactory();
|
||||
testFeed = setUpTestFeeds();
|
||||
testMedia11 = testFeed.getItemAtIndex(0).getMedia();
|
||||
@ -77,6 +82,10 @@ public class DownloadServiceTest {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
DownloadService.setDownloaderFactory(origFactory);
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
DownloadRequester.getInstance().cancelAllDownloads(context);
|
||||
context.stopService(new Intent(context, DownloadService.class));
|
||||
EspressoTestUtils.tryKillDownloadService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -136,8 +145,9 @@ public class DownloadServiceTest {
|
||||
}
|
||||
|
||||
private void doTestCancelDownload_UndoEnqueue(boolean itemAlreadyInQueue) throws Exception {
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
// let download takes longer to ensure the test can cancel the download in time
|
||||
DownloadService.setDownloaderFactory(new StubDownloaderFactory(150, downloadStatus -> {
|
||||
DownloadService.setDownloaderFactory(new StubDownloaderFactory(10000, downloadStatus -> {
|
||||
downloadStatus.setSuccessful();
|
||||
}));
|
||||
UserPreferences.setEnqueueDownloadedEpisodes(true);
|
||||
@ -146,45 +156,38 @@ public class DownloadServiceTest {
|
||||
final long item1Id = testMedia11.getItem().getId();
|
||||
if (itemAlreadyInQueue) {
|
||||
// simulate item already in queue condition
|
||||
DBWriter.addQueueItem(InstrumentationRegistry.getTargetContext(), false, item1Id).get();
|
||||
DBWriter.addQueueItem(context, false, item1Id).get();
|
||||
assertTrue(DBReader.getQueueIDList().contains(item1Id));
|
||||
} else {
|
||||
assertFalse(DBReader.getQueueIDList().contains(item1Id));
|
||||
}
|
||||
|
||||
withFeedItemEventListener(feedItemEventListener -> {
|
||||
try {
|
||||
DownloadRequester.getInstance().downloadMedia(false, InstrumentationRegistry.getTargetContext(),
|
||||
testMedia11.getItem());
|
||||
if (itemAlreadyInQueue) {
|
||||
Awaitility.await("download service receives the request - "
|
||||
+ "no event is expected before cancel is issued")
|
||||
.atLeast(100, TimeUnit.MILLISECONDS)
|
||||
.until(() -> true);
|
||||
} else {
|
||||
Awaitility.await("item enqueue event")
|
||||
.atMost(1000, TimeUnit.MILLISECONDS)
|
||||
.until(() -> feedItemEventListener.getEvents().size() >= 1);
|
||||
}
|
||||
DownloadRequester.getInstance().cancelDownload(InstrumentationRegistry.getTargetContext(),
|
||||
testMedia11);
|
||||
final int totalNumEventsExpected = itemAlreadyInQueue ? 1 : 3;
|
||||
Awaitility.await("item dequeue event + download termination event")
|
||||
.atMost(1000, TimeUnit.MILLISECONDS)
|
||||
.until(() ->feedItemEventListener.getEvents().size() >= totalNumEventsExpected);
|
||||
assertFalse("The download should have been canceled",
|
||||
DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
|
||||
if (itemAlreadyInQueue) {
|
||||
assertTrue("The FeedItem should still be in the queue after the download is cancelled."
|
||||
+ " It's there before download.",
|
||||
DBReader.getQueueIDList().contains(item1Id));
|
||||
} else {
|
||||
assertFalse("The FeedItem should not be in the queue after the download is cancelled.",
|
||||
DBReader.getQueueIDList().contains(item1Id));
|
||||
}
|
||||
} catch (ConditionTimeoutException cte) {
|
||||
fail("The expected FeedItemEvent (for media download complete) has not been posted. "
|
||||
+ cte.getMessage());
|
||||
DownloadRequester.getInstance().downloadMedia(false, context, testMedia11.getItem());
|
||||
if (itemAlreadyInQueue) {
|
||||
Awaitility.await("download service receives the request - "
|
||||
+ "no event is expected before cancel is issued")
|
||||
.atLeast(100, TimeUnit.MILLISECONDS)
|
||||
.until(() -> true);
|
||||
} else {
|
||||
Awaitility.await("item enqueue event")
|
||||
.atMost(2000, TimeUnit.MILLISECONDS)
|
||||
.until(() -> feedItemEventListener.getEvents().size() >= 1);
|
||||
}
|
||||
DownloadRequester.getInstance().cancelDownload(context, testMedia11);
|
||||
final int totalNumEventsExpected = itemAlreadyInQueue ? 1 : 3;
|
||||
Awaitility.await("item dequeue event + download termination event")
|
||||
.atMost(1000, TimeUnit.MILLISECONDS)
|
||||
.until(() -> feedItemEventListener.getEvents().size() >= totalNumEventsExpected);
|
||||
assertFalse("The download should have been canceled",
|
||||
DBReader.getFeedMedia(testMedia11.getId()).isDownloaded());
|
||||
if (itemAlreadyInQueue) {
|
||||
assertTrue("The FeedItem should still be in the queue after the download is cancelled."
|
||||
+ " It's there before download.",
|
||||
DBReader.getQueueIDList().contains(item1Id));
|
||||
} else {
|
||||
assertFalse("The FeedItem should not be in the queue after the download is cancelled.",
|
||||
DBReader.getQueueIDList().contains(item1Id));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -29,10 +29,9 @@ public class HttpDownloaderTest {
|
||||
private static final String TAG = "HttpDownloaderTest";
|
||||
private static final String DOWNLOAD_DIR = "testdownloads";
|
||||
|
||||
private static boolean successful = true;
|
||||
|
||||
private String url404;
|
||||
private String urlAuth;
|
||||
private File destDir;
|
||||
|
||||
private HTTPBin httpServer;
|
||||
|
||||
public HttpDownloaderTest() {
|
||||
@ -57,6 +56,8 @@ public class HttpDownloaderTest {
|
||||
assertTrue(destDir.exists());
|
||||
httpServer = new HTTPBin();
|
||||
httpServer.start();
|
||||
url404 = httpServer.getBaseUrl() + "/status/404";
|
||||
urlAuth = httpServer.getBaseUrl() + "/basic-auth/user/passwd";
|
||||
}
|
||||
|
||||
private FeedFileImpl setupFeedFile(String downloadUrl, String title, boolean deleteExisting) {
|
||||
@ -88,33 +89,29 @@ public class HttpDownloaderTest {
|
||||
return downloader;
|
||||
}
|
||||
|
||||
|
||||
private static final String URL_404 = HTTPBin.BASE_URL + "/status/404";
|
||||
private static final String URL_AUTH = HTTPBin.BASE_URL + "/basic-auth/user/passwd";
|
||||
|
||||
@Test
|
||||
public void testPassingHttp() {
|
||||
download(HTTPBin.BASE_URL + "/status/200", "test200", true);
|
||||
download(httpServer.getBaseUrl() + "/status/200", "test200", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirect() {
|
||||
download(HTTPBin.BASE_URL + "/redirect/4", "testRedirect", true);
|
||||
download(httpServer.getBaseUrl() + "/redirect/4", "testRedirect", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGzip() {
|
||||
download(HTTPBin.BASE_URL + "/gzip/100", "testGzip", true);
|
||||
download(httpServer.getBaseUrl() + "/gzip/100", "testGzip", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404() {
|
||||
download(URL_404, "test404", false);
|
||||
download(url404, "test404", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancel() {
|
||||
final String url = HTTPBin.BASE_URL + "/delay/3";
|
||||
final String url = httpServer.getBaseUrl() + "/delay/3";
|
||||
FeedFileImpl feedFile = setupFeedFile(url, "delay", true);
|
||||
final Downloader downloader = new HttpDownloader(new DownloadRequest(feedFile.getFile_url(), url, "delay", 0, feedFile.getTypeAsInt()));
|
||||
Thread t = new Thread() {
|
||||
@ -139,7 +136,7 @@ public class HttpDownloaderTest {
|
||||
|
||||
@Test
|
||||
public void testDeleteOnFailShouldDelete() {
|
||||
Downloader downloader = download(URL_404, "testDeleteOnFailShouldDelete", false, true, null, null, true);
|
||||
Downloader downloader = download(url404, "testDeleteOnFailShouldDelete", false, true, null, null, true);
|
||||
assertFalse(new File(downloader.getDownloadRequest().getDestination()).exists());
|
||||
}
|
||||
|
||||
@ -149,18 +146,18 @@ public class HttpDownloaderTest {
|
||||
File dest = new File(destDir, filename);
|
||||
dest.delete();
|
||||
assertTrue(dest.createNewFile());
|
||||
Downloader downloader = download(URL_404, filename, false, false, null, null, false);
|
||||
Downloader downloader = download(url404, filename, false, false, null, null, false);
|
||||
assertTrue(new File(downloader.getDownloadRequest().getDestination()).exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationShouldSucceed() throws InterruptedException {
|
||||
download(URL_AUTH, "testAuthSuccess", true, true, "user", "passwd", true);
|
||||
download(urlAuth, "testAuthSuccess", true, true, "user", "passwd", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationShouldFail() {
|
||||
Downloader downloader = download(URL_AUTH, "testAuthSuccess", false, true, "user", "Wrong passwd", true);
|
||||
Downloader downloader = download(urlAuth, "testAuthSuccess", false, true, "user", "Wrong passwd", true);
|
||||
assertEquals(DownloadError.ERROR_UNAUTHORIZED, downloader.getResult().getReason());
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@ package de.test.antennapod.service.playback;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import de.test.antennapod.EspressoTestUtils;
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
@ -32,7 +32,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@ -45,13 +45,12 @@ import static org.junit.Assert.fail;
|
||||
*/
|
||||
@MediumTest
|
||||
public class PlaybackServiceMediaPlayerTest {
|
||||
private static final String PLAYABLE_FILE_URL = "http://127.0.0.1:" + HTTPBin.PORT + "/files/0";
|
||||
private static final String PLAYABLE_DEST_URL = "psmptestfile.mp3";
|
||||
private String PLAYABLE_LOCAL_URL = null;
|
||||
private static final int LATCH_TIMEOUT_SECONDS = 3;
|
||||
|
||||
private HTTPBin httpServer;
|
||||
|
||||
private String playableFileUrl;
|
||||
private volatile AssertionFailedError assertionError;
|
||||
|
||||
@After
|
||||
@ -67,10 +66,11 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
EspressoTestUtils.makeNotFirstRun();
|
||||
EspressoTestUtils.clearDatabase();
|
||||
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
|
||||
httpServer = new HTTPBin();
|
||||
httpServer.start();
|
||||
playableFileUrl = httpServer.getBaseUrl() + "/files/0";
|
||||
|
||||
File cacheDir = context.getExternalFilesDir("testFiles");
|
||||
if (cacheDir == null)
|
||||
@ -81,7 +81,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
assertTrue(cacheDir.canWrite());
|
||||
assertTrue(cacheDir.canRead());
|
||||
if (!dest.exists()) {
|
||||
InputStream i = InstrumentationRegistry.getContext().getAssets().open("3sec.mp3");
|
||||
InputStream i = getInstrumentation().getTargetContext().getAssets().open("3sec.mp3");
|
||||
OutputStream o = new FileOutputStream(new File(cacheDir, PLAYABLE_DEST_URL));
|
||||
IOUtils.copy(i, o);
|
||||
o.flush();
|
||||
@ -167,7 +167,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
|
||||
Playable p = writeTestPlayable(playableFileUrl, null);
|
||||
psmp.playMediaObject(p, true, false, false);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -207,7 +207,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
|
||||
Playable p = writeTestPlayable(playableFileUrl, null);
|
||||
psmp.playMediaObject(p, true, true, false);
|
||||
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
@ -251,7 +251,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
|
||||
Playable p = writeTestPlayable(playableFileUrl, null);
|
||||
psmp.playMediaObject(p, true, false, true);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -296,7 +296,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, null);
|
||||
Playable p = writeTestPlayable(playableFileUrl, null);
|
||||
psmp.playMediaObject(p, true, true, true);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -334,7 +334,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
psmp.playMediaObject(p, false, false, false);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -373,7 +373,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
psmp.playMediaObject(p, false, true, false);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -415,7 +415,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
psmp.playMediaObject(p, false, false, true);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -460,7 +460,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
psmp.playMediaObject(p, false, true, true);
|
||||
boolean res = countDownLatch.await(LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
if (assertionError != null)
|
||||
@ -523,7 +523,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
if (initialState == PlayerStatus.PLAYING) {
|
||||
psmp.playMediaObject(p, stream, true, true);
|
||||
}
|
||||
@ -616,7 +616,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
if (initialState == PlayerStatus.PREPARED || initialState == PlayerStatus.PLAYING || initialState == PlayerStatus.PAUSED) {
|
||||
boolean startWhenPrepared = (initialState != PlayerStatus.PREPARED);
|
||||
psmp.playMediaObject(writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL), false, startWhenPrepared, true);
|
||||
psmp.playMediaObject(writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL), false, startWhenPrepared, true);
|
||||
}
|
||||
if (initialState == PlayerStatus.PAUSED) {
|
||||
psmp.pause(false, false);
|
||||
@ -673,7 +673,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
if (initialState == PlayerStatus.INITIALIZED
|
||||
|| initialState == PlayerStatus.PLAYING
|
||||
|| initialState == PlayerStatus.PREPARED
|
||||
@ -747,7 +747,7 @@ public class PlaybackServiceMediaPlayerTest {
|
||||
}
|
||||
});
|
||||
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, callback);
|
||||
Playable p = writeTestPlayable(PLAYABLE_FILE_URL, PLAYABLE_LOCAL_URL);
|
||||
Playable p = writeTestPlayable(playableFileUrl, PLAYABLE_LOCAL_URL);
|
||||
boolean prepareImmediately = initialState != PlayerStatus.INITIALIZED;
|
||||
boolean startImmediately = initialState != PlayerStatus.PREPARED;
|
||||
psmp.playMediaObject(p, false, startImmediately, prepareImmediately);
|
||||
|
@ -7,6 +7,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import de.test.antennapod.EspressoTestUtils;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.awaitility.core.ConditionTimeoutException;
|
||||
import org.junit.After;
|
||||
@ -14,6 +16,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.DBTasksCallbacks;
|
||||
@ -49,21 +52,16 @@ public class AutoDownloadTest {
|
||||
|
||||
dbTasksCallbacksOrig = ClientConfig.dbTasksCallbacks;
|
||||
|
||||
// create new database
|
||||
PodDBAdapter.init(context);
|
||||
PodDBAdapter.deleteDatabase();
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.close();
|
||||
EspressoTestUtils.clearPreferences();
|
||||
EspressoTestUtils.clearDatabase();
|
||||
UserPreferences.setAllowMobileStreaming(true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
stubFeedsServer.tearDown();
|
||||
ClientConfig.dbTasksCallbacks = dbTasksCallbacksOrig;
|
||||
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||
Awaitility.await().until(() -> !PlaybackService.isRunning);
|
||||
EspressoTestUtils.tryKillPlaybackService();
|
||||
stubFeedsServer.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,7 +115,7 @@ public class AutoDownloadTest {
|
||||
FeedMedia media = item.getMedia();
|
||||
DBTasks.playMedia(context, media, false, true, true);
|
||||
Awaitility.await("episode is playing")
|
||||
.atMost(1000, MILLISECONDS)
|
||||
.atMost(2000, MILLISECONDS)
|
||||
.until(() -> item.equals(getCurrentlyPlaying()));
|
||||
}
|
||||
|
||||
@ -126,7 +124,7 @@ public class AutoDownloadTest {
|
||||
if (playable == null) {
|
||||
return null;
|
||||
}
|
||||
return ((FeedMedia)playable).getItem();
|
||||
return ((FeedMedia) playable).getItem();
|
||||
}
|
||||
|
||||
private void useDownloadAlgorithm(final AutomaticDownloadAlgorithm downloadAlgorithm) {
|
||||
|
@ -29,10 +29,12 @@ import static androidx.test.espresso.contrib.ActivityResultMatchers.hasResultCod
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.Intents.times;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static de.test.antennapod.EspressoTestUtils.clickPreference;
|
||||
import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
|
||||
import static de.test.antennapod.EspressoTestUtils.waitForView;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@ -75,11 +77,11 @@ public class MainActivityTest {
|
||||
final Feed feed = uiTestUtils.hostedFeeds.get(0);
|
||||
openNavDrawer();
|
||||
onView(withText(R.string.add_feed_label)).perform(click());
|
||||
onView(withId(R.id.etxtFeedurl)).perform(typeText(feed.getDownload_url()));
|
||||
onView(withText(R.string.confirm_label)).perform(scrollTo()).perform(click());
|
||||
onView(withId(R.id.etxtFeedurl)).perform(scrollTo(), typeText(feed.getDownload_url()));
|
||||
onView(withText(R.string.confirm_label)).perform(scrollTo(), click());
|
||||
Espresso.closeSoftKeyboard();
|
||||
onView(withText(R.string.subscribe_label)).perform(click());
|
||||
intended(hasComponent(MainActivity.class.getName()), times(2));
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.butShowSettings), 5000));
|
||||
}
|
||||
|
||||
private String getActionbarTitle() {
|
||||
|
@ -32,6 +32,7 @@ import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.action.ViewActions.scrollTo;
|
||||
import static androidx.test.espresso.action.ViewActions.swipeDown;
|
||||
import static androidx.test.espresso.action.ViewActions.swipeUp;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
@ -246,10 +247,10 @@ public class PreferencesTest {
|
||||
public void testPauseForInterruptions() {
|
||||
onView(withText(R.string.playback_pref)).perform(click());
|
||||
final boolean pauseForFocusLoss = UserPreferences.shouldPauseForFocusLoss();
|
||||
onView(withText(R.string.pref_pausePlaybackForFocusLoss_title)).perform(click());
|
||||
clickPreference(R.string.pref_pausePlaybackForFocusLoss_title);
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> pauseForFocusLoss != UserPreferences.shouldPauseForFocusLoss());
|
||||
onView(withText(R.string.pref_pausePlaybackForFocusLoss_title)).perform(click());
|
||||
clickPreference(R.string.pref_pausePlaybackForFocusLoss_title);
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> pauseForFocusLoss == UserPreferences.shouldPauseForFocusLoss());
|
||||
}
|
||||
@ -332,7 +333,8 @@ public class PreferencesTest {
|
||||
clickPreference(R.string.network_pref);
|
||||
clickPreference(R.string.pref_automatic_download_title);
|
||||
clickPreference(R.string.pref_episode_cache_title);
|
||||
onView(withText(minEntry)).perform(scrollTo()).perform(click());
|
||||
onView(withId(R.id.select_dialog_listview)).perform(swipeDown());
|
||||
onView(withText(minEntry)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> UserPreferences.getEpisodeCacheSize() == minValue);
|
||||
}
|
||||
@ -346,6 +348,7 @@ public class PreferencesTest {
|
||||
onView(withText(R.string.network_pref)).perform(click());
|
||||
onView(withText(R.string.pref_automatic_download_title)).perform(click());
|
||||
onView(withText(R.string.pref_episode_cache_title)).perform(click());
|
||||
onView(withId(R.id.select_dialog_listview)).perform(swipeUp());
|
||||
onView(withText(maxEntry)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> UserPreferences.getEpisodeCacheSize() == maxValue);
|
||||
@ -365,17 +368,17 @@ public class PreferencesTest {
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(UserPreferences::isEnableAutodownload);
|
||||
final boolean enableAutodownloadOnBattery = UserPreferences.isEnableAutodownloadOnBattery();
|
||||
onView(withText(R.string.pref_automatic_download_on_battery_title)).perform(click());
|
||||
clickPreference(R.string.pref_automatic_download_on_battery_title);
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> enableAutodownloadOnBattery != UserPreferences.isEnableAutodownloadOnBattery());
|
||||
onView(withText(R.string.pref_automatic_download_on_battery_title)).perform(click());
|
||||
clickPreference(R.string.pref_automatic_download_on_battery_title);
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> enableAutodownloadOnBattery == UserPreferences.isEnableAutodownloadOnBattery());
|
||||
final boolean enableWifiFilter = UserPreferences.isEnableAutodownloadWifiFilter();
|
||||
onView(withText(R.string.pref_autodl_wifi_filter_title)).perform(click());
|
||||
clickPreference(R.string.pref_autodl_wifi_filter_title);
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> enableWifiFilter != UserPreferences.isEnableAutodownloadWifiFilter());
|
||||
onView(withText(R.string.pref_autodl_wifi_filter_title)).perform(click());
|
||||
clickPreference(R.string.pref_autodl_wifi_filter_title);
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> enableWifiFilter == UserPreferences.isEnableAutodownloadWifiFilter());
|
||||
}
|
||||
@ -425,7 +428,7 @@ public class PreferencesTest {
|
||||
clickPreference(R.string.network_pref);
|
||||
clickPreference(R.string.pref_automatic_download_title);
|
||||
clickPreference(R.string.pref_episode_cleanup_title);
|
||||
String search = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, 5, 5);
|
||||
String search = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, 3, 3);
|
||||
onView(isRoot()).perform(waitForView(withText(search), 1000));
|
||||
onView(withText(search)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
@ -433,7 +436,7 @@ public class PreferencesTest {
|
||||
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
|
||||
if (alg instanceof APCleanupAlgorithm) {
|
||||
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm) alg;
|
||||
return cleanupAlg.getNumberOfHoursAfterPlayback() == 120; // 5 days
|
||||
return cleanupAlg.getNumberOfHoursAfterPlayback() == 72; // 5 days
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -11,11 +11,11 @@ import de.danoeh.antennapod.activity.AudioplayerActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import de.test.antennapod.EspressoTestUtils;
|
||||
import de.test.antennapod.IgnoreOnCi;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -39,6 +39,7 @@ import static de.test.antennapod.EspressoTestUtils.waitForView;
|
||||
* User interface tests for changing the playback speed.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@IgnoreOnCi
|
||||
public class SpeedChangeTest {
|
||||
|
||||
@Rule
|
||||
@ -68,9 +69,7 @@ public class SpeedChangeTest {
|
||||
UserPreferences.setPlaybackSpeedArray(new String[] {"1.00", "2.00", "3.00"});
|
||||
availableSpeeds = UserPreferences.getPlaybackSpeedArray();
|
||||
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||
Awaitility.await().until(() -> !PlaybackService.isRunning);
|
||||
|
||||
EspressoTestUtils.tryKillPlaybackService();
|
||||
activityRule.launchActivity(new Intent());
|
||||
}
|
||||
|
||||
@ -88,7 +87,7 @@ public class SpeedChangeTest {
|
||||
public void testChangeSpeedPlaying() {
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.butPlay), 1000));
|
||||
onView(withId(R.id.butPlay)).perform(click());
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(()
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(()
|
||||
-> activityRule.getActivity().getPlaybackController().getStatus() == PlayerStatus.PLAYING);
|
||||
clickThroughSpeeds();
|
||||
}
|
||||
@ -97,10 +96,10 @@ public class SpeedChangeTest {
|
||||
public void testChangeSpeedPaused() {
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.butPlay), 1000));
|
||||
onView(withId(R.id.butPlay)).perform(click());
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(()
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(()
|
||||
-> activityRule.getActivity().getPlaybackController().getStatus() == PlayerStatus.PLAYING);
|
||||
onView(withId(R.id.butPlay)).perform(click());
|
||||
Awaitility.await().atMost(1, TimeUnit.SECONDS).until(()
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(()
|
||||
-> activityRule.getActivity().getPlaybackController().getStatus() == PlayerStatus.PAUSED);
|
||||
clickThroughSpeeds();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -87,13 +88,13 @@ public class UITestUtils {
|
||||
out.close();
|
||||
int id = server.serveFile(feedFile);
|
||||
Assert.assertTrue(id != -1);
|
||||
return String.format("%s/files/%d", HTTPBin.BASE_URL, id);
|
||||
return String.format("%s/files/%d", server.getBaseUrl(), id);
|
||||
}
|
||||
|
||||
private String hostFile(File file) {
|
||||
int id = server.serveFile(file);
|
||||
Assert.assertTrue(id != -1);
|
||||
return String.format("%s/files/%d", HTTPBin.BASE_URL, id);
|
||||
return String.format("%s/files/%d", server.getBaseUrl(), id);
|
||||
}
|
||||
|
||||
private File newBitmapFile(String name) throws IOException {
|
||||
@ -204,12 +205,14 @@ public class UITestUtils {
|
||||
}
|
||||
|
||||
public PlaybackController getPlaybackController(MainActivity mainActivity) {
|
||||
ExternalPlayerFragment fragment = (ExternalPlayerFragment)mainActivity.getSupportFragmentManager().findFragmentByTag(ExternalPlayerFragment.TAG);
|
||||
ExternalPlayerFragment fragment = (ExternalPlayerFragment) mainActivity.getSupportFragmentManager()
|
||||
.findFragmentByTag(ExternalPlayerFragment.TAG);
|
||||
return fragment.getPlaybackControllerTestingOnly();
|
||||
}
|
||||
|
||||
public FeedMedia getCurrentMedia(MainActivity mainActivity) {
|
||||
return (FeedMedia)getPlaybackController(mainActivity).getMedia();
|
||||
public FeedMedia getCurrentMedia() {
|
||||
Playable playable = Playable.PlayableUtils.createInstanceFromPreferences(context);
|
||||
return (FeedMedia) playable;
|
||||
}
|
||||
|
||||
public void setMediaFileName(String filename) {
|
||||
|
@ -39,9 +39,6 @@ import de.danoeh.antennapod.BuildConfig;
|
||||
*/
|
||||
public class HTTPBin extends NanoHTTPD {
|
||||
private static final String TAG = "HTTPBin";
|
||||
public static final int PORT = 8124;
|
||||
public static final String BASE_URL = "http://127.0.0.1:" + HTTPBin.PORT;
|
||||
|
||||
|
||||
private static final String MIME_HTML = "text/html";
|
||||
private static final String MIME_PLAIN = "text/plain";
|
||||
@ -49,10 +46,14 @@ public class HTTPBin extends NanoHTTPD {
|
||||
private final List<File> servedFiles;
|
||||
|
||||
public HTTPBin() {
|
||||
super(PORT);
|
||||
super(0); // Let system pick a free port
|
||||
this.servedFiles = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return "http://127.0.0.1:" + getListeningPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given file to the server.
|
||||
*
|
||||
|
@ -215,7 +215,7 @@ public class DownloadService extends Service {
|
||||
|
||||
downloadCompletionThread.interrupt();
|
||||
try {
|
||||
downloadCompletionThread.join();
|
||||
downloadCompletionThread.join(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -985,23 +985,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
}
|
||||
|
||||
if (item != null) {
|
||||
if (ended || smartMarkAsPlayed ||
|
||||
(skipped && !UserPreferences.shouldSkipKeepEpisode())) {
|
||||
if (ended || smartMarkAsPlayed
|
||||
|| (skipped && !UserPreferences.shouldSkipKeepEpisode())) {
|
||||
// only mark the item as played if we're not keeping it anyways
|
||||
DBWriter.markItemPlayed(item, FeedItem.PLAYED, ended);
|
||||
try {
|
||||
final List<FeedItem> queue = taskManager.getQueue();
|
||||
if (QueueAccess.ItemListAccess(queue).contains(item.getId())) {
|
||||
// don't know if it actually matters to not autodownload when smart mark as played is triggered
|
||||
DBWriter.removeQueueItem(PlaybackService.this, ended, item);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
// isInQueue remains false
|
||||
}
|
||||
// don't know if it actually matters to not autodownload when smart mark as played is triggered
|
||||
DBWriter.removeQueueItem(PlaybackService.this, ended, item);
|
||||
// Delete episode if enabled
|
||||
if (item.getFeed().getPreferences().getCurrentAutoDelete() &&
|
||||
(!item.isTagged(FeedItem.TAG_FAVORITE) || !UserPreferences.shouldFavoriteKeepEpisode())) {
|
||||
if (item.getFeed().getPreferences().getCurrentAutoDelete()
|
||||
&& (!item.isTagged(FeedItem.TAG_FAVORITE) || !UserPreferences.shouldFavoriteKeepEpisode())) {
|
||||
DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId());
|
||||
Log.d(TAG, "Episode Deleted");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user