Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
RingerJK committed May 23, 2023
1 parent b397692 commit b7a1787
Show file tree
Hide file tree
Showing 14 changed files with 518 additions and 17 deletions.
1 change: 1 addition & 0 deletions instrumentation-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ dependencies {
implementation project(':libnavigation-android')
implementation project(':libnavui-dropin')
implementation project(":libnavui-util")
implementation project(':libnavigator')

// test
androidTestImplementation project(':libtesting-ui')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package com.mapbox.navigation.instrumentation_tests.core

import android.content.Context
import android.location.Location
import androidx.test.platform.app.InstrumentationRegistry
import com.mapbox.bindgen.Value
import com.mapbox.common.SettingsServiceFactory
import com.mapbox.common.SettingsServiceStorageType
import com.mapbox.geojson.Point
import com.mapbox.navigation.base.options.DeviceProfile
import com.mapbox.navigation.base.options.NavigationOptions
import com.mapbox.navigation.base.trip.model.RouteProgressState
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.MapboxNavigationProvider
import com.mapbox.navigation.core.telemetry.events.FeedbackEvent
import com.mapbox.navigation.instrumentation_tests.activity.EmptyTestActivity
import com.mapbox.navigation.instrumentation_tests.utils.events.EventsAccumulatorRule
import com.mapbox.navigation.instrumentation_tests.utils.events.domain.EventArrive
import com.mapbox.navigation.instrumentation_tests.utils.events.domain.EventBase
import com.mapbox.navigation.instrumentation_tests.utils.events.domain.EventDepart
import com.mapbox.navigation.instrumentation_tests.utils.events.domain.EventFeedback
import com.mapbox.navigation.instrumentation_tests.utils.events.domain.EventFreeDrive
import com.mapbox.navigation.instrumentation_tests.utils.events.domain.EventNavigationStateChanged
import com.mapbox.navigation.instrumentation_tests.utils.events.verify.verifyEvents
import com.mapbox.navigation.instrumentation_tests.utils.http.EventsRequestHandle
import com.mapbox.navigation.instrumentation_tests.utils.location.MockLocationReplayerRule
import com.mapbox.navigation.instrumentation_tests.utils.routes.MockRoute
import com.mapbox.navigation.instrumentation_tests.utils.routes.RoutesProvider
import com.mapbox.navigation.instrumentation_tests.utils.routes.RoutesProvider.toNavigationRoutes
import com.mapbox.navigation.testing.ui.BaseTest
import com.mapbox.navigation.testing.ui.utils.MapboxNavigationRule
import com.mapbox.navigation.testing.ui.utils.coroutines.passed
import com.mapbox.navigation.testing.ui.utils.coroutines.rawLocationUpdates
import com.mapbox.navigation.testing.ui.utils.coroutines.routeProgressUpdates
import com.mapbox.navigation.testing.ui.utils.coroutines.sdkTest
import com.mapbox.navigation.testing.ui.utils.getMapboxAccessTokenFromResources
import com.mapbox.navigation.testing.ui.utils.runOnMainSync
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class TelemetryEventsTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.java) {

@get:Rule
val eventsAccumulatorRule = EventsAccumulatorRule(
getMapboxAccessTokenFromResources(InstrumentationRegistry.getInstrumentation().targetContext)
)

@get:Rule
val mockLocationReplayerRule = MockLocationReplayerRule(mockLocationUpdatesRule)

@get:Rule
val mapboxNavigationRule = MapboxNavigationRule()

private val coordinates = listOf(
Point.fromLngLat(-77.031991, 38.894721),
Point.fromLngLat(-77.031991, 38.895433),
Point.fromLngLat(-77.030923, 38.895433),
)

private lateinit var mapboxNavigation: MapboxNavigation
private val eventsRequestHandle = EventsRequestHandle()

private companion object {
private const val LOG_CATEGORY = "TelemetryEventsTest"

/* See mapbox_common_settings_internal.hpp in common repo */
private const val TELEMETRY_EVENTS_BASE_URL_PROPERTY =
"com.mapbox.common.telemetry.internal.events_base_url_override"

private fun createMapboxNavigation(context: Context): MapboxNavigation =
MapboxNavigationProvider.create(
NavigationOptions.Builder(context)
.accessToken(getMapboxAccessTokenFromResources(context))
.deviceProfile(
DeviceProfile.Builder()
.customConfig(
"""
{
"features": {
"useTelemetryNavigationEvents": true
},
"telemetry": {
"eventsPriority": "Immediate"
}
}
""".trimIndent()
)
.build()
)
.build()
)

/**
* Give the chance to send events: 5 attempts with 1 seconds delay
*/
private suspend fun waitForEventsBeSent(expectedEvents: Int, current: () -> Int) {
IntRange(0, 4).forEach { _ ->
if (expectedEvents == current()) {
return
} else {
delay(1_000)
}
}
}

private fun List<String>.prettyErrors(): String = joinToString(postfix = "\n")
}

override fun setupMockLocation(): Location = mockLocationUpdatesRule.generateLocationUpdate {
latitude = coordinates[0].latitude()
longitude = coordinates[0].longitude()
}

@Before
fun setup() {
runOnMainSync {
// substitute telemetry base url
SettingsServiceFactory.getInstance(SettingsServiceStorageType.NON_PERSISTENT).apply {
set(TELEMETRY_EVENTS_BASE_URL_PROPERTY, Value(mockWebServerRule.baseUrl))
}

mockWebServerRule.requestHandlers.add(eventsRequestHandle)
}
}

@Test
fun freeDrivePlain() = sdkTest {
val dcShorRoute = RoutesProvider.dc_short_with_alternative(activity).apply {
setRouteAsOriginLocation()
}
mapboxNavigation = createMapboxNavigation(activity)

mapboxNavigation.startTripSession()
mockLocationReplayerRule.playRoute(dcShorRoute.routeResponse.routes().first())
mapboxNavigation.rawLocationUpdates().passed(50.0).first()
mapboxNavigation.stopTripSession()

verifyResult(
EventFreeDrive(EventFreeDrive.Type.Start),
EventFreeDrive(EventFreeDrive.Type.Stop),
)
}

@Test
fun activeGuidancePlain() = sdkTest {
val dcShortRoute = RoutesProvider.dc_short_with_alternative(activity).apply {
setRouteAsOriginLocation()
}
mapboxNavigation = createMapboxNavigation(activity)
mockLocationReplayerRule.playbackSpeed(3.0)

mapboxNavigation.setNavigationRoutes(dcShortRoute.toNavigationRoutes())
mapboxNavigation.startTripSession()
mockLocationReplayerRule.playRoute(dcShortRoute.routeResponse.routes().first())
mapboxNavigation.routeProgressUpdates().first {
it.currentState == RouteProgressState.COMPLETE
}
mapboxNavigation.stopTripSession()

verifyResult(
EventNavigationStateChanged(EventNavigationStateChanged.State.NavStarted),
EventDepart(),
EventArrive(),
EventNavigationStateChanged(EventNavigationStateChanged.State.NavEnded),
)
}

@Test
fun freeDriveWithFeedback() = sdkTest(200_000) {
val dcShorRoute = RoutesProvider.dc_very_short_two_legs(activity)
mapboxNavigation = createMapboxNavigation(activity)
val feedbackType = "feedbackType"
val description = "description"
val screenshot = "screenshot"
val feedbackSubType = arrayOf("subType1", "subType2")

mapboxNavigation.startTripSession()
mockLocationReplayerRule.playRoute(dcShorRoute.routeResponse.routes().first())
mapboxNavigation.rawLocationUpdates().passed(20.0).first()
mapboxNavigation.postUserFeedback(
feedbackType = feedbackType,
description = description,
feedbackSource = "na",
screenshot = "screenshot",
feedbackSubType = feedbackSubType
)
mapboxNavigation.rawLocationUpdates().passed(20.0).first()
mapboxNavigation.stopTripSession()

verifyResult(
EventFreeDrive(EventFreeDrive.Type.Start),
EventFeedback(
driverMode = EventBase.DriverMode.FreeDrive,
feedbackType = feedbackType,
description = description,
feedbackSubType = feedbackSubType,
// TODO fixme when NN implement data_ref
screenshot = "c2NyZWVuc2hvdA==",
),
EventFreeDrive(EventFreeDrive.Type.Stop),
)
}

private suspend fun verifyResult(vararg expected: EventBase) {
waitForEventsBeSent(expected.size) { eventsAccumulatorRule.events.size }
val result = expected.asList().verifyEvents(eventsAccumulatorRule.events)

check(result.isEmpty()) {
result.prettyErrors()
}
}

private fun MockRoute.setRouteAsOriginLocation() {
mockLocationUpdatesRule.pushLocationUpdate(
mockLocationUpdatesRule.generateLocationUpdate {
latitude = this@setRouteAsOriginLocation.routeWaypoints.first().latitude()
longitude = this@setRouteAsOriginLocation.routeWaypoints.first().longitude()
}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.mapbox.navigation.instrumentation_tests.utils.events

import com.mapbox.bindgen.Value
import com.mapbox.common.EventsServerOptions
import com.mapbox.common.EventsService
import com.mapbox.common.EventsServiceError
import com.mapbox.common.EventsServiceObserver
import com.mapbox.navigation.utils.internal.logE
import com.mapbox.navigator.Navigator
import org.junit.rules.TestWatcher
import org.junit.runner.Description

class EventsAccumulatorRule(
mapboxToken: String,
) : TestWatcher() {

private val eventService = EventsService.getOrCreate(
EventsServerOptions(
mapboxToken, Navigator.getUserAgentFragment(), null
)
)

private val eventsServiceObserver = object : EventsServiceObserver {
override fun didEncounterError(error: EventsServiceError, events: Value) {
logE(LOG_CATEGORY) {
"Occurred error [$error] when send events: $events"
}
}

override fun didSendEvents(events: Value) {
_events.addAll(events.contents as List<Value>)
}
}

private val _events = mutableListOf<Value>()
val events: List<Value> get() = _events

private companion object {
private const val LOG_CATEGORY = "EventsAccumulatorRule"
}

override fun starting(description: Description?) {
_events.clear()
eventService.registerObserver(eventsServiceObserver)
}

override fun finished(description: Description?) {
eventService.unregisterObserver(eventsServiceObserver)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.mapbox.navigation.instrumentation_tests.utils.events.domain

internal abstract class EventBase(
driverMode: DriverMode,
) {
abstract val event: String
val eventVersion: Double = 2.4
val driverMode: String = when (driverMode) {
DriverMode.FreeDrive -> "freeDrive"
DriverMode.ActiveGuidance -> "trip"
}

enum class DriverMode {
FreeDrive,
ActiveGuidance,
}
}

internal abstract class EventBaseActiveGuidance(

) : EventBase(DriverMode.ActiveGuidance) {

}

internal class EventFeedback(
driverMode: DriverMode,
val feedbackType: String,
val description: String,
val feedbackSubType: Array<String>,
val screenshot: String,
): EventBase(driverMode) {
override val event: String = "navigation.feedback"
}

internal class EventFreeDrive(
eventType: Type,
) : EventBase(DriverMode.FreeDrive) {
override val event: String = "navigation.freeDrive"
val eventType: String = when (eventType) {
Type.Start -> "start"
Type.Stop -> "stop"
}

enum class Type {
Start,
Stop,
}
}

internal class EventNavigationStateChanged(
state: State,
) : EventBase(DriverMode.ActiveGuidance) {
override val event: String = "navigation.navigationStateChanged"
val state: String = when (state) {
State.NavStarted -> "navigation_started"
State.NavEnded -> "navigation_ended"
}

enum class State {
NavStarted,
NavEnded,
}
}

internal class EventDepart : EventBaseActiveGuidance() {
override val event: String = "navigation.depart"
}

internal class EventArrive : EventBaseActiveGuidance() {
override val event: String = "navigation.arrive"
}

/**
* "volumeLevel" -> {Value@20958} "33"
"driverMode" -> {Value@20960} "freeDrive"
"batteryPluggedIn" -> {Value@20962} "false"
"eventVersion" -> {Value@20964} "2.4"
"simulation" -> {Value@20966} "true"
"audioType" -> {Value@20968} "headphones"
"percentTimeInPortrait" -> {Value@20970} "100"
"operatingSystem" -> {Value@20972} "Android 11"
"driverModeId" -> {Value@20974} "6283cc3d-6262-4833-86f5-663581327e2f"
"connectivity" -> {Value@20976} "Unknown"
"driverModeStartTimestamp" -> {Value@20978} "2023-05-17T16:35:26.530Z"
"percentTimeInForeground" -> {Value@20980} "100"
"driverModeStartTimestampMonotime" -> {Value@20982} "526084002909708"
"event" -> {Value@20984} "navigation.freeDrive"
"lat" -> {Value@20986} "38.89514907122847"
"batteryLevel" -> {Value@20988} "100"
"lng" -> {Value@20990} "-77.03195362937024"
"created" -> {Value@20992} "2023-05-17T16:35:33.859Z"
"eventType" -> {Value@20994} "stop"
"version" -> {Value@20996} "2.4"
"sdkIdentifier" -> {Value@20998} "mapbox-navigation-android"
"createdMonotime" -> {Value@21000} "526091271247708"
"locationEngine" -> {Value@21002} "fused"
"screenBrightness" -> {Value@21004} "40"
"device" -> {Value@21006} "generic_x86 (x86; Android SDK built for x86)"
*/
Loading

0 comments on commit b7a1787

Please sign in to comment.