Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit d655b7e

Browse files
daoshengmukeianhzo
authored andcommitted
Support Glean metric unit tests (#2444)
* Support Glean unit test. * Run Glean unit test in Taskcluster.
1 parent 4739b3a commit d655b7e

File tree

7 files changed

+182
-9
lines changed

7 files changed

+182
-9
lines changed

.taskcluster.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ tasks:
4343
&& rm -rf gvr-android-sdk && git clone https://github.com/MozillaReality/FirefoxReality-gvr-android-sdk.git gvr-android-sdk
4444
&& git submodule update
4545
&& ./gradlew --no-daemon --console=plain clean `python tools/taskcluster/build_targets.py =all+googlevr+noapi`
46+
&& ./gradlew app:testNoapiArm64DebugUnitTest
4647
metadata:
4748
name: Firefox Reality for Android - Build - Pull Request
4849
description: Building Firefox Reality for Android (via Gradle) - triggered by a pull request.

app/build.gradle

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,10 @@ android {
414414
]
415415
}
416416
}
417+
418+
testOptions {
419+
unitTests.includeAndroidResources = true
420+
}
417421
}
418422

419423
configurations {
@@ -460,21 +464,18 @@ dependencies {
460464
implementation deps.android_components.support_rustlog
461465
implementation deps.android_components.support_rusthttp
462466
implementation deps.android_components.glean
467+
implementation deps.app_services.rustlog
463468

464469
// For production builds, the native code for all `org.mozilla.appservices`
465470
// dependencies gets compiled together into a single "megazord" build, and
466471
// different megazords are published for different subsets of features. Ref
467472
// https://mozilla.github.io/application-services/docs/applications/consuming-megazord-libraries.html
468473
// For now we can jut use the one that's specifically designed for Fenix.
469474
implementation deps.app_services.megazord
470-
testImplementation deps.app_services.megazord_forUnitTests
471475
modules {
472476
module('org.mozilla.appservices:full-megazord') {
473477
replacedBy('org.mozilla.appservices:fenix-megazord', 'prefer the fenix megazord, to reduce final application size')
474478
}
475-
module('org.mozilla.appservices:fenix-megazord') {
476-
replacedBy('org.mozilla.appservices:fenix-megazord-forUnitTests', 'prefer the forUnitTests variant if present')
477-
}
478479
}
479480

480481
// TODO this should not be necessary at all, see Services.kt
@@ -495,9 +496,16 @@ dependencies {
495496
implementation deps.disklrucache.disklrucache
496497

497498
// Testing
498-
testImplementation deps.junit
499499
androidTestImplementation deps.atsl.runner
500500
androidTestImplementation deps.espresso.core
501+
testImplementation deps.junit
502+
testImplementation deps.atsl.core
503+
testImplementation deps.robolectric
504+
testImplementation deps.app_services.megazord_forUnitTests
505+
testImplementation deps.app_services.rustlog
506+
testImplementation deps.android_components.support_test
507+
testImplementation deps.telemetry.glean_unittests
508+
testImplementation deps.work.testing
501509

502510
// Daydream
503511
googlevrImplementation deps.google_vr.sdk_base

app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ class Accounts constructor(val context: Context) {
229229

230230
private fun loadDefaultProfilePicture(): BitmapDrawable? {
231231
BitmapFactory.decodeResource(context.resources, R.drawable.ic_icon_settings_account)?.let {
232-
BitmapCache.getInstance(context).addBitmap(PROFILE_PICTURE_TAG, it)
232+
try {
233+
BitmapCache.getInstance(context).addBitmap(PROFILE_PICTURE_TAG, it)
234+
} catch (e: NullPointerException) {
235+
Log.w(LOGTAG, "Bitmap is a null pointer.")
236+
return null
237+
}
233238
profilePicture = BitmapDrawable(context.resources, ViewUtils.getRoundedCroppedBitmap(it))
234239
}
235240

app/src/common/shared/org/mozilla/vrbrowser/browser/Services.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import kotlinx.coroutines.CoroutineScope
1515
import kotlinx.coroutines.Dispatchers
1616
import kotlinx.coroutines.launch
1717
import mozilla.appservices.Megazord
18+
import mozilla.appservices.rustlog.LogAdapterCannotEnable
1819
import mozilla.components.concept.sync.*
1920
import mozilla.components.service.fxa.*
2021
import mozilla.components.service.fxa.manager.FxaAccountManager
@@ -29,8 +30,6 @@ import org.mozilla.geckoview.GeckoResult
2930
import org.mozilla.geckoview.GeckoSession
3031
import org.mozilla.vrbrowser.R
3132
import org.mozilla.vrbrowser.browser.engine.EngineProvider
32-
import org.mozilla.vrbrowser.browser.engine.GeckoViewFetchClient
33-
import org.mozilla.vrbrowser.browser.engine.SessionStore
3433
import org.mozilla.vrbrowser.utils.SystemUtils
3534
import org.mozilla.vrbrowser.telemetry.GleanMetricsService
3635

@@ -52,7 +51,11 @@ class Services(val context: Context, places: Places): GeckoSession.NavigationDel
5251
// This makes bookmarks storage accessible to background sync workers.
5352
init {
5453
Megazord.init()
55-
RustLog.enable()
54+
try {
55+
RustLog.enable()
56+
} catch (e: LogAdapterCannotEnable) {
57+
android.util.Log.w(LOGTAG, "RustLog has been enabled.")
58+
}
5659
RustHttpConfig.setClient(lazy { EngineProvider.createClient(context) })
5760

5861
// Make sure we get logs out of our android-components.

app/src/common/shared/org/mozilla/vrbrowser/telemetry/GleanMetricsService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import androidx.annotation.NonNull;
77
import androidx.annotation.UiThread;
8+
import androidx.annotation.VisibleForTesting;
89

910
import org.mozilla.vrbrowser.BuildConfig;
1011
import org.mozilla.vrbrowser.GleanMetrics.Distribution;
@@ -159,6 +160,11 @@ private static void setStartupMetrics() {
159160
Distribution.INSTANCE.getChannelName().set(DeviceType.isOculusBuild() ? "oculusvr" : BuildConfig.FLAVOR_platform);
160161
}
161162

163+
@VisibleForTesting
164+
public static void testSetStartupMetrics() {
165+
setStartupMetrics();
166+
}
167+
162168
public static class FxA {
163169

164170
public static void signIn() {
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package org.mozilla.vrbrowser
2+
3+
import androidx.test.core.app.ApplicationProvider
4+
import mozilla.components.concept.sync.DeviceType
5+
import mozilla.components.service.glean.testing.GleanTestRule
6+
import org.junit.Assert.*
7+
import org.junit.Rule
8+
import org.junit.Test
9+
import org.junit.runner.RunWith
10+
import org.mozilla.vrbrowser.GleanMetrics.*
11+
import org.mozilla.vrbrowser.telemetry.GleanMetricsService
12+
import org.robolectric.RobolectricTestRunner
13+
import org.robolectric.annotation.Config
14+
15+
16+
@RunWith(RobolectricTestRunner::class)
17+
@Config(manifest = Config.NONE)
18+
class GleanMetricsServiceTest {
19+
20+
@get:Rule
21+
val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext())
22+
23+
@Test
24+
fun testURLTelemetry() {
25+
assertFalse(Url.domains.testHasValue())
26+
assertFalse(Url.visits.testHasValue())
27+
GleanMetricsService.stopPageLoadTimeWithURI("https://www.example.com/test.html");
28+
assertTrue(Url.domains.testHasValue())
29+
assertEquals(Url.domains.testGetValue(), 1)
30+
31+
assertTrue(Url.visits.testHasValue())
32+
assertEquals(Url.visits.testGetValue(), 1)
33+
34+
assertFalse(Url.queryType["type_link"].testHasValue())
35+
assertFalse(Url.queryType["type_query"].testHasValue())
36+
GleanMetricsService.urlBarEvent(true)
37+
assertTrue(Url.queryType["type_link"].testHasValue())
38+
assertEquals(Url.queryType["type_link"].testGetValue(), 1)
39+
GleanMetricsService.urlBarEvent(false)
40+
assertTrue(Url.queryType["type_query"].testHasValue())
41+
assertEquals(Url.queryType["type_query"].testGetValue(), 1)
42+
43+
assertFalse(Url.queryType["voice_query"].testHasValue())
44+
GleanMetricsService.voiceInputEvent()
45+
assertTrue(Url.queryType["voice_query"].testHasValue())
46+
assertEquals(Url.queryType["voice_query"].testGetValue(), 1)
47+
}
48+
49+
@Test
50+
fun testDistributionChannelTelemetry() {
51+
assertFalse(Distribution.channelName.testHasValue())
52+
GleanMetricsService.testSetStartupMetrics()
53+
assertTrue(Distribution.channelName.testHasValue())
54+
assertEquals(Distribution.channelName.testGetValue(), BuildConfig.FLAVOR_platform)
55+
}
56+
57+
@Test
58+
fun testFxAAccountTelemetry() {
59+
assertFalse(FirefoxAccount.signIn.testHasValue())
60+
GleanMetricsService.FxA.signIn()
61+
assertTrue(FirefoxAccount.signIn.testHasValue())
62+
var events = FirefoxAccount.signIn.testGetValue()
63+
assertEquals(events.size, 1)
64+
65+
assertFalse(FirefoxAccount.signInResult.testHasValue())
66+
GleanMetricsService.FxA.signInResult(false)
67+
assertTrue(FirefoxAccount.signInResult.testHasValue())
68+
events = FirefoxAccount.signInResult.testGetValue()
69+
assertEquals(events.size, 1)
70+
// We only expect 1 extra key.
71+
assertEquals(events[0].extra!!.size, 1)
72+
assertEquals(events[0].extra!!["state"], "false")
73+
74+
GleanMetricsService.FxA.signInResult(true)
75+
events = FirefoxAccount.signInResult.testGetValue()
76+
assertEquals(events.size, 2)
77+
// We only expect 1 extra key.
78+
assertEquals(events[1].extra!!.size, 1)
79+
assertEquals(events[1].extra!!["state"], "true")
80+
81+
assertFalse(FirefoxAccount.signOut.testHasValue())
82+
GleanMetricsService.FxA.signOut()
83+
assertTrue(FirefoxAccount.signOut.testHasValue())
84+
events = FirefoxAccount.signOut.testGetValue()
85+
assertEquals(events.size, 1)
86+
}
87+
88+
@Test
89+
fun testFxABookmarkTelemetry() {
90+
assertFalse(FirefoxAccount.bookmarksSyncStatus.testHasValue())
91+
GleanMetricsService.FxA.bookmarksSyncStatus(false)
92+
assertTrue(FirefoxAccount.bookmarksSyncStatus.testHasValue())
93+
assertEquals(FirefoxAccount.bookmarksSyncStatus.testGetValue(), false)
94+
95+
GleanMetricsService.FxA.bookmarksSyncStatus(true)
96+
assertEquals(FirefoxAccount.bookmarksSyncStatus.testGetValue(), true)
97+
}
98+
99+
@Test
100+
fun testFxAHistoryTelemetry() {
101+
assertFalse(FirefoxAccount.historySyncStatus.testHasValue())
102+
GleanMetricsService.FxA.historySyncStatus(false)
103+
assertTrue(FirefoxAccount.historySyncStatus.testHasValue())
104+
assertEquals(FirefoxAccount.historySyncStatus.testGetValue(), false)
105+
106+
GleanMetricsService.FxA.historySyncStatus(true)
107+
assertEquals(FirefoxAccount.historySyncStatus.testGetValue(), true)
108+
}
109+
110+
@Test
111+
fun testFxATabTelemetry() {
112+
assertFalse(FirefoxAccount.tabSent.testHasValue())
113+
GleanMetricsService.FxA.sentTab()
114+
assertTrue(FirefoxAccount.tabSent.testHasValue())
115+
assertEquals(FirefoxAccount.tabSent.testGetValue(), 1)
116+
117+
assertFalse(FirefoxAccount.receivedTab[DeviceType.MOBILE.name].testHasValue())
118+
GleanMetricsService.FxA.receivedTab(DeviceType.MOBILE)
119+
assertTrue(FirefoxAccount.receivedTab[DeviceType.MOBILE.name].testHasValue())
120+
assertEquals(FirefoxAccount.receivedTab[DeviceType.MOBILE.name].testGetValue(), 1)
121+
}
122+
123+
@Test
124+
fun testTabTelemetry() {
125+
assertFalse(Tabs.opened[GleanMetricsService.Tabs.TabSource.BOOKMARKS.name].testHasValue())
126+
GleanMetricsService.Tabs.openedCounter(GleanMetricsService.Tabs.TabSource.BOOKMARKS)
127+
assertTrue(Tabs.opened[GleanMetricsService.Tabs.TabSource.BOOKMARKS.name].testHasValue())
128+
assertEquals(Tabs.opened[GleanMetricsService.Tabs.TabSource.BOOKMARKS.name].testGetValue(), 1)
129+
130+
assertFalse(Tabs.activated.testHasValue())
131+
GleanMetricsService.Tabs.activatedEvent()
132+
assertTrue(Tabs.activated.testHasValue())
133+
assertEquals(Tabs.activated.testGetValue(), 1)
134+
}
135+
}

versions.gradle

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ versions.support = "1.0.0"
4242
versions.recyclerview = "1.1.0"
4343
versions.constraint_layout = "2.0.0-alpha2"
4444
versions.junit = "4.12"
45+
versions.atsl_core = "1.2.0"
4546
versions.atsl_runner = "1.1.0-alpha4"
4647
versions.atsl_rules = "1.1.0-alpha4"
4748
versions.espresso = "3.1.0-alpha4"
@@ -50,7 +51,11 @@ versions.kotlin = "1.3.31"
5051
versions.kotlin_coroutines = "1.2.1"
5152
versions.snakeyaml = "1.24"
5253
versions.gson = "2.8.5"
54+
versions.robolectric = "4.2.1"
55+
versions.work = "2.2.0"
56+
versions.telemetry = "22.0.0"
5357
ext.versions = versions
58+
5459
def deps = [:]
5560

5661
def gecko_view = [:]
@@ -72,11 +77,13 @@ android_components.concept_fetch = "org.mozilla.components:concept-fetch:$versio
7277
android_components.lib_fetch = "org.mozilla.components:lib-fetch-httpurlconnection:$versions.android_components"
7378
android_components.support_rustlog = "org.mozilla.components:support-rustlog:$versions.android_components"
7479
android_components.support_rusthttp = "org.mozilla.components:support-rusthttp:$versions.android_components"
80+
android_components.support_test = "org.mozilla.components:support-test:$versions.android_components"
7581
deps.android_components = android_components
7682

7783
def app_services = [:]
7884
app_services.megazord = "org.mozilla.appservices:fenix-megazord:${versions.mozilla_appservices}"
7985
app_services.megazord_forUnitTests = "org.mozilla.appservices:fenix-megazord-forUnitTests:${versions.mozilla_appservices}"
86+
app_services.rustlog = "org.mozilla.appservices:rustlog:${versions.mozilla_appservices}"
8087
deps.app_services = app_services
8188

8289
deps.mozilla_speech = "com.github.mozilla:mozillaspeechlibrary:$versions.mozilla_speech"
@@ -102,6 +109,7 @@ deps.support = support
102109
// TODO this should not be necessary at all, see Services.kt
103110
def work = [:]
104111
work.runtime = "androidx.work:work-runtime-ktx:$versions.work"
112+
work.testing = "androidx.work:work-testing:$versions.work"
105113
deps.work = work
106114

107115
def room = [:]
@@ -124,6 +132,7 @@ espresso.intents = "androidx.test.espresso:espresso-intents:$versions.espresso"
124132
deps.espresso = espresso
125133

126134
def atsl = [:]
135+
atsl.core = "androidx.test:core-ktx:$versions.atsl_core"
127136
atsl.runner = "androidx.test:runner:$versions.atsl_runner"
128137
atsl.rules = "androidx.test:rules:$versions.atsl_runner"
129138
deps.atsl = atsl
@@ -145,6 +154,10 @@ kotlin.coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.kot
145154
kotlin.coroutines_jdk8 = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$versions.kotlin_coroutines"
146155
deps.kotlin = kotlin
147156

157+
def telemetry = [:]
158+
telemetry.glean_unittests = "org.mozilla.telemetry:glean-forUnitTests:$versions.telemetry"
159+
deps.telemetry = telemetry
160+
148161
deps.constraint_layout = "androidx.constraintlayout:constraintlayout:$versions.constraint_layout"
149162

150163
deps.junit = "junit:junit:$versions.junit"
@@ -157,6 +170,8 @@ deps.snakeyaml = "org.yaml:snakeyaml:$versions.snakeyaml:android"
157170

158171
deps.gson = "com.google.code.gson:gson:$versions.gson"
159172

173+
deps.robolectric = "org.robolectric:robolectric:$versions.robolectric"
174+
160175
ext.deps = deps
161176

162177
def build_versions = [:]

0 commit comments

Comments
 (0)