Refactored unit tests (#643)

* Removed redundant configureHostInfo
  It was only used to set the Kodi backend version which is also
  set using setKodiMajorVersion.

* Removed unused annotations and throwables

* Improved robustness of SlideUpPanelTests
  Replaced explicit sleeps with the waitForView action.
  Fixed issue in waitForView action as it required the UI
  to be idle which is mostly not the case for the bottom
  panel with the progress indicator.

* Improved robustness of eventserver
  When eventserver handles a wrong payload this should not crash
  but simply show a log message and let the actual test fail.
This commit is contained in:
Martijn Brekhof 2019-06-11 09:47:11 +02:00 committed by Synced Synapse
parent e5ab122b1d
commit d1d8412654
14 changed files with 51 additions and 105 deletions

View File

@ -22,7 +22,6 @@ import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.MotionEvents; import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.action.Press; import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.ScrollToAction;
import android.support.test.espresso.util.HumanReadables; import android.support.test.espresso.util.HumanReadables;
import android.support.test.espresso.util.TreeIterables; import android.support.test.espresso.util.TreeIterables;
import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerAdapter;
@ -92,7 +91,6 @@ public final class ViewActions {
@Override @Override
public void perform(UiController uiController, View view) { public void perform(UiController uiController, View view) {
uiController.loopMainThreadUntilIdle();
final long endTime = System.currentTimeMillis() + millis; final long endTime = System.currentTimeMillis() + millis;
do { do {
for (View child : TreeIterables.breadthFirstViewTraversal(view)) { for (View child : TreeIterables.breadthFirstViewTraversal(view)) {

View File

@ -62,12 +62,6 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
*/ */
abstract protected void setSharedPreferences(Context context); abstract protected void setSharedPreferences(Context context);
/**
* Called from {@link #setUp()} right after HostInfo has been created.
* @param hostInfo created HostInfo used by the activity under test
*/
abstract protected void configureHostInfo(HostInfo hostInfo);
private LoaderIdlingResource loaderIdlingResource; private LoaderIdlingResource loaderIdlingResource;
private ActivityTestRule<T> activityTestRule; private ActivityTestRule<T> activityTestRule;
private static MockTcpServer server; private static MockTcpServer server;
@ -114,8 +108,6 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
hostInfo = Database.addHost(context, server.getHostName(), hostInfo = Database.addHost(context, server.getHostName(),
HostConnection.PROTOCOL_TCP, HostInfo.DEFAULT_HTTP_PORT, HostConnection.PROTOCOL_TCP, HostInfo.DEFAULT_HTTP_PORT,
server.getPort(), useEventServer, kodiMajorVersion); server.getPort(), useEventServer, kodiMajorVersion);
//Allow each test to change the host info
configureHostInfo(hostInfo);
loaderIdlingResource = new LoaderIdlingResource(activityTestRule.getActivity().getSupportLoaderManager()); loaderIdlingResource = new LoaderIdlingResource(activityTestRule.getActivity().getSupportLoaderManager());
IdlingRegistry.getInstance().register(loaderIdlingResource); IdlingRegistry.getInstance().register(loaderIdlingResource);

View File

@ -79,11 +79,6 @@ public class AddonsActivityTests extends AbstractTestClass<AddonsActivity> {
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
@Before @Before
public void setUp() throws Throwable { public void setUp() throws Throwable {
super.setUp(); super.setUp();

View File

@ -58,11 +58,6 @@ public class MoviesActivityTests extends AbstractTestClass<MoviesActivity> {
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
/** /**
* Test if action bar title initially displays Movies * Test if action bar title initially displays Movies
*/ */

View File

@ -18,7 +18,6 @@ package org.xbmc.kore.tests.ui.movies;
import android.content.Context; import android.content.Context;
import android.support.test.espresso.Espresso; import android.support.test.espresso.Espresso;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule; import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
@ -26,13 +25,11 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.xbmc.kore.R; import org.xbmc.kore.R;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.testhelpers.EspressoTestUtils; import org.xbmc.kore.testhelpers.EspressoTestUtils;
import org.xbmc.kore.tests.ui.AbstractTestClass; import org.xbmc.kore.tests.ui.AbstractTestClass;
import org.xbmc.kore.ui.sections.video.MoviesActivity; import org.xbmc.kore.ui.sections.video.MoviesActivity;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@LargeTest
public class RestoreSearchQueryListFragmentTest extends AbstractTestClass<MoviesActivity> { public class RestoreSearchQueryListFragmentTest extends AbstractTestClass<MoviesActivity> {
private final String SEARCH_QUERY = "Room"; private final String SEARCH_QUERY = "Room";
@ -53,11 +50,6 @@ public class RestoreSearchQueryListFragmentTest extends AbstractTestClass<Movies
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
/** /**
* Simple test that checks if search query results in expected item(s) * Simple test that checks if search query results in expected item(s)
*/ */

View File

@ -62,11 +62,6 @@ public class MusicActivityTests extends AbstractTestClass<MusicActivity> {
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
/** /**
* Test if action bar title initially displays Music * Test if action bar title initially displays Music
*/ */

View File

@ -19,7 +19,6 @@ package org.xbmc.kore.tests.ui.music;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.support.test.espresso.Espresso; import android.support.test.espresso.Espresso;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule; import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
@ -27,7 +26,6 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.xbmc.kore.R; import org.xbmc.kore.R;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.testhelpers.EspressoTestUtils; import org.xbmc.kore.testhelpers.EspressoTestUtils;
import org.xbmc.kore.testhelpers.LoaderIdlingResource; import org.xbmc.kore.testhelpers.LoaderIdlingResource;
import org.xbmc.kore.tests.ui.AbstractTestClass; import org.xbmc.kore.tests.ui.AbstractTestClass;
@ -37,7 +35,6 @@ import static org.xbmc.kore.testhelpers.EspressoTestUtils.clickAlbumsTab;
import static org.xbmc.kore.testhelpers.EspressoTestUtils.clickArtistsTab; import static org.xbmc.kore.testhelpers.EspressoTestUtils.clickArtistsTab;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@LargeTest
public class RestoreSearchQueryViewPagerTest extends AbstractTestClass<MusicActivity> { public class RestoreSearchQueryViewPagerTest extends AbstractTestClass<MusicActivity> {
private final String ARTIST_SEARCH_QUERY = "Ben"; private final String ARTIST_SEARCH_QUERY = "Ben";
@ -64,11 +61,6 @@ public class RestoreSearchQueryViewPagerTest extends AbstractTestClass<MusicActi
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
/** /**
* Simple test that checks if search query results in expected item(s) * Simple test that checks if search query results in expected item(s)
* *

View File

@ -32,7 +32,6 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.xbmc.kore.R; import org.xbmc.kore.R;
import org.xbmc.kore.Settings; import org.xbmc.kore.Settings;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.testhelpers.Utils; import org.xbmc.kore.testhelpers.Utils;
import org.xbmc.kore.testhelpers.action.ViewActions; import org.xbmc.kore.testhelpers.action.ViewActions;
import org.xbmc.kore.tests.ui.AbstractTestClass; import org.xbmc.kore.tests.ui.AbstractTestClass;
@ -75,11 +74,6 @@ public class SlideUpPanelTests extends AbstractTestClass<MusicActivity> {
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
@Override @Override
public void setUp() throws Throwable { public void setUp() throws Throwable {
super.setUp(); super.setUp();
@ -409,7 +403,12 @@ public class SlideUpPanelTests extends AbstractTestClass<MusicActivity> {
rotateDevice(getActivity()); rotateDevice(getActivity());
onView(withId(R.id.vli_seek_bar)).check(matches(withProgress(volume))); onView(isRoot()).perform(ViewActions.waitForView(R.id.vli_seek_bar, new ViewActions.CheckStatus() {
@Override
public boolean check(View v) {
return ((SeekBar) v).getProgress() == volume;
}
}, 10000));
onView(withId(R.id.vli_volume_text)).check(matches(withText(String.valueOf(volume)))); onView(withId(R.id.vli_volume_text)).check(matches(withText(String.valueOf(volume))));
assertTrue(getApplicationHandler().getVolume() == volume); assertTrue(getApplicationHandler().getVolume() == volume);
} }
@ -486,9 +485,14 @@ public class SlideUpPanelTests extends AbstractTestClass<MusicActivity> {
getPlayerHandler().startPlay(); getPlayerHandler().startPlay();
SeekBar seekBar = (SeekBar) getActivity().findViewById(R.id.mpi_seek_bar); SeekBar seekBar = (SeekBar) getActivity().findViewById(R.id.mpi_seek_bar);
int progress = seekBar.getProgress(); final int progress = seekBar.getProgress();
SystemClock.sleep(1000); //wait one second to check if progression has indeed progressed onView(isRoot()).perform(ViewActions.waitForView(
assertTrue(seekBar.getProgress() > progress); R.id.mpi_seek_bar, new ViewActions.CheckStatus() {
@Override
public boolean check(View v) {
return ((SeekBar) v).getProgress() > progress;
}
}, 10000));
} }
/** /**
@ -502,11 +506,15 @@ public class SlideUpPanelTests extends AbstractTestClass<MusicActivity> {
public void progressionUpdaterStartedAfterPlay() { public void progressionUpdaterStartedAfterPlay() {
expandPanel(); expandPanel();
SeekBar seekBar = (SeekBar) getActivity().findViewById(R.id.mpi_seek_bar); SeekBar seekBar = (SeekBar) getActivity().findViewById(R.id.mpi_seek_bar);
int progress = seekBar.getProgress(); final int progress = seekBar.getProgress();
SystemClock.sleep(1000); //wait one second to check if progression has indeed progressed onView(isRoot()).perform(ViewActions.waitForView(
R.id.mpi_seek_bar, new ViewActions.CheckStatus() {
assertTrue(seekBar.getProgress() > progress); @Override
public boolean check(View v) {
return ((SeekBar) v).getProgress() > progress;
}
}, 10000));
} }
/** /**

View File

@ -37,8 +37,6 @@ import org.xbmc.kore.testutils.eventserver.EventPacketBUTTON;
import org.xbmc.kore.testutils.eventserver.MockEventServer; import org.xbmc.kore.testutils.eventserver.MockEventServer;
import org.xbmc.kore.ui.sections.remote.RemoteActivity; import org.xbmc.kore.ui.sections.remote.RemoteActivity;
import java.io.IOException;
import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick; import static android.support.test.espresso.action.ViewActions.longClick;
@ -62,13 +60,8 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
Utils.setUseEventServerPreference(context, true); Utils.setUseEventServerPreference(context, true);
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
@BeforeClass @BeforeClass
public static void setupEventServer() throws Throwable { public static void setupEventServer() {
mockEventServer = new MockEventServer(); mockEventServer = new MockEventServer();
mockEventServer.setListenPort(HostInfo.DEFAULT_EVENT_SERVER_PORT); mockEventServer.setListenPort(HostInfo.DEFAULT_EVENT_SERVER_PORT);
mockEventServer.start(); mockEventServer.start();
@ -86,40 +79,40 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
} }
@AfterClass @AfterClass
public static void cleanup() throws IOException { public static void cleanup() {
mockEventServer.shutdown(); mockEventServer.shutdown();
} }
@Test @Test
public void leftControlPadButtonTest() throws InterruptedException { public void leftControlPadButtonTest() {
onView(withId(R.id.left)).perform(click()); onView(withId(R.id.left)).perform(click());
testRemoteButton(ButtonCodes.REMOTE_LEFT); testRemoteButton(ButtonCodes.REMOTE_LEFT);
} }
@Test @Test
public void rightControlPadButtonTest() throws InterruptedException { public void rightControlPadButtonTest() {
onView(withId(R.id.right)).perform(click()); onView(withId(R.id.right)).perform(click());
testRemoteButton(ButtonCodes.REMOTE_RIGHT); testRemoteButton(ButtonCodes.REMOTE_RIGHT);
} }
@Test @Test
public void upControlPadButtonTest() throws InterruptedException { public void upControlPadButtonTest() {
onView(withId(R.id.up)).perform(click()); onView(withId(R.id.up)).perform(click());
testRemoteButton(ButtonCodes.REMOTE_UP); testRemoteButton(ButtonCodes.REMOTE_UP);
} }
@Test @Test
public void downControlPadButtonTest() throws InterruptedException { public void downControlPadButtonTest() {
onView(withId(R.id.down)).perform(click()); onView(withId(R.id.down)).perform(click());
testRemoteButton(ButtonCodes.REMOTE_DOWN); testRemoteButton(ButtonCodes.REMOTE_DOWN);
} }
@Test @Test
public void selectPadButtonTest() throws InterruptedException { public void selectPadButtonTest() {
onView(withId(R.id.select)).perform(click()); onView(withId(R.id.select)).perform(click());
testRemoteButton(ButtonCodes.REMOTE_SELECT); testRemoteButton(ButtonCodes.REMOTE_SELECT);
@ -128,14 +121,14 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
//The following tests do not use the event server. They're included here //The following tests do not use the event server. They're included here
//to make sure they still work when the event server is enabled. //to make sure they still work when the event server is enabled.
@Test @Test
public void contextControlPadButtonTest() throws InterruptedException { public void contextControlPadButtonTest() {
onView(withId(R.id.context)).perform(click()); onView(withId(R.id.context)).perform(click());
TestUtils.testHTTPEvent(Input.ExecuteAction.METHOD_NAME, Input.ExecuteAction.CONTEXTMENU); TestUtils.testHTTPEvent(Input.ExecuteAction.METHOD_NAME, Input.ExecuteAction.CONTEXTMENU);
} }
@Test @Test
public void infoControlPadButtonTest() throws InterruptedException { public void infoControlPadButtonTest() {
HostManager.getInstance(getActivity()).getHostInfo().setKodiVersionMajor(17); HostManager.getInstance(getActivity()).getHostInfo().setKodiVersionMajor(17);
onView(withId(R.id.info)).perform(click()); onView(withId(R.id.info)).perform(click());
@ -144,21 +137,21 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
} }
@Test @Test
public void infoControlPadButtonLongClickTest() throws InterruptedException { public void infoControlPadButtonLongClickTest() {
onView(withId(R.id.info)).perform(longClick()); onView(withId(R.id.info)).perform(longClick());
TestUtils.testHTTPEvent(Input.ExecuteAction.METHOD_NAME, Input.ExecuteAction.PLAYERPROCESSINFO); TestUtils.testHTTPEvent(Input.ExecuteAction.METHOD_NAME, Input.ExecuteAction.PLAYERPROCESSINFO);
} }
@Test @Test
public void osdControlPadButtonTest() throws InterruptedException { public void osdControlPadButtonTest() {
onView(withId(R.id.osd)).perform(click()); onView(withId(R.id.osd)).perform(click());
TestUtils.testHTTPEvent(Input.ExecuteAction.METHOD_NAME, Input.ExecuteAction.OSD); TestUtils.testHTTPEvent(Input.ExecuteAction.METHOD_NAME, Input.ExecuteAction.OSD);
} }
@Test @Test
public void backControlPadButtonTest() throws InterruptedException { public void backControlPadButtonTest() {
onView(withId(R.id.back)).perform(click()); onView(withId(R.id.back)).perform(click());
TestUtils.testHTTPEvent(Input.Back.METHOD_NAME, null); TestUtils.testHTTPEvent(Input.Back.METHOD_NAME, null);

View File

@ -33,8 +33,6 @@ import org.xbmc.kore.tests.ui.AbstractTestClass;
import org.xbmc.kore.testutils.eventserver.MockEventServer; import org.xbmc.kore.testutils.eventserver.MockEventServer;
import org.xbmc.kore.ui.sections.remote.RemoteActivity; import org.xbmc.kore.ui.sections.remote.RemoteActivity;
import java.io.IOException;
import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.longClick; import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withId;
@ -57,12 +55,8 @@ public class KodiPreV17Tests extends AbstractTestClass<RemoteActivity> {
Utils.setUseEventServerPreference(context, true); Utils.setUseEventServerPreference(context, true);
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
@BeforeClass @BeforeClass
public static void setupEventServer() throws Throwable { public static void setupEventServer() {
mockEventServer = new MockEventServer(); mockEventServer = new MockEventServer();
mockEventServer.setListenPort(HostInfo.DEFAULT_EVENT_SERVER_PORT); mockEventServer.setListenPort(HostInfo.DEFAULT_EVENT_SERVER_PORT);
mockEventServer.start(); mockEventServer.start();
@ -80,14 +74,12 @@ public class KodiPreV17Tests extends AbstractTestClass<RemoteActivity> {
} }
@AfterClass @AfterClass
public static void cleanup() throws IOException { public static void cleanup() {
mockEventServer.shutdown(); mockEventServer.shutdown();
} }
@Test @Test
public void infoControlPadButtonLongClickTest() throws InterruptedException { public void infoControlPadButtonLongClickTest() {
HostManager.getInstance(getActivity()).getHostInfo().setKodiVersionMajor(16);
onView(withId(R.id.info)).perform(longClick()); onView(withId(R.id.info)).perform(longClick());
String actionReceived = getInputHandler().getAction(); String actionReceived = getInputHandler().getAction();

View File

@ -50,10 +50,6 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
Utils.setUseEventServerPreference(context, false); Utils.setUseEventServerPreference(context, false);
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
@Override @Override
public void setUp() throws Throwable { public void setUp() throws Throwable {
setKodiMajorVersion(HostInfo.KODI_V17_KRYPTON); setKodiMajorVersion(HostInfo.KODI_V17_KRYPTON);

View File

@ -48,11 +48,6 @@ public class KodiPreV17Tests extends AbstractTestClass<RemoteActivity> {
Utils.setUseEventServerPreference(context, false); Utils.setUseEventServerPreference(context, false);
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
hostInfo.setKodiVersionMajor(16);
}
@Override @Override
public void setUp() throws Throwable { public void setUp() throws Throwable {
setKodiMajorVersion(HostInfo.KODI_V16_JARVIS); setKodiMajorVersion(HostInfo.KODI_V16_JARVIS);

View File

@ -61,11 +61,6 @@ public class TVShowsActivityTests extends AbstractTestClass<TVShowsActivity> {
} }
@Override
protected void configureHostInfo(HostInfo hostInfo) {
}
/** /**
* Test if action bar title initially displays TV Shows * Test if action bar title initially displays TV Shows
*/ */

View File

@ -16,9 +16,12 @@
package org.xbmc.kore.testutils.eventserver; package org.xbmc.kore.testutils.eventserver;
import org.xbmc.kore.utils.LogUtils;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class EventPacketBUTTON extends EventPacket { public class EventPacketBUTTON extends EventPacket {
private final static String TAG = LogUtils.makeLogTag(EventPacketBUTTON.class);
private short code; private short code;
private String mapName; private String mapName;
@ -34,14 +37,19 @@ public class EventPacketBUTTON extends EventPacket {
super(packet); super(packet);
byte[] payload = getPayload(); byte[] payload = getPayload();
code = ByteBuffer.wrap(payload, 0, 2).getShort();
flags = ByteBuffer.wrap(payload, 2, 2).getShort();
amount = ByteBuffer.wrap(payload, 4, 2).getShort();
mapName = getStringFromPayload(payload, 6); try {
code = ByteBuffer.wrap(payload, 0, 2).getShort();
flags = ByteBuffer.wrap(payload, 2, 2).getShort();
amount = ByteBuffer.wrap(payload, 4, 2).getShort();
int nextStringPosition = 6 + mapName.getBytes().length + 1; mapName = getStringFromPayload(payload, 6);
buttonName = getStringFromPayload(payload, nextStringPosition);
int nextStringPosition = 6 + mapName.getBytes().length + 1;
buttonName = getStringFromPayload(payload, nextStringPosition);
} catch (ArrayIndexOutOfBoundsException e) {
LogUtils.LOGE(TAG, "Error handling payload " + new String(payload));
}
} }
public String getButtonName() { public String getButtonName() {