1
0
mirror of https://github.com/vector-im/riotX-android synced 2025-10-06 00:02:48 +02:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Michael Kaye
6c4c3d5404 Remove leading new line 2022-08-04 11:49:03 +01:00
Michael Kaye
7ba26e624f Confused of west london writes: "i hit cleanup code and committed already, why do i need to do it twice". 2022-08-04 11:03:19 +01:00
Michael Kaye
9d0e57a44c Move whitespace 2022-08-04 10:56:00 +01:00
Michael Kaye
5bb006ad09 Changelog entry 2022-08-04 10:54:08 +01:00
Michael Kaye
362a58d702 Tidy up 2022-08-04 10:42:54 +01:00
Michael Kaye
0c4451ffc6 Format test code; use inbound values from trafficlight to set options 2022-08-03 15:48:49 +01:00
Michael Kaye
0330a624b6 TrafficLightClient test to run based on traffic light server requests. 2022-08-03 15:48:49 +01:00
4 changed files with 277 additions and 0 deletions

1
changelog.d/6729.misc Normal file
View File

@@ -0,0 +1 @@
Demo trafficlight client for element android https://github.com/matrix-org/trafficlight

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.ui
import android.Manifest
import androidx.test.espresso.IdlingPolicies
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import im.vector.app.espresso.tools.ScreenshotFailureRule
import im.vector.app.features.MainActivity
import im.vector.app.ui.robot.ElementRobot
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import java.lang.Thread.sleep
import java.util.UUID
import java.util.concurrent.TimeUnit
/**
* TrafficLight client is a UI test that receives requests from a TrafficLight server and fufils them on the UI
*/
@RunWith(AndroidJUnit4::class)
class TrafficLightClientTest {
@get:Rule
val testRule: RuleChain = RuleChain
.outerRule(ActivityScenarioRule(MainActivity::class.java))
.around(GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE))
.around(ScreenshotFailureRule())
private val elementRobot = ElementRobot()
private val client = OkHttpClient()
@Test
fun trafficLightCycle() {
IdlingPolicies.setMasterPolicyTimeout(120, TimeUnit.SECONDS)
// keep the same UUID during each run; otherwise it should be entirely random.
val uuid = UUID.randomUUID().toString()
val trafficLightServer = "http://10.0.2.2:5000"
val postURL = "$trafficLightServer/client/$uuid/respond"
val pollURL = "$trafficLightServer/client/$uuid/poll"
val registerURL = "$trafficLightServer/client/$uuid/register"
register(registerURL)
while (true) {
var pollResponse = poll(pollURL)
var action = pollResponse.get("action")
if (action == "login") {
val data = pollResponse.getJSONObject("data")
val user = data.getString("username")
val pass = data.getString("password")
val homeserverURL = data.getJSONObject("homeserver_url").getString("local_docker")
elementRobot.login(homeserverURL, user, pass)
// TODO: Determine how to avoid these 60s delays before prompt arrives.
// TODO (alt): Determine how to wait for the prompt to be visible before continuing instead of explicit wait.
sleep(20000) // try to wait for cross signing to have kicked in...
println("Waited 20s")
sleep(20000)
println("Waited 40s")
sleep(20000)
println("Waited 60s")
post(postURL, "{\"response\": \"loggedin\"}")
}
if (action == "register") {
val data = pollResponse.getJSONObject("data")
val user = data.getString("username")
val pass = data.getString("password")
val homeserverURL = data.getJSONObject("homeserver_url").getString("local_docker")
elementRobot.register(homeserverURL, user, pass)
sleep(20000) // try to wait for cross signing to have kicked in...
println("Waited 20s")
sleep(20000)
println("Waited 40s")
sleep(20000)
println("Waited 60s")
post(postURL, "{\"response\": \"registered\"}")
}
if (action == "idle") {
val data = pollResponse.getJSONObject("data")
val delay = data.getLong("delay")
sleep(delay)
}
// client will be told to start OR accept cross signing request
if (action == "start_crosssign") {
elementRobot.startVerification()
post(postURL, "{\"response\": \"started_crosssign\"}")
}
if (action == "accept_crosssign") {
elementRobot.acceptVerification()
post(postURL, "{\"response\": \"accepted_crosssign\"}")
}
// Both clients will be told to verify the cross sign
if (action == "verify_crosssign_emoji") {
elementRobot.completeVerification()
post(postURL, "{\"response\": \"verified_crosssign\"}")
}
// exit test
if (action == "exit") {
break
}
sleep(500) // provide a minimum delay between polls, prevent tightly spinning loops
}
}
private val JSON: MediaType = "application/json".toMediaType()
private fun post(url: String, json: String): String {
val body: RequestBody = json.toRequestBody(JSON)
val request: Request = Request.Builder()
.url(url)
.post(body)
.build()
client.newCall(request).execute().use { response -> return response.body!!.string() }
}
private fun poll(url: String): JSONObject {
val request: Request = Request.Builder()
.url(url)
.build()
client.newCall(request).execute().use { response -> return JSONObject(response.body!!.string()) }
}
private fun register(url: String): JSONObject {
val json = "{ \"type\": \"element-android\", \"version\":\"0.whatever.1\"}"
val body: RequestBody = json.toRequestBody("application/json".toMediaType())
val request: Request = Request.Builder()
.url(url)
.post(body)
.build()
client.newCall(request).execute().use { response -> return JSONObject(response.body!!.string()) }
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.ui.robot
import androidx.test.espresso.PerformException
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.matcher.ViewMatchers.withChild
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.adevinta.android.barista.interaction.BaristaClickInteractions
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import com.adevinta.android.barista.interaction.BaristaDrawerInteractions
import com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItem
import com.adevinta.android.barista.internal.performAction
import im.vector.app.R
import im.vector.app.espresso.tools.clickOnPreference
import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.waitForView
import im.vector.app.withRetry
import org.hamcrest.core.AllOf
class CryptoRobot {
// Do this if we don't get the popup in time; but actually; just wait for the pop-up
fun manualVerification() {
// Settings
BaristaDrawerInteractions.openDrawer()
clickOn(R.id.homeDrawerHeaderSettingsView)
BaristaClickInteractions.clickOn(R.string.settings_security_and_privacy)
clickOnPreference(R.string.settings_active_sessions_show_all)
clickListItem(R.id.genericRecyclerView, 3) // the first remote client.
AllOf.allOf(withId(R.id.itemVerificationClickableZone), withChild(withText(R.string.verification_verify_device))).performAction(click())
}
fun startVerification() {
// These are kinda async popups, be somewhat lenient with them.
withRetry {
waitUntilViewVisible(withText(R.string.crosssigning_verify_this_session))
clickOn(R.string.crosssigning_verify_this_session)
}
}
fun acceptVerification() {
// This is somewhat async; be lenient
withRetry {
waitUntilViewVisible(withText(R.string.verification_request))
clickOn(R.string.verification_request)
}
try {
withRetry {
waitUntilViewVisible(withText(R.string.verification_scan_emoji_title))
clickOn(R.string.verification_scan_emoji_title)
}
} catch (e: PerformException) {
// Ignore...
}
}
fun completeVerification() {
waitForView(withText(R.string.verification_emoji_notice))
clickOn(R.string.verification_sas_match)
waitForView(withText(R.string.verification_conclusion_ok_self_notice))
waitForView(withText(R.string.done))
clickOn(R.string.done)
}
}

View File

@@ -66,6 +66,38 @@ class ElementRobot {
waitForHome()
}
// Used for michaelk testing
fun login(homeserverURL: String, userId: String, password: String) {
val onboardingRobot = OnboardingRobot()
onboardingRobot.login(userId = userId, password = password, homeServerUrl = homeserverURL)
val analyticsRobot = AnalyticsRobot() // The application stores the analytics state on first open
analyticsRobot.optOut()
waitForHome()
}
// Used for michaelk testing
fun register(homeserverURL: String, userId: String, password: String) {
onboarding { createAccount(userId, password, homeServerUrl = homeserverURL) }
val analyticsRobot = AnalyticsRobot()
analyticsRobot.optOut()
waitForHome()
}
fun startVerification() {
val cryptoRobot = CryptoRobot()
cryptoRobot.startVerification()
}
fun acceptVerification() {
val cryptoRobot = CryptoRobot()
cryptoRobot.acceptVerification()
}
fun completeVerification() {
val cryptoRobot = CryptoRobot()
cryptoRobot.completeVerification()
}
private fun waitForHome() {
waitUntilActivityVisible<HomeActivity> {
waitUntilViewVisible(withId(R.id.roomListContainer))