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