1*21373fa4SWill Schurman package host.exp.exponent.utils 2*21373fa4SWill Schurman 3*21373fa4SWill Schurman import android.content.Intent 4*21373fa4SWill Schurman import android.net.Uri 5*21373fa4SWill Schurman import android.os.Build 6*21373fa4SWill Schurman import androidx.test.InstrumentationRegistry 7*21373fa4SWill Schurman import androidx.test.espresso.Espresso 8*21373fa4SWill Schurman import androidx.test.espresso.assertion.ViewAssertions 9*21373fa4SWill Schurman import androidx.test.espresso.matcher.ViewMatchers 10*21373fa4SWill Schurman import androidx.test.uiautomator.By 11*21373fa4SWill Schurman import androidx.test.uiautomator.UiDevice 12*21373fa4SWill Schurman import androidx.test.uiautomator.Until 13*21373fa4SWill Schurman import host.exp.exponent.generated.ExponentBuildConstants 14*21373fa4SWill Schurman import host.exp.exponent.kernel.ExponentUrls 15*21373fa4SWill Schurman import okhttp3.MediaType 16*21373fa4SWill Schurman import okhttp3.OkHttpClient 17*21373fa4SWill Schurman import okhttp3.Request 18*21373fa4SWill Schurman import okhttp3.RequestBody 19*21373fa4SWill Schurman import org.json.JSONException 20*21373fa4SWill Schurman import org.json.JSONObject 21*21373fa4SWill Schurman import java.io.IOException 22*21373fa4SWill Schurman import java.util.* 23*21373fa4SWill Schurman 24*21373fa4SWill Schurman object TestServerUtils { 25*21373fa4SWill Schurman private const val LAUNCH_TIMEOUT = 5000 26*21373fa4SWill Schurman 27*21373fa4SWill Schurman private val JSON = MediaType.parse("application/json; charset=utf-8") 28*21373fa4SWill Schurman private val isTestServerAvailable: Boolean 29*21373fa4SWill Schurman get() = ExponentBuildConstants.TEST_SERVER_URL != "TODO" 30*21373fa4SWill Schurman 31*21373fa4SWill Schurman @Throws(Exception::class) runFixtureTestnull32*21373fa4SWill Schurman fun runFixtureTest(device: UiDevice, fixtureName: String) { 33*21373fa4SWill Schurman if (!isTestServerAvailable) { 34*21373fa4SWill Schurman return 35*21373fa4SWill Schurman } 36*21373fa4SWill Schurman 37*21373fa4SWill Schurman // Get a fixture server 38*21373fa4SWill Schurman val fixtureServer = getFixtureServerInstance(fixtureName) 39*21373fa4SWill Schurman 40*21373fa4SWill Schurman // Launch the app 41*21373fa4SWill Schurman val context = InstrumentationRegistry.getContext() 42*21373fa4SWill Schurman val intent = Intent(Intent.ACTION_VIEW, Uri.parse(fixtureServer!!.manifestServerUrl)).apply { 43*21373fa4SWill Schurman addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 44*21373fa4SWill Schurman } 45*21373fa4SWill Schurman context.startActivity(intent) 46*21373fa4SWill Schurman 47*21373fa4SWill Schurman // Wait for the app to appear 48*21373fa4SWill Schurman device.wait(Until.hasObject(By.pkg("host.exp.exponent").depth(0)), LAUNCH_TIMEOUT.toLong()) 49*21373fa4SWill Schurman 50*21373fa4SWill Schurman // Need this to wait on idling resources 51*21373fa4SWill Schurman Espresso.onView(ExponentMatchers.withTestId("test_container")) 52*21373fa4SWill Schurman .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) 53*21373fa4SWill Schurman for (event in fixtureServer.testEvents) { 54*21373fa4SWill Schurman event.waitForCompleted(device, fixtureServer.manifestServerUrl) 55*21373fa4SWill Schurman } 56*21373fa4SWill Schurman } 57*21373fa4SWill Schurman 58*21373fa4SWill Schurman @Throws(IOException::class) httpRequestnull59*21373fa4SWill Schurman private fun httpRequest(request: Request): String { 60*21373fa4SWill Schurman val client = OkHttpClient() 61*21373fa4SWill Schurman val response = client.newCall(request).execute() 62*21373fa4SWill Schurman if (!response.isSuccessful) { 63*21373fa4SWill Schurman throw IOException("Unexpected code $response") 64*21373fa4SWill Schurman } 65*21373fa4SWill Schurman return response.body()!!.string() 66*21373fa4SWill Schurman } 67*21373fa4SWill Schurman getFixtureServerInstancenull68*21373fa4SWill Schurman private fun getFixtureServerInstance(fixtureName: String): FixtureServerInstance? { 69*21373fa4SWill Schurman try { 70*21373fa4SWill Schurman val request = Request.Builder() 71*21373fa4SWill Schurman .url(ExponentBuildConstants.TEST_SERVER_URL + "/start-fixture-server?fixtureName=" + fixtureName) 72*21373fa4SWill Schurman .build() 73*21373fa4SWill Schurman val responseJson = JSONObject(httpRequest(request)) 74*21373fa4SWill Schurman val manifestServerUrl = responseJson.getString("manifestServerUrl") 75*21373fa4SWill Schurman val jsonTestEvents = responseJson.getJSONArray("testEvents") 76*21373fa4SWill Schurman val testEvents: MutableList<TestEvent> = ArrayList() 77*21373fa4SWill Schurman for (i in 0 until jsonTestEvents.length()) { 78*21373fa4SWill Schurman val jsonTestEvent = jsonTestEvents.getJSONObject(i) 79*21373fa4SWill Schurman testEvents.add( 80*21373fa4SWill Schurman TestEvent( 81*21373fa4SWill Schurman jsonTestEvent.getString("type"), 82*21373fa4SWill Schurman jsonTestEvent.getString("data"), 83*21373fa4SWill Schurman jsonTestEvent.getInt("testEventId") 84*21373fa4SWill Schurman ) 85*21373fa4SWill Schurman ) 86*21373fa4SWill Schurman } 87*21373fa4SWill Schurman return FixtureServerInstance(manifestServerUrl, testEvents) 88*21373fa4SWill Schurman } catch (e: IOException) { 89*21373fa4SWill Schurman e.printStackTrace() 90*21373fa4SWill Schurman } catch (e: JSONException) { 91*21373fa4SWill Schurman e.printStackTrace() 92*21373fa4SWill Schurman } 93*21373fa4SWill Schurman return null 94*21373fa4SWill Schurman } 95*21373fa4SWill Schurman 96*21373fa4SWill Schurman @Throws(Exception::class) reportTestResultnull97*21373fa4SWill Schurman fun reportTestResult(success: Boolean, testName: String?, logs: String?) { 98*21373fa4SWill Schurman if (!isTestServerAvailable) { 99*21373fa4SWill Schurman return 100*21373fa4SWill Schurman } 101*21373fa4SWill Schurman val jsonBody = JSONObject().apply { 102*21373fa4SWill Schurman put("testRunId", ExponentBuildConstants.TEST_RUN_ID) 103*21373fa4SWill Schurman put("testName", testName) 104*21373fa4SWill Schurman put("success", success) 105*21373fa4SWill Schurman put("logs", logs) 106*21373fa4SWill Schurman put("deviceName", Build.MODEL) 107*21373fa4SWill Schurman put("systemVersion", Build.VERSION.RELEASE) 108*21373fa4SWill Schurman } 109*21373fa4SWill Schurman val request = Request.Builder() 110*21373fa4SWill Schurman .url(ExponentBuildConstants.TEST_SERVER_URL + "/report-test-result") 111*21373fa4SWill Schurman .post(RequestBody.create(JSON, jsonBody.toString())) 112*21373fa4SWill Schurman .build() 113*21373fa4SWill Schurman httpRequest(request) 114*21373fa4SWill Schurman } 115*21373fa4SWill Schurman 116*21373fa4SWill Schurman class TestEvent(private val type: String, private val data: String, private val testEventId: Int) { 117*21373fa4SWill Schurman @Throws(Exception::class) waitForCompletednull118*21373fa4SWill Schurman fun waitForCompleted(device: UiDevice, manifestUrl: String) { 119*21373fa4SWill Schurman if (type == "findTextOnScreen") { 120*21373fa4SWill Schurman ExpoConditionWatcher.waitForText(device, data) 121*21373fa4SWill Schurman } 122*21373fa4SWill Schurman try { 123*21373fa4SWill Schurman val request = Request.Builder() 124*21373fa4SWill Schurman .url(ExponentUrls.toHttp(manifestUrl) + "/finished-test-event") 125*21373fa4SWill Schurman .addHeader("test-event-id", testEventId.toString()) 126*21373fa4SWill Schurman .build() 127*21373fa4SWill Schurman httpRequest(request) 128*21373fa4SWill Schurman } catch (e: RuntimeException) { 129*21373fa4SWill Schurman } catch (e: IOException) { 130*21373fa4SWill Schurman } 131*21373fa4SWill Schurman } 132*21373fa4SWill Schurman } 133*21373fa4SWill Schurman 134*21373fa4SWill Schurman class FixtureServerInstance(val manifestServerUrl: String, val testEvents: List<TestEvent>) 135*21373fa4SWill Schurman } 136