Skip to content

Commit

Permalink
Run Tests on bitbar.cloud and collect artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
JosephBK committed Jul 16, 2019
1 parent 5eeec4e commit 5bbafd4
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 361 deletions.
10 changes: 6 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ android {
buildConfigField 'int', "VISIBLE_TOP_SITES", '4'

applicationId "com.cliqz.browser"
testApplicationId "com.cliqz.browser.test"
testInstrumentationRunner "com.cliqz.browser.test.CustomTestRunner"
vectorDrawables.useSupportLibrary = true
}
Expand All @@ -37,9 +38,7 @@ android {
shrinkResources false
proguardFiles 'proguard-project.txt'
versionNameSuffix '-debug'
dexcount {
enabled false
}
dexcount.enabled = false
}

release {
Expand Down Expand Up @@ -111,6 +110,9 @@ android {
universalApk false
}
}
testOptions {
animationsDisabled = true
}
}

dexcount {
Expand Down Expand Up @@ -221,7 +223,7 @@ dependencies {
lumenImplementation 'com.revenuecat.purchases:purchases:2.1.2'

// vpn module
lumenImplementation 'com.cliqz:com.cliqz.vpnlib:1.0.4'
lumenImplementation 'com.cliqz:com.cliqz.vpnlib:1.0.1'

// Testing-only dependencies
testImplementation 'junit:junit:4.12'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void setAndConfirmSearchEngine(final String engine, final String url) {
onView(withText(equalToIgnoringCase("Complementary search engine"))).perform(click());
onView(withText(equalToIgnoringCase(engine))).perform(click());
onView(withText(equalToIgnoringCase("OK"))).perform(click());
onView(withText(equalToIgnoringCase("General"))).perform(pressBack());
onView(withText(equalToIgnoringCase("Search results for"))).perform(pressBack());
onView(withText(equalToIgnoringCase("Settings"))).perform(pressBack());
onView(withId(R.id.title_bar)).perform(click());
onView(withId(R.id.search_edit_text)).perform(typeText(query),
Expand Down
1 change: 1 addition & 0 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repositories {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "com.android.tools.build:gradle:3.4.1"
implementation "com.squareup.okhttp3:okhttp:4.0.1"
}

// Clearing dependencies order, we do not want to compile java at all
Expand Down
144 changes: 142 additions & 2 deletions buildSrc/src/main/groovy/com/cliqz/gradle/TestdroidTask.groovy
Original file line number Diff line number Diff line change
@@ -1,18 +1,158 @@
package com.cliqz.gradle

import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import groovy.json.JsonSlurper

class TestdroidTask extends DefaultTask {
import java.nio.charset.StandardCharsets

class TestDroidTask extends DefaultTask {

def env = System.getenv()
String projectId = env['PROJECT_ID']
String apIKey = env['API_KEY']
String frameworkId = env['FRAMEWORK_ID']
String deviceGroupId = env['DEVICE_GROUP_ID']


final PROJECT_ID = projectId
final API_KEY = apIKey
final FRAMEWORK_ID = frameworkId
final DEVICE_GROUP_ID = deviceGroupId

final OkHttpClient client = new OkHttpClient()
final slurper = new JsonSlurper()

@TaskAction
def connectTestdroid() {
println("Hello, world!!!")
// 1. Does the project identified by the id param exists? Decide yourself how to pass this param
final url = new URL("https://cloud.bitbar.com/api/me/projects/${PROJECT_ID}")
final request = url.openConnection()
request.setRequestProperty('Authorization', "Basic ${getBasicAuth(API_KEY)}")
if (request.responseCode == HttpURLConnection.HTTP_OK) {
logger.info("Project exists")
} else {
logger.error("No project for the given id: ${PROJECT_ID}")
throw new Exception('Error occurred: Specify a project ID that exists')
}
// 2. Upload the 2 apks and store the ids
final apkID = uploadFile("/Users/kiizajosephbazaare/browser-android/app/build/outputs/apk/cliqz/debug/app-cliqz-arm64-v8a-debug.apk")
final testsID = uploadFile("/Users/kiizajosephbazaare/browser-android/app/build/outputs/apk/androidTest/cliqz/debug/app-cliqz-debug-androidTest.apk")
// 3. Create the testrun and run it
final runID = performTestRun(apkID, testsID)
// 4. Poll every minute (os so) to check the job finished
String state = pollTestRunStatus(runID)
int timeTaken = 0
while (state!= "FINISHED"){
sleep(60000)
timeTaken+=1
state = pollTestRunStatus(runID)
}
logger.info("Tests finished in ${timeTaken} minutes")
// 5. Download the artifacts and put them in a predefined folder (where Azure/Jenkins can find it)
fetchTestRunArtifacts(runID)
// 6. log error if any test failed, otherwise just return
}

def getBasicAuth(String apiKey) {
"${apiKey}:".bytes.encodeBase64().toString()
}

def uploadFile(String filepath){
final file = new File(filepath)
final mediaType = MediaType.parse('application/octet-stream')
def requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart('file', file.name, RequestBody.create(file, mediaType))
.build()
def request = new Request.Builder()
.header('Authorization', "Basic ${getBasicAuth(API_KEY)}")
.url("https://cloud.bitbar.com/api/me/files")
.post(requestBody)
.build()
final response = client.newCall(request).execute()
if (!response.isSuccessful()) throw new IOException("Unexpected file" + response.code)
final json = slurper.parseText(response.body.string())
json.id
}

def performTestRun(long appFileID, long testFileID){
final mediaType = MediaType.parse('application/json')
final content = """
{
"osType":"ANDROID",
"projectId":"$PROJECT_ID",
"files":[
{"id":"$appFileID"},
{"id":"$testFileID"}
],
"frameworkId":"$FRAMEWORK_ID",
"deviceGroupId":"$DEVICE_GROUP_ID"
}""".stripIndent()

def request = new Request.Builder()
.header('Authorization', "Basic ${getBasicAuth(API_KEY)}")
.url("https://cloud.bitbar.com/api/me/runs")
.post(RequestBody.create(content, mediaType))
.build()
final response = client.newCall(request).execute()
if (!response.isSuccessful()) throw new IOException("Test run not possible " + response.code)
final testRun = slurper.parseText(response.body.string())
response.close()
testRun.id
}

def pollTestRunStatus(long testID){
final poll = new URL("https://cloud.bitbar.com/api/me/projects/${PROJECT_ID}/runs/${testID}")
final check = poll.openConnection()
check.setRequestProperty('Authorization', "Basic ${getBasicAuth(API_KEY)}")
if (check.responseCode == HttpURLConnection.HTTP_OK){
final pollStatus = slurper.parseText (check.content.text)
pollStatus.state
} else {
logger.error("No Test Run for the given id: ${testID}")
}
}

def fetchTestRunArtifacts(long testRunID){
final url = new URL("https://cloud.bitbar.com/api/me/projects/${PROJECT_ID}/runs/${testRunID}/device-sessions")
final sessions = url.openConnection()
sessions.setRequestProperty('Authorization', "Basic ${getBasicAuth(API_KEY)}")
if (sessions.responseCode == HttpURLConnection.HTTP_OK){
final sessionResults = slurper.parse(sessions.inputStream)
sessionResults.data.each{ session ->
println "Device: ${session.device.displayName} ID: ${session.id} SuccessRatio: ${session.successRatio}"
if (session.successRatio < 1){
def request = new Request.Builder()
.url("https://cloud.bitbar.com/api/me/projects/${PROJECT_ID}/runs/${testRunID}/device-sessions/${session.id}/output-file-set/files.zip")
.header('Authorization', "Basic ${getBasicAuth(API_KEY)}")
.get()
.build()
final artifact = client.newCall(request).execute()
def something
FileOutputStream artifactFile = new FileOutputStream("./artifacts/${session.id}.zip")
byte[] buf = new byte[1024]
while ( (something = artifact.body().source().read(buf)) != -1){
artifactFile.write(buf, 0, something)
}
artifactFile.flush()
if (artifact.isSuccessful()){
logger.info("Artifacts downloaded")
println("Artifacts downloaded")
}else{
logger.error("Files for Session ${session.id} are not available")
}
}else {
logger.info("Tests runs on ${session.device.displayName} were successful ")
}
}
} else{
logger.error("No session data for test run ${testRunID}")
}
}
}
7 changes: 6 additions & 1 deletion buildSrc/src/main/java/com/cliqz/gradle/CliqzPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ class CliqzPlugin: Plugin<Project> {
private fun createTestdroidTask(project: Project, variant: ApplicationVariant) {
val taskName = "connect${variant.name.capitalize()}TestDroid"
// Make sure this task depends on the assembling of the app and tests, we need those file to be uploaded
project.tasks.register(taskName, TestdroidTask::class.java)
val assembleTestProvider = project.tasks.named("assemble${variant.name.capitalize()}AndroidTest")
val assembleProvider = project.tasks.named("assemble${variant.name.capitalize()}")
val taskProvider = project.tasks.register(taskName, TestDroidTask::class.java)
taskProvider.configure {
it.dependsOn(assembleProvider, assembleTestProvider)
}
}

private fun createCliqzConfigTasks(project: Project, variant: ApplicationVariant) {
Expand Down
25 changes: 0 additions & 25 deletions testdroid/build.gradle

This file was deleted.

Loading

0 comments on commit 5bbafd4

Please sign in to comment.