Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion androidtest-library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ dependencies {
testImplementation 'junit:junit:4.12'

implementation 'androidx.test:runner:1.2.0'

implementation ('io.socket:socket.io-client:1.0.0') {
exclude group: 'org.json', module: 'json'
}

androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
Expand Down

This file was deleted.

140 changes: 138 additions & 2 deletions androidtest-library/src/main/java/com/moquality/android/MoQuality.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,73 @@
package com.moquality.android;

import android.graphics.Bitmap;
import android.os.Looper;
import android.util.Log;

import androidx.test.runner.screenshot.ScreenCapture;
import androidx.test.runner.screenshot.Screenshot;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MoQuality {
public class MoQuality implements SocketIOHandlerThread.Callback {

public static String TAG = "MQ";
private static String TAG = "MQ";

private SocketIOHandlerThread mHandlerThread;

private ArrayList<Object> appTests = new ArrayList<>();

public int log(String message) {
Log.i(TAG, message);
return 0;
}

public void register(Object test, String deviceId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does the test get a deviceId? I am assuming in Espresso code, the client will call
MoQuality.register(class, "device1")

If this is the case, then they are hardcoding the deviceId in the test, which means they would have to generate a new APK for device2. Is that right? Ideally we would want this to be dynamically assigned to the test via a command line argument or something. In Android, when running the test from command line, clients can supply key value pairs to am instrument e.g., -e deviceId device1.
https://developer.android.com/studio/test/command-line#AMOptionsSyntax

These can be fetched from within the code using the InstrumentationRegistry.getArguments()
https://developer.android.com/reference/android/support/test/InstrumentationRegistry
https://github.com/android/android-test/blob/master/runner/monitor/java/androidx/test/InstrumentationRegistry.java

this.appTests.add(test);

// launch Socket IO chat thread
if (Looper.myLooper() == null) {
Looper.prepare();
}
mHandlerThread = new SocketIOHandlerThread(this, deviceId);
mHandlerThread.start();
mHandlerThread.prepareHandler();
}

public void unregister(Class test){
for (Object testClass:appTests) {
if (testClass.getClass().getSimpleName().equalsIgnoreCase(test.getSimpleName())){
appTests.remove(testClass);
}
}
}

public void shutdown() {
if(mHandlerThread != null){
mHandlerThread.quit();
mHandlerThread.interrupt();
}
}

public void runSocketIOTest() {
mHandlerThread.queueTask(TestConstants.SOCKET_IO_START);
try {
long threadStartTime = System.currentTimeMillis();
long executionTimeInMillis = 0;
while (mHandlerThread.isThreadAlive()) {
executionTimeInMillis = System.currentTimeMillis() - threadStartTime;
}

Log.i("SOCKET_IO THREAD", "Execution time = " + executionTimeInMillis/1000 + " seconds");
} catch (Exception e) {
Log.d("SOCKET IO", "Test interrupted");
}
}

public void takeScreenshot(String name) throws IOException {
log("Saving screenshot "+name);
ScreenCapture capture = Screenshot.capture();
Expand All @@ -29,5 +80,90 @@ public void takeScreenshot(String name) throws IOException {
throw e;
}
}

@Override
public void onSocketTaskCompleted(int taskId) {
switch (taskId){
case TestConstants.SOCKET_IO_MSG_RECEIVED:
Log.i(TAG, "Message received in UI");
break;
case TestConstants.SOCKET_IO_DISCONNECTED:
break;
}
}

@Override
public void onSocketEventReceived(String eventName, String method, List<Class> classArgs, List<String> stringArgs) {
switch (eventName){
case TestConstants.SOCKET_EVENT_CALL:
Log.i(TAG, "CALL command received for this device.");
callAppTestMethod(method, classArgs, stringArgs);
break;
case TestConstants.SOCKET_EVENT_STATUS:
Log.i(TAG, "STATUS command received for this device.");
break;
case TestConstants.SOCKET_EVENT_RETURN:
Log.i(TAG, "RETURN command received for this device.");
}
}

private void setMode(String mode) {
switch (mode) {
case "reflect":
mHandlerThread.queueTask(TestConstants.REFLECT_MODE);

break;
case "quit":
this.mHandlerThread.quit();

break;
default:
Log.i(TAG, "Unhandled mode " + mode);
//mHandlerThread.queueTask(TestConstants.DEFAULT_MODE);
}
}

private void callAppTestMethod(String method, List<Class> classArgs, List<String> stringArgs){
if (appTests!=null) {

if (stringArgs!=null && stringArgs.size()>0) {
Log.i(TAG, "******* METHOD = " + method + " ARGS = " + stringArgs.get(0));
} else {
Log.i(TAG, "******* METHOD = " + method);
}
if (method.equalsIgnoreCase("setMode")){
if (stringArgs!=null) {
setMode(stringArgs.get(0));
}
} else {
for (Object testClass:appTests) {
try {
Method m = testClass.getClass().getMethod(method, classArgs.toArray(new Class[0]));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we're searching for a method in all the Test Classes and selecting the first test method? What if two methods in 2 classes have the same name? Perhaps it's best to have 2 methods -- one where you can specify and the other where it does a lookup like this...

try {
Log.i(TAG, testClass.getClass().getSimpleName() + " - method called = " + m.toString());
String data = "";
if (stringArgs != null && stringArgs.size() > 0) {
data = m.invoke(testClass, stringArgs.toArray(new String[0])).toString();
} else {
data = m.invoke(testClass).toString();
}
Log.i(TAG, "return " + data);
} catch (NullPointerException e) {
Log.i(TAG, "Error returning data from method invoke()");
} catch (IllegalAccessException e) {
Log.i(TAG, method + " invoke error - Illegal Access Exception");
} catch (InvocationTargetException e) {
Log.i(TAG, method + " invoke error - Invocation Target Exception");
}
} catch (NoSuchMethodException e) {
Log.i(TAG, "Method (" + method + ") not found in app test class " + testClass.getClass().getSimpleName());
} catch (NullPointerException e){
Log.i(TAG, "Null pointer exception on class constructor.");
}
}
}
}
}
}

Loading