diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d5952b6e7..ecee19a8b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -158,4 +158,33 @@ jobs: displayName: 'Run Test on Sauce on iOS and Android' - \ No newline at end of file + - job: Genymotion + pool: + vmImage: 'macOS 10.13' + + + steps: + - task: NodeTool@0 + inputs: + versionSpec: '8.12.0' + + - script: | + node -v + npm install -g appium@beta + appium -v + displayName: 'Install Appium' + + - bash: | + pip3 install gmsaas + displayName: 'Download Genymotion Installer' + + - bash: | + gmsaas config set android-sdk-path $ANDROID_HOME + displayName: 'Set Android Sdk Path' + + - script: | + mvn clean install -Dmaven.test.skip=true + Platform='android' CLOUD_USER=$(user_gm) CLOUD_KEY=$(pass_gm) CONFIG_FILE='gm_config.properties' mvn clean -Dtest=Runner test + + displayName: 'Run Test on Genymotion Android' + diff --git a/caps/genymotion.json b/caps/genymotion.json new file mode 100644 index 000000000..15f8486a6 --- /dev/null +++ b/caps/genymotion.json @@ -0,0 +1,30 @@ +{ + "android": { + "automationName": "UIAutomator2", + "project": "ATD", + "app": { + "local": "https://github.com/shridharkalagi/AppiumSample/raw/master/VodQA.apk" + }, + "noSign": true + }, + "genycloud": { + "android": [ + { + "udid": "107d757e-463a-4a18-8667-b8dec6e4c87e", + "deviceName": "Google Pixel", + "osVersion": "9.0" + }, + { + "udid": "a59951f2-ed13-40f9-80b9-3ddceb3c89f5", + "deviceName": "Google Nexus 6", + "osVersion": "8.0" + } + ] + }, + "hostMachines": [ + { + "machineIP": "127.0.0.1", + "appiumServerPath": "/usr/local/lib/node_modules/appium/build/lib/main.js" + } + ] +} \ No newline at end of file diff --git a/gm_config.properties b/gm_config.properties new file mode 100644 index 000000000..6b3f75871 --- /dev/null +++ b/gm_config.properties @@ -0,0 +1,4 @@ +RUNNER=distribute +FRAMEWORK=testng +CAPS=./caps/genymotion.json +RUNNER_LEVEL=methods diff --git a/src/main/java/com/appium/capabilities/CapabilityManager.java b/src/main/java/com/appium/capabilities/CapabilityManager.java index c16ab9613..d31a14a6f 100644 --- a/src/main/java/com/appium/capabilities/CapabilityManager.java +++ b/src/main/java/com/appium/capabilities/CapabilityManager.java @@ -202,7 +202,11 @@ public boolean isRealDeviceAppPresentInCapsJson() { } public String getAppiumServerPath(String host) throws Exception { - return appiumServerProp(host, "appiumServerPath"); + try { + return appiumServerProp(host, "appiumServerPath"); + } catch (Exception e) { + return null; + } } public boolean isCloud(String host) { diff --git a/src/main/java/com/appium/device/GenyMotionManager.java b/src/main/java/com/appium/device/GenyMotionManager.java new file mode 100644 index 000000000..4389a9b53 --- /dev/null +++ b/src/main/java/com/appium/device/GenyMotionManager.java @@ -0,0 +1,88 @@ +package com.appium.device; + +import com.appium.utils.Api; +import com.appium.utils.CommandPrompt; +import okhttp3.Response; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.logging.Logger; + +public class GenyMotionManager { + + private static final Logger LOGGER = Logger + .getLogger(GenyMotionManager.class.getSimpleName()); + private static String cloud_user = System.getenv("CLOUD_USER"); + private static String cloud_key = System.getenv("CLOUD_KEY"); + + protected static void connectToGenyCloud(String udid, Object devices) throws IOException { + + String gmLogin = "gmsaas auth login " + + cloud_user + " " + cloud_key; + try { + new CommandPrompt() + .runCommandThruProcess(gmLogin); + LOGGER.info("Connected to Genymotion Cloud.."); + } catch (IOException e) { + throw new IOException("Failed to Connect to geny cloud.."); + } + + ((ArrayList)devices).parallelStream().forEach(o -> { + + String instanceUdid = (String) ((HashMap) o).get("udid"); + String instanceName = (String) ((HashMap) o).get("deviceName"); + String gnInstance = "gmsaas instances start " + + instanceUdid + " " + "\"" + instanceName + "\""; + LOGGER.info("Starting Device on genymotion cloud instance with uuid" + + instanceUdid + "and device name " + instanceName); + String createdInstance; + try { + createdInstance = new CommandPrompt() + .runCommandThruProcess(gnInstance); + String adbTunnel = "gmsaas instances adbconnect " + + " " + createdInstance; + new CommandPrompt() + .runCommandThruProcess(adbTunnel); + } catch (IOException e) { + e.printStackTrace(); + } + }); + + try { + LOGGER.info("Running Instances"); + String gmsaas_instances_list = new CommandPrompt() + .runCommandThruProcess("gmsaas instances list"); + LOGGER.info(gmsaas_instances_list); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public void stopAllGenymotionInstances() throws ParseException, IOException { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("email", cloud_user); + jsonObject.put("password", cloud_key); + Api api = new Api(); + String post = api.post("https://api.geny.io/cloud/v1/users/login", jsonObject.toString()); + JSONParser parser = new JSONParser(); + Object parse = parser.parse(post); + Object token = ((JSONObject) parse).get("token"); + Response response = api.requestBuilderWithBearerToken("https://api.geny.io/cloud/v1/instances", token.toString()); + String string = response.body().string(); + JSONParser responseUdid = new JSONParser(); + ((JSONArray) responseUdid.parse(string)).parallelStream().forEach(o -> { + Object uuid = ((JSONObject) o).get("uuid"); + LOGGER.info("Stopping Genymotion instance.." + uuid.toString()); + String recipe_uuid = null; + recipe_uuid = api.postWithNoBody("https://api.geny.io/cloud/v1/instances/" + uuid + + "/stop-disposable", token.toString()); + System.out.println(recipe_uuid); + }); + } +} diff --git a/src/main/java/com/appium/device/HostMachineDeviceManager.java b/src/main/java/com/appium/device/HostMachineDeviceManager.java index 950cf3b17..83c7d09ca 100644 --- a/src/main/java/com/appium/device/HostMachineDeviceManager.java +++ b/src/main/java/com/appium/device/HostMachineDeviceManager.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.logging.Logger; import java.util.stream.Collectors; public class HostMachineDeviceManager { @@ -176,6 +177,15 @@ private Map> getDevices() throws Exception { }); devicesByHost.put(ip, getAppiumDevices(ip, device)); } else { + if (capabilityManager.getCapabilityObjectFromKey("genycloud") != null) { + JSONObject cloud = capabilityManager + .getCapabilityObjectFromKey("genycloud"); + for (Map.Entry entry : cloud.toMap().entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + GenyMotionManager.connectToGenyCloud(key, value); + } + } devicesByHost.put(ip, getDevicesByIP(ip, platform, hostMachineJson)); } @@ -223,7 +233,6 @@ private List getSimulatorsToBoot(String machineIP, JSONArray simulators) } return devices; } - } diff --git a/src/main/java/com/appium/manager/AppiumParallelMethodTestListener.java b/src/main/java/com/appium/manager/AppiumParallelMethodTestListener.java index b026a8c0c..cb0f958f0 100644 --- a/src/main/java/com/appium/manager/AppiumParallelMethodTestListener.java +++ b/src/main/java/com/appium/manager/AppiumParallelMethodTestListener.java @@ -4,11 +4,13 @@ import com.annotation.values.RetryCount; import com.annotation.values.SkipIf; import com.appium.capabilities.CapabilityManager; +import com.appium.device.GenyMotionManager; import com.appium.utils.FileFilterParser; import com.appium.utils.Helpers; import com.context.SessionContext; import com.context.TestExecutionContext; +import org.json.simple.parser.ParseException; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ISuite; @@ -178,7 +180,14 @@ public void afterInvocation(IInvokedMethod iInvokedMethod, ITestResult iTestResu */ @Override public void onFinish(ISuite iSuite) { - System.out.println(); + if (CapabilityManager.getInstance() + .getCapabilityObjectFromKey("genycloud") != null) { + try { + new GenyMotionManager().stopAllGenymotionInstances(); + } catch (ParseException | IOException e) { + e.printStackTrace(); + } + } } /* diff --git a/src/main/java/com/appium/utils/Api.java b/src/main/java/com/appium/utils/Api.java index a62c9d49a..976efe79a 100644 --- a/src/main/java/com/appium/utils/Api.java +++ b/src/main/java/com/appium/utils/Api.java @@ -14,14 +14,14 @@ public class Api extends Helpers { public static final MediaType JSON - = MediaType.parse("application/json; charset=utf-8"); + = MediaType.parse("application/json; charset=utf-8"); public Response getResponse(String url) throws IOException { OkHttpClient client = new OkHttpClient.Builder() - .connectTimeout(90, TimeUnit.SECONDS) - .writeTimeout(90, TimeUnit.SECONDS) - .readTimeout(90, TimeUnit.SECONDS) - .build(); + .connectTimeout(90, TimeUnit.SECONDS) + .writeTimeout(90, TimeUnit.SECONDS) + .readTimeout(90, TimeUnit.SECONDS) + .build(); try { Request request = new Request.Builder().url(url).build(); return client.newCall(request).execute(); @@ -31,16 +31,28 @@ public Response getResponse(String url) throws IOException { } + public Response requestBuilderWithBearerToken(String url, String userToken) throws IOException { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(url) + .get() + .addHeader("Content-Type", "application/json;charset=utf-8") + .addHeader("Authorization", "Bearer" + " " + userToken) + .build(); + return client.newCall(request).execute(); + + } + public String uploadMultiPartFile(File filePath, String hostMachine) throws Exception { OkHttpClient client = new OkHttpClient(); MediaType MEDIA_TYPE_PNG = MediaType.parse("multipart/form-data"); RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM) - .addFormDataPart("uploaded_file", filePath.getName(), - RequestBody.create(MEDIA_TYPE_PNG, filePath)) - .build(); + .addFormDataPart("uploaded_file", filePath.getName(), + RequestBody.create(MEDIA_TYPE_PNG, filePath)) + .build(); Request request = new Request.Builder().url("http://" + hostMachine - + ":" + getRemoteAppiumManagerPort(hostMachine) + "/artifacts/upload") - .post(requestBody).build(); + + ":" + getRemoteAppiumManagerPort(hostMachine) + "/artifacts/upload") + .post(requestBody).build(); Response response = client.newCall(request).execute(); return response.body().string(); } @@ -49,9 +61,9 @@ public String post(String url, String json) { OkHttpClient client = new OkHttpClient(); RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() - .url(url) - .post(body) - .build(); + .url(url) + .post(body) + .build(); try { Response response = client.newCall(request).execute(); return response.body().string(); @@ -60,4 +72,23 @@ public String post(String url, String json) { } } + public String postWithNoBody(String url, String token) { + OkHttpClient client = new OkHttpClient(); + RequestBody body = RequestBody.create(null, new byte[]{}); + Request request = new Request.Builder() + .url(url) + .addHeader("Content-Type", "application/json;charset=utf-8") + .addHeader("Authorization", "Bearer" + " " + token) + .post(body) + .build(); + try { + Response response = client.newCall(request).execute(); + return response.body().string(); + } catch (Exception e) { + return null; + } + } + + + } diff --git a/src/main/java/com/appium/utils/CommandPrompt.java b/src/main/java/com/appium/utils/CommandPrompt.java index c6f57caa0..a93c2e0cf 100755 --- a/src/main/java/com/appium/utils/CommandPrompt.java +++ b/src/main/java/com/appium/utils/CommandPrompt.java @@ -48,14 +48,14 @@ public BufferedReader getBufferedReader(String command) throws IOException { return new BufferedReader(isr); } - public void runCommandThruProcess(String command) - throws InterruptedException, IOException { + public String runCommandThruProcess(String command) + throws IOException { BufferedReader br = getBufferedReader(command); String line; String allLine = ""; while ((line = br.readLine()) != null) { allLine = allLine + "" + line + "\n"; - System.out.println(allLine); } + return allLine; } } diff --git a/src/main/java/com/video/recorder/Flick.java b/src/main/java/com/video/recorder/Flick.java index 7506192aa..8849c31d0 100644 --- a/src/main/java/com/video/recorder/Flick.java +++ b/src/main/java/com/video/recorder/Flick.java @@ -59,7 +59,7 @@ private void flickRecordingCommand(String command, String className, + AppiumDeviceManager.getAppiumDevice().getDevice().getUdid(); runCommandThruProcess(android); - } catch (IOException | InterruptedException e) { + } catch (IOException e) { e.printStackTrace(); } } else {