Skip to content

Commit 1b368b9

Browse files
committed
Fix the flaky "metrics" scheduler tests
This raises the timeout value for the testing API from 250ms to 5seconds, since the CI infrastructure could be under stress or slow. This additionally adds more logging to the "metrics" ping scheduler in order to make it easier to diagnose startup problems.
1 parent c6f7864 commit 1b368b9

File tree

7 files changed

+28
-12
lines changed

7 files changed

+28
-12
lines changed

components/service/glean/src/main/java/mozilla/components/service/glean/CommonMetricData.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ interface CommonMetricData {
4444

4545
companion object {
4646
internal const val DEFAULT_STORAGE_NAME = "default"
47-
private const val JOB_TIMEOUT_MS = 250L
47+
// The job timeout is useful in tests, which are usually running on CI
48+
// infrastructure. The timeout needs to be reasonably high to account for
49+
// slow or under-stress hardware.
50+
private const val JOB_TIMEOUT_MS = 5000L
4851
}
4952

5053
fun shouldRecord(logger: Logger): Boolean {

components/service/glean/src/main/java/mozilla/components/service/glean/ping/PingMaker.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ internal class PingMaker(
119119
* @return a string holding the data for the ping, or null if there is no data to send.
120120
*/
121121
fun collect(storage: String): String? {
122+
logger.debug("Collecting $storage")
122123
val jsonPing = storageManager.collect(storage)
123124

124125
// Return null if there is nothing in the jsonPing object so that this can be used by

components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/MetricsPingScheduler.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ internal class MetricsPingScheduler(val applicationContext: Context) {
201201
// The ping wasn't already sent today. Are we overdue or just waiting for
202202
// the right time?
203203
isAfterDueTime(now) -> {
204+
logger.info("The 'metrics' ping is scheduled for immediate collection")
204205
// The reason why we're collecting the "metrics" ping in the `Dispatchers.API`
205206
// context is that we want to make sure no other metric API adds data before
206207
// the ping is collected. All the exposed metrics API dispatch calls to the
@@ -214,6 +215,7 @@ internal class MetricsPingScheduler(val applicationContext: Context) {
214215
}
215216
else -> {
216217
// This covers (3).
218+
logger.info("The 'metrics' collection scheduled for the next calendar day")
217219
schedulePingCollection(now, sendTheNextCalendarDay = false)
218220
}
219221
}

components/service/glean/src/main/java/mozilla/components/service/glean/storages/PingStorageEngine.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ internal class PingStorageEngine(context: Context) {
5252
* @param ping Serialized JSON string representing the ping payload
5353
*/
5454
fun store(uuidFileName: UUID, pingPath: String, pingData: String): Job {
55+
logger.debug("Storing ping $uuidFileName in $pingPath")
5556
return GlobalScope.launch(KotlinDispatchers.IO) {
5657
// Check that the director exists and create it if needed
5758
ensureDirectoryExists(storageDirectory)

components/service/glean/src/test/java/mozilla/components/service/glean/GleanTest.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.test.core.app.ApplicationProvider
1212
import androidx.work.testing.WorkManagerTestInitHelper
1313
import kotlinx.coroutines.ExperimentalCoroutinesApi
1414
import kotlinx.coroutines.ObsoleteCoroutinesApi
15+
import kotlinx.coroutines.runBlocking
1516
import mozilla.components.service.glean.storages.StringsStorageEngine
1617
import mozilla.components.service.glean.scheduler.GleanLifecycleObserver
1718
import mozilla.components.service.glean.scheduler.PingUploadWorker
@@ -237,24 +238,29 @@ class GleanTest {
237238
val gleanSpy = spy<GleanInternalAPI>(GleanInternalAPI::class.java)
238239

239240
gleanSpy.initialized = false
240-
gleanSpy.handleBackgroundEvent()
241+
runBlocking {
242+
gleanSpy.handleBackgroundEvent()
243+
}
241244
assertFalse(isWorkScheduled(PingUploadWorker.PING_WORKER_TAG))
242245
}
243246

244247
@Test
245248
fun `Don't schedule pings if metrics disabled`() {
246249
Glean.setUploadEnabled(false)
247250

248-
Glean.handleBackgroundEvent()
249-
251+
runBlocking {
252+
Glean.handleBackgroundEvent()
253+
}
250254
assertFalse(isWorkScheduled(PingUploadWorker.PING_WORKER_TAG))
251255
}
252256

253257
@Test
254258
fun `Don't schedule pings if there is no ping content`() {
255259
resetGlean(getContextWithMockedInfo())
256260

257-
Glean.handleBackgroundEvent()
261+
runBlocking {
262+
Glean.handleBackgroundEvent()
263+
}
258264

259265
// We should only have a baseline ping and no events or metrics pings since nothing was
260266
// recorded

components/service/glean/src/test/java/mozilla/components/service/glean/TestUtil.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ internal fun isWorkScheduled(tag: String): Boolean {
180180
*/
181181
internal fun triggerWorkManager() {
182182
// Check that the work is scheduled
183-
Assert.assertTrue(isWorkScheduled(PingUploadWorker.PING_WORKER_TAG))
183+
Assert.assertTrue("A scheduled PingUploadWorker must exist",
184+
isWorkScheduled(PingUploadWorker.PING_WORKER_TAG))
184185

185186
// Since WorkManager does not properly run in tests, simulate the work being done
186187
GlobalScope.launch(Dispatchers.IO) {

components/service/glean/src/test/java/mozilla/components/service/glean/scheduler/MetricsPingSchedulerTest.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class MetricsPingSchedulerTest {
262262

263263
val expectedValue = "test-only metric"
264264
testMetric.set(expectedValue)
265-
assertTrue(testMetric.testHasValue())
265+
assertTrue("The initial test data must have been recorded", testMetric.testHasValue())
266266

267267
// Manually call the function to trigger the collection.
268268
Glean.metricsPingScheduler.collectPingAndReschedule(Calendar.getInstance())
@@ -272,14 +272,15 @@ class MetricsPingSchedulerTest {
272272

273273
// Fetch the ping from the server and decode its JSON body.
274274
val request = server.takeRequest(20L, AndroidTimeUnit.SECONDS)
275-
assertEquals("POST", request.method)
276275
val metricsJsonData = request.body.readUtf8()
277276
val metricsJson = JSONObject(metricsJsonData)
278277

279278
// Validate the received data.
280279
checkPingSchema(metricsJson)
281-
assertEquals("metrics", metricsJson.getJSONObject("ping_info")["ping_type"])
280+
assertEquals("The received ping must be a 'metrics' ping",
281+
"metrics", metricsJson.getJSONObject("ping_info")["ping_type"])
282282
assertEquals(
283+
"The reported metric must contain the expected value",
283284
expectedValue,
284285
metricsJson.getJSONObject("metrics")
285286
.getJSONObject("string")
@@ -420,7 +421,7 @@ class MetricsPingSchedulerTest {
420421
// Record the data we expect to be in the final metrics ping.
421422
val expectedValue = "expected_data!"
422423
stringMetric.set(expectedValue)
423-
assertTrue(stringMetric.testHasValue())
424+
assertTrue("The initial expected data must be recorded", stringMetric.testHasValue())
424425

425426
// Pretend glean is disabled. This is used so that any API call will be discarded and
426427
// glean will init again.
@@ -477,14 +478,15 @@ class MetricsPingSchedulerTest {
477478
}
478479

479480
// Parse the received ping payload to a JSON object.
480-
assertEquals("POST", request.method)
481481
val metricsJsonData = request.body.readUtf8()
482482
val metricsJson = JSONObject(metricsJsonData)
483483

484484
// Validate the received data.
485485
checkPingSchema(metricsJson)
486-
assertEquals("metrics", metricsJson.getJSONObject("ping_info")["ping_type"])
486+
assertEquals("The received ping must be a 'metrics' ping",
487+
"metrics", metricsJson.getJSONObject("ping_info")["ping_type"])
487488
assertEquals(
489+
"The reported metric must contain the expected value",
488490
expectedValue,
489491
metricsJson.getJSONObject("metrics")
490492
.getJSONObject("string")

0 commit comments

Comments
 (0)