From 0abb2c4f8b57985d6b8d89c7db6610cb7a6ff874 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Fri, 17 Jul 2020 16:19:32 -0700 Subject: [PATCH] Add tests for web push integration --- .../fenix/push/WebPushEngineIntegration.kt | 9 +- .../push/WebPushEngineIntegrationTest.kt | 183 ++++++++++++++++++ 2 files changed, 188 insertions(+), 4 deletions(-) create mode 100644 app/src/test/java/org/mozilla/fenix/push/WebPushEngineIntegrationTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt b/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt index c23bd13df..646b20ee9 100644 --- a/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt +++ b/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt @@ -6,7 +6,7 @@ package org.mozilla.fenix.push import android.util.Base64 import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import mozilla.components.concept.engine.Engine import mozilla.components.concept.engine.webpush.WebPushDelegate @@ -22,7 +22,8 @@ import mozilla.components.support.base.log.logger.Logger */ class WebPushEngineIntegration( private val engine: Engine, - private val pushFeature: AutoPushFeature + private val pushFeature: AutoPushFeature, + private val coroutineScope: CoroutineScope = MainScope() ) : AutoPushFeature.Observer { private var handler: WebPushHandler? = null @@ -39,13 +40,13 @@ class WebPushEngineIntegration( } override fun onMessageReceived(scope: PushScope, message: ByteArray?) { - CoroutineScope(Dispatchers.Main).launch { + coroutineScope.launch { handler?.onPushMessage(scope, message) } } override fun onSubscriptionChanged(scope: PushScope) { - CoroutineScope(Dispatchers.Main).launch { + coroutineScope.launch { handler?.onSubscriptionChanged(scope) } } diff --git a/app/src/test/java/org/mozilla/fenix/push/WebPushEngineIntegrationTest.kt b/app/src/test/java/org/mozilla/fenix/push/WebPushEngineIntegrationTest.kt new file mode 100644 index 000000000..08354def9 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/push/WebPushEngineIntegrationTest.kt @@ -0,0 +1,183 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.push + +import android.util.Base64 +import io.mockk.Called +import io.mockk.CapturingSlot +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.slot +import io.mockk.unmockkStatic +import io.mockk.verify +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.runBlockingTest +import mozilla.components.concept.engine.Engine +import mozilla.components.concept.engine.webpush.WebPushDelegate +import mozilla.components.concept.engine.webpush.WebPushHandler +import mozilla.components.concept.engine.webpush.WebPushSubscription +import mozilla.components.feature.push.AutoPushFeature +import mozilla.components.feature.push.AutoPushSubscription +import org.junit.After +import org.junit.Before +import org.junit.Test + +@ExperimentalCoroutinesApi +class WebPushEngineIntegrationTest { + + private val scope = TestCoroutineScope() + @MockK private lateinit var engine: Engine + @MockK private lateinit var pushFeature: AutoPushFeature + @MockK(relaxed = true) private lateinit var handler: WebPushHandler + private lateinit var delegate: CapturingSlot + private lateinit var integration: WebPushEngineIntegration + + @Before + fun setup() { + MockKAnnotations.init(this) + mockkStatic(Base64::class) + delegate = slot() + + every { engine.registerWebPushDelegate(capture(delegate)) } returns handler + every { pushFeature.register(any()) } just Runs + every { pushFeature.unregister(any()) } just Runs + every { Base64.decode(any(), any()) } answers { firstArg() } + + integration = WebPushEngineIntegration(engine, pushFeature, scope) + } + + @After + fun teardown() { + unmockkStatic(Base64::class) + } + + @Test + fun `methods are no-op before calling start`() = scope.runBlockingTest { + integration.onMessageReceived("push", null) + integration.onSubscriptionChanged("push") + verify { handler wasNot Called } + + integration.start() + + integration.onMessageReceived("push", null) + verify { handler.onPushMessage("push", null) } + + integration.onSubscriptionChanged("push") + verify { handler.onSubscriptionChanged("push") } + } + + @Test + fun `start and stop register and unregister pushFeature`() { + integration.start() + verify { pushFeature.register(integration) } + + integration.stop() + verify { pushFeature.unregister(integration) } + } + + @Test + fun `delegate calls getSubscription`() { + integration.start() + val slot = slot<(AutoPushSubscription?) -> Unit>() + every { pushFeature.getSubscription("scope", block = capture(slot)) } just Runs + + val onSubscription = mockk<(WebPushSubscription?) -> Unit>(relaxed = true) + delegate.captured.onGetSubscription("scope", onSubscription) + + verify { onSubscription wasNot Called } + slot.captured(AutoPushSubscription( + scope = "scope", + publicKey = "abc", + endpoint = "def", + authKey = "xyz", + appServerKey = null + )) + + verify { + onSubscription( + WebPushSubscription( + scope = "scope", + publicKey = "abc".toByteArray(), + endpoint = "def", + authSecret = "xyz".toByteArray(), + appServerKey = null + ) + ) + } + } + + @Test + fun `delegate calls subscribe`() { + integration.start() + val onSubscribeError = slot<() -> Unit>() + val onSubscribe = slot<(AutoPushSubscription?) -> Unit>() + every { + pushFeature.subscribe( + scope = "scope", + appServerKey = null, + onSubscribeError = capture(onSubscribeError), + onSubscribe = capture(onSubscribe) + ) + } just Runs + + val onSubscription = mockk<(WebPushSubscription?) -> Unit>(relaxed = true) + delegate.captured.onSubscribe("scope", null, onSubscription) + + verify { onSubscription wasNot Called } + + onSubscribeError.captured() + verify { onSubscription(null) } + + onSubscribe.captured(AutoPushSubscription( + scope = "scope", + publicKey = "abc", + endpoint = "def", + authKey = "xyz", + appServerKey = null + )) + verify { + onSubscription( + WebPushSubscription( + scope = "scope", + publicKey = "abc".toByteArray(), + endpoint = "def", + authSecret = "xyz".toByteArray(), + appServerKey = null + ) + ) + } + } + + @Test + fun `delegate calls unsubscribe`() { + integration.start() + val onUnsubscribeError = slot<() -> Unit>() + val onUnsubscribe = slot<(Boolean) -> Unit>() + every { + pushFeature.unsubscribe( + scope = "scope", + onUnsubscribeError = capture(onUnsubscribeError), + onUnsubscribe = capture(onUnsubscribe) + ) + } just Runs + + val onUnsubscription = mockk<(Boolean) -> Unit>(relaxed = true) + delegate.captured.onUnsubscribe("scope", onUnsubscription) + + verify { onUnsubscription wasNot Called } + + onUnsubscribeError.captured() + verify { onUnsubscription(false) } + + onUnsubscribe.captured(true) + verify { onUnsubscription(true) } + } +}