diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt index bf9147aec..51c7feae2 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt @@ -10,6 +10,6 @@ internal class NotificationReceivedEvent( var effectiveNotification: Notification? = notification override fun complete(notification: INotification?) { - effectiveNotification = notification as Notification + effectiveNotification = notification as Notification? } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt index 63e0f2b40..3bebf8cc4 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt @@ -2,6 +2,7 @@ package com.onesignal.notifications.internal.generation.impl import android.content.Context import com.onesignal.common.AndroidUtils +import com.onesignal.common.safeString import com.onesignal.core.internal.application.IApplicationService import com.onesignal.core.internal.config.ConfigModelStore import com.onesignal.core.internal.time.ITime @@ -15,7 +16,6 @@ import com.onesignal.notifications.internal.display.INotificationDisplayer import com.onesignal.notifications.internal.generation.INotificationGenerationProcessor import com.onesignal.notifications.internal.lifecycle.INotificationLifecycleService import com.onesignal.notifications.internal.summary.INotificationSummaryManager -import com.onesignal.session.internal.session.ISessionService import kotlinx.coroutines.delay import kotlinx.coroutines.withTimeout import org.json.JSONException @@ -32,7 +32,6 @@ internal class NotificationGenerationProcessor( private val _dataController: INotificationRepository, private val _notificationSummaryManager: INotificationSummaryManager, private val _lifecycleService: INotificationLifecycleService, - private val _sessionService: ISessionService, private val _time: ITime ) : INotificationGenerationProcessor { @@ -229,7 +228,7 @@ internal class NotificationGenerationProcessor( _dataController.createNotification( customJSON.optString("i"), - jsonPayload.optString("grp"), + jsonPayload.safeString("grp"), collapseKey, notificationJob.isNotificationToDisplay, // When notification was displayed, count any notifications with duplicated android notification ids as dismissed. opened, diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt index 4c19d2760..3e045b2f2 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt @@ -37,7 +37,7 @@ internal class PushTokenManager( // runtime error if (pushToken == null && ( - pushTokenStatus == SubscriptionStatus.SUBSCRIBED || + pushTokenStatus == SubscriptionStatus.NO_PERMISSION || pushStatusRuntimeError(pushTokenStatus) ) ) { diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/ExampleUnitTest.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/ExampleUnitTest.kt deleted file mode 100644 index 3ebe1551c..000000000 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/ExampleUnitTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.onesignal.notifications - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt new file mode 100644 index 000000000..873c62cc6 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt @@ -0,0 +1,67 @@ +/** + * Code taken from https://github.com/kotest/kotest-extensions-robolectric with no changes. + * + * LICENSE: https://github.com/kotest/kotest-extensions-robolectric/blob/master/LICENSE + */ +package com.onesignal.notifications.extensions + +import org.junit.runners.model.FrameworkMethod +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.internal.bytecode.InstrumentationConfiguration +import org.robolectric.pluginapi.config.ConfigurationStrategy +import org.robolectric.plugins.ConfigConfigurer +import java.lang.reflect.Method + +internal class ContainedRobolectricRunner( + private val config: Config? +) : RobolectricTestRunner(PlaceholderTest::class.java, injector) { + private val placeHolderMethod: FrameworkMethod = children[0] + val sdkEnvironment = getSandbox(placeHolderMethod).also { + configureSandbox(it, placeHolderMethod) + } + private val bootStrapMethod = sdkEnvironment.bootstrappedClass(testClass.javaClass) + .getMethod(PlaceholderTest::bootStrapMethod.name) + + fun containedBefore() { + Thread.currentThread().contextClassLoader = sdkEnvironment.robolectricClassLoader + super.beforeTest(sdkEnvironment, placeHolderMethod, bootStrapMethod) + } + + fun containedAfter() { + super.afterTest(placeHolderMethod, bootStrapMethod) + super.finallyAfterTest(placeHolderMethod) + Thread.currentThread().contextClassLoader = ContainedRobolectricRunner::class.java.classLoader + } + + override fun createClassLoaderConfig(method: FrameworkMethod?): InstrumentationConfiguration { + return InstrumentationConfiguration.Builder(super.createClassLoaderConfig(method)) + .doNotAcquirePackage("io.kotest") + .build() + } + + override fun getConfig(method: Method?): Config { + val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java) + .getConfig(testClass.javaClass, method) + + if (config != null) { + val configConfigurer = injector.getInstance(ConfigConfigurer::class.java) + return configConfigurer.merge(defaultConfiguration[Config::class.java], config) + } + + return super.getConfig(method) + } + + class PlaceholderTest { + @org.junit.Test + fun testPlaceholder() { + } + + fun bootStrapMethod() { + } + } + + companion object { + private val injector = defaultInjector().build() + } +} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt new file mode 100644 index 000000000..ce40e0fc5 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt @@ -0,0 +1,96 @@ +/** + * Code taken from https://github.com/kotest/kotest-extensions-robolectric with a + * fix in the intercept method. + * + * LICENSE: https://github.com/kotest/kotest-extensions-robolectric/blob/master/LICENSE + */ +package com.onesignal.notifications.extensions + +import android.app.Application +import io.kotest.core.extensions.ConstructorExtension +import io.kotest.core.extensions.TestCaseExtension +import io.kotest.core.spec.AutoScan +import io.kotest.core.spec.Spec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import org.robolectric.annotation.Config +import kotlin.reflect.KClass +import kotlin.reflect.full.findAnnotation + +/** + * We override TestCaseExtension to configure the Robolectric environment because TestCase intercept + * occurs on the same thread the test is run. This is unfortunate because it is run for every test, + * rather than every spec. But the SpecExtension intercept is run on a different thread. + */ +@AutoScan +internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { + private fun Class<*>.getParentClass(): List> { + if (superclass == null) return listOf() + return listOf(superclass) + superclass.getParentClass() + } + + private fun KClass<*>.getConfig(): Config { + val configAnnotations = listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() + + val configAnnotation = configAnnotations.firstOrNull() + + if (configAnnotation != null) { + return Config.Builder(configAnnotation).build() + } + + val robolectricTestAnnotations = listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() + + val application: KClass? = robolectricTestAnnotations + .firstOrNull { it.application != KotestDefaultApplication::class }?.application + val sdk: Int? = robolectricTestAnnotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk + + return Config.Builder() + .also { builder -> + if (application != null) { + builder.setApplication(application.java) + } + + if (sdk != null) { + builder.setSdk(sdk) + } + }.build() + } + + override fun instantiate(clazz: KClass): Spec? { + clazz.findAnnotation() ?: return null + + return ContainedRobolectricRunner(clazz.getConfig()) + .sdkEnvironment.bootstrappedClass(clazz.java).newInstance() + } + + override suspend fun intercept( + testCase: TestCase, + execute: suspend (TestCase) -> TestResult + ): TestResult { + // FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717 + val hasRobolectricAnnotation = testCase.spec::class.annotations.any { annotation -> + annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName + } + + if (!hasRobolectricAnnotation) { + return execute(testCase) + } + + val containedRobolectricRunner = ContainedRobolectricRunner(testCase.spec::class.getConfig()) + containedRobolectricRunner.containedBefore() + val result = execute(testCase) + containedRobolectricRunner.containedAfter() + return result + } +} + +internal class KotestDefaultApplication : Application() + +annotation class RobolectricTest( + val application: KClass = KotestDefaultApplication::class, + val sdk: Int = -1 +) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt new file mode 100644 index 000000000..8fc21b98c --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt @@ -0,0 +1,182 @@ +package com.onesignal.notifications.internal.backend + +import com.onesignal.common.exceptions.BackendException +import com.onesignal.core.internal.device.IDeviceService +import com.onesignal.core.internal.http.HttpResponse +import com.onesignal.core.internal.http.IHttpClient +import com.onesignal.debug.LogLevel +import com.onesignal.debug.internal.logging.Logging +import com.onesignal.notifications.internal.backend.impl.NotificationBackendService +import io.kotest.assertions.throwables.shouldThrowUnit +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.runner.junit4.KotestTestRunner +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import org.json.JSONObject +import org.junit.runner.RunWith + +@RunWith(KotestTestRunner::class) +class NotificationBackendServiceTests : FunSpec({ + beforeAny { + Logging.logLevel = LogLevel.NONE + } + + test("updateNotificationAsReceived succeeds when response is successful") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(202, null) + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + /* When */ + notificationBackendService.updateNotificationAsReceived("appId", "notificationId", "subscriptionId", IDeviceService.DeviceType.Android) + + /* Then */ + coVerify { + spyHttpClient.put( + "notifications/notificationId/report_received", + withArg { + it.getString("app_id") shouldBe "appId" + it.getString("player_id") shouldBe "subscriptionId" + it.getInt("device_type") shouldBe IDeviceService.DeviceType.Android.value + } + ) + } + } + + test("updateNotificationAsReceived throws exception when response is unsuccessful") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(404, null) + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + /* When */ + val exception = shouldThrowUnit { + notificationBackendService.updateNotificationAsReceived( + "appId", + "notificationId", + "subscriptionId", + IDeviceService.DeviceType.Android + ) + } + + /* Then */ + exception.statusCode shouldBe 404 + } + + test("updateNotificationAsOpened succeeds when response is successful") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(202, null) + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + /* When */ + notificationBackendService.updateNotificationAsOpened("appId", "notificationId", "subscriptionId", IDeviceService.DeviceType.Android) + + /* Then */ + coVerify { + spyHttpClient.put( + "notifications/notificationId", + withArg { + it.getString("app_id") shouldBe "appId" + it.getString("player_id") shouldBe "subscriptionId" + it.getBoolean("opened") shouldBe true + it.getInt("device_type") shouldBe IDeviceService.DeviceType.Android.value + } + ) + } + } + + test("updateNotificationAsOpened throws exception when response is unsuccessful") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(404, null) + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + /* When */ + val exception = shouldThrowUnit { + notificationBackendService.updateNotificationAsOpened( + "appId", + "notificationId", + "subscriptionId", + IDeviceService.DeviceType.Android + ) + } + + /* Then */ + exception.statusCode shouldBe 404 + } + + test("postNotification succeeds when response is successful and appId not provided in payload") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{prop1: \"val1\"}") + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + val jsonObject = JSONObject().put("prop1", "val1") + + /* When */ + val response = notificationBackendService.postNotification("appId", jsonObject) + + /* Then */ + response.getString("prop1") shouldBe "val1" + coVerify { + spyHttpClient.post( + "notifications/", + withArg { + it.getString("app_id") shouldBe "appId" + it.getString("prop1") shouldBe "val1" + } + ) + } + } + + test("postNotification succeeds when response is successful and appId provided in payload") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{prop1: \"val1\"}") + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + val jsonObject = JSONObject().put("app_id", "appId1").put("prop1", "val1") + + /* When */ + val response = notificationBackendService.postNotification("appId2", jsonObject) + + /* Then */ + response.getString("prop1") shouldBe "val1" + coVerify { + spyHttpClient.post( + "notifications/", + withArg { + it.getString("app_id") shouldBe "appId1" + it.getString("prop1") shouldBe "val1" + } + ) + } + } + + test("postNotification throws exception when response is unsuccessful") { + /* Given */ + val spyHttpClient = mockk() + coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(404, null) + + val notificationBackendService = NotificationBackendService(spyHttpClient) + + val jsonObject = JSONObject().put("prop1", "val1") + + /* When */ + val exception = shouldThrowUnit { + notificationBackendService.postNotification("appId", jsonObject) + } + + /* Then */ + exception.statusCode shouldBe 404 + } +}) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt new file mode 100644 index 000000000..6133e6d79 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt @@ -0,0 +1,292 @@ +package com.onesignal.notifications.internal.channels + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import com.onesignal.debug.LogLevel +import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.AndroidMockHelper +import com.onesignal.mocks.MockHelper +import com.onesignal.notifications.extensions.RobolectricTest +import com.onesignal.notifications.internal.channels.impl.NotificationChannelManager +import com.onesignal.notifications.internal.common.NotificationGenerationJob +import com.onesignal.notifications.shadows.ShadowRoboNotificationManager +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import io.kotest.runner.junit4.KotestTestRunner +import org.json.JSONArray +import org.json.JSONObject +import org.junit.runner.RunWith +import org.robolectric.annotation.Config +import java.math.BigInteger + +@Config( + packageName = "com.onesignal.example", + shadows = [ShadowRoboNotificationManager::class], + sdk = [26] +) +@RobolectricTest +@RunWith(KotestTestRunner::class) +class NotificationChannelManagerTests : FunSpec({ + beforeAny { + Logging.logLevel = LogLevel.NONE + } + + test("createNotificationChannel should return default channel with empty payload") { + /* Given */ + val mockTime = MockHelper.time(1111) + + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + + /* When */ + val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(JSONObject(), mockTime)) + + /* Then */ + response shouldBe "fcm_fallback_notification_channel" + + val lastChannel = ShadowRoboNotificationManager.lastChannel + lastChannel shouldNotBe null + lastChannel!!.id shouldBe "fcm_fallback_notification_channel" + lastChannel.sound shouldNotBe null + lastChannel.shouldShowLights() shouldBe true + lastChannel.shouldVibrate() shouldBe true + } + + test("createNotificationChannel should create basic channel") { + /* Given */ + val mockTime = MockHelper.time(1111) + + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + val payload = JSONObject() + .put( + "chnl", + JSONObject() + .put("id", "test_id") + ) + + /* When */ + val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) + + /* Then */ + response shouldBe "test_id" + + val lastChannel = ShadowRoboNotificationManager.lastChannel + lastChannel shouldNotBe null + lastChannel!!.id shouldBe "test_id" + lastChannel.sound shouldNotBe null + lastChannel.shouldShowLights() shouldBe true + lastChannel.shouldVibrate() shouldBe true + } + + test("createNotificationChannel with all options") { + /* Given */ + val mockTime = MockHelper.time(1111) + + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + val payload = JSONObject() + .put("pri", 10) + .put("led", 0) + .put("ledc", "FFFF0000") + .put("vib", 0) + .put("vib_pt", JSONArray("[1,2,3,4]")) + .put("sound", "notification") + .put("vis", Notification.VISIBILITY_SECRET) + .put("bdg", 1) + .put("bdnd", 1) + .put( + "chnl", + JSONObject() + .put("id", "test_id") + .put("nm", "Test Name") + .put("dscr", "Some description") + .put("grp_id", "grp_id") + .put("grp_nm", "Group Name") + ) + + /* When */ + val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) + + /* Then */ + response shouldBe "test_id" + + val lastChannel = ShadowRoboNotificationManager.lastChannel + val lastGroup = ShadowRoboNotificationManager.lastChannelGroup + + lastChannel shouldNotBe null + lastChannel!!.id shouldBe "test_id" + lastChannel.name shouldBe "Test Name" + lastChannel.description shouldBe "Some description" + lastChannel.group shouldBe "grp_id" + + lastGroup shouldNotBe null + lastGroup!!.id shouldBe "grp_id" + lastGroup.name shouldBe "Group Name" + + lastChannel.sound shouldNotBe null + lastChannel.shouldShowLights() shouldBe false // Setting a led color should NOT override enableLights + + lastChannel.lightColor.toLong() shouldBe -65536 + lastChannel.shouldVibrate() shouldBe false // Setting a pattern should NOT override enableVibration + + lastChannel.vibrationPattern shouldBe longArrayOf(1, 2, 3, 4) + + lastChannel.importance.toLong() shouldBe NotificationManager.IMPORTANCE_MAX + lastChannel.sound.toString() shouldBe "content://settings/system/notification_sound" + lastChannel.lockscreenVisibility.toLong() shouldBe Notification.VISIBILITY_SECRET.toLong() + lastChannel.canShowBadge() shouldBe true + lastChannel.canBypassDnd() shouldBe true + } + + test("createNotificationChannel use other channel when available") { + /* Given */ + val mockTime = MockHelper.time(1111) + + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + val payload = JSONObject() + .put("oth_chnl", "existing_id") + .put("chnl", JSONObject().put("id", "test_id")) + + /* When */ + val response1 = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) + createChannel("existing_id", ApplicationProvider.getApplicationContext()) + val response2 = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) + + /* Then */ + response1 shouldBe "test_id" + response2 shouldBe "existing_id" + } + + test("createNotificationChannel with invalid color should revert to FFFFFFFF") { + /* Given */ + val mockTime = MockHelper.time(1111) + + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + val payload = JSONObject() + .put("ledc", "FFFFFFFFY") + .put( + "chnl", + JSONObject() + .put("id", "test_id") + .put("nm", "Test Name") + ) + + /* When */ + val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) + + /* Then */ + val lastChannel = ShadowRoboNotificationManager.lastChannel + response shouldBe "test_id" + lastChannel shouldNotBe null + lastChannel!!.lightColor shouldBe BigInteger("FFFFFFFF", 16).toInt() + } + + test("processChannelList with no channel list should keep existing channels") { + /* Given */ + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + + createChannel("local_existing_id", ApplicationProvider.getApplicationContext()) + createChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) + + /* When */ + notificationChannelManager.processChannelList(null) + + /* Then */ + getChannel("local_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null + getChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null + } + + test("processChannelList with existing local channel should not delete local channel") { + /* Given */ + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + + createChannel("local_existing_id", ApplicationProvider.getApplicationContext()) + + val payload = JSONArray() + .put( + JSONObject() + .put("chnl", JSONObject().put("id", "OS_id1")) + ) + + /* When */ + notificationChannelManager.processChannelList(payload) + + /* Then */ + getChannel("local_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null + getChannel("OS_id1", ApplicationProvider.getApplicationContext()) shouldNotBe null + } + + test("processChannelList with existing OS channel should delete old OS channel when it is not in channel list") { + /* Given */ + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + + createChannel("local_existing_id", ApplicationProvider.getApplicationContext()) + createChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) + + val payload = JSONArray() + .put( + JSONObject() + .put("chnl", JSONObject().put("id", "OS_id1")) + ) + + /* When */ + notificationChannelManager.processChannelList(payload) + + /* Then */ + getChannel("local_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null + getChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) shouldBe null + getChannel("OS_id1", ApplicationProvider.getApplicationContext()) shouldNotBe null + } + + test("processChannelList multilanguage") { + /* Given */ + val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) + + val payload = JSONArray() + .put( + JSONObject() + .put( + "chnl", + JSONObject() + .put("id", "OS_id1") + .put("grp_id", "grp_id1") + .put( + "langs", + JSONObject() + .put( + "en", + JSONObject() + .put("nm", "en_nm") + .put("dscr", "en_dscr") + .put("grp_nm", "en_grp_nm") + ) + ) + ) + ) + + /* When */ + notificationChannelManager.processChannelList(payload) + + /* Then */ + val lastGroup = ShadowRoboNotificationManager.lastChannelGroup + val channel = getChannel("OS_id1", ApplicationProvider.getApplicationContext()) + channel shouldNotBe null + channel!!.name shouldBe "en_nm" + channel.description shouldBe "en_dscr" + lastGroup shouldNotBe null + lastGroup!!.name shouldBe "en_grp_nm" + } +}) + +fun createChannel(id: String, context: Context) { + val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val channel = NotificationChannel(id, "name", NotificationManager.IMPORTANCE_DEFAULT) + notificationManager.createNotificationChannel(channel) +} + +private fun getChannel(id: String, context: Context): NotificationChannel? { + val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + return notificationManager.getNotificationChannel(id) +} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt new file mode 100644 index 000000000..821c441c2 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt @@ -0,0 +1,348 @@ +package com.onesignal.notifications.internal.generation + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import com.onesignal.debug.LogLevel +import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.AndroidMockHelper +import com.onesignal.mocks.MockHelper +import com.onesignal.notifications.INotificationReceivedEvent +import com.onesignal.notifications.extensions.RobolectricTest +import com.onesignal.notifications.internal.data.INotificationRepository +import com.onesignal.notifications.internal.display.INotificationDisplayer +import com.onesignal.notifications.internal.generation.impl.NotificationGenerationProcessor +import com.onesignal.notifications.internal.lifecycle.INotificationLifecycleService +import com.onesignal.notifications.internal.summary.INotificationSummaryManager +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.runner.junit4.KotestTestRunner +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.runs +import kotlinx.coroutines.delay +import org.json.JSONObject +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +@Config( + packageName = "com.onesignal.example", + sdk = [26] +) +@RobolectricTest +@RunWith(KotestTestRunner::class) +class NotificationGenerationProcessorTests : FunSpec({ + beforeAny { + Logging.logLevel = LogLevel.NONE + } + + test("processNotificationData should set title correctly") { + /* Given */ + val context = ApplicationProvider.getApplicationContext() + val mockTime = MockHelper.time(1111) + val mockApplicationService = AndroidMockHelper.applicationService() + every { mockApplicationService.isInForeground } returns true + val mockNotificationDisplayer = mockk() + coEvery { mockNotificationDisplayer.displayNotification(any()) } returns true + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false + coEvery { mockNotificationRepository.createNotification(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()) } just runs + val mockNotificationSummaryManager = mockk() + val mockNotificationLifecycleService = mockk() + coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true + coEvery { mockNotificationLifecycleService.notificationReceived(any()) } just runs + + val notificationGenerationProcessor = NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime + ) + + val payload = JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1") + ) + + /* When */ + notificationGenerationProcessor.processNotificationData(context, 1, payload, false, 1111) + + /* Then */ + coVerify(exactly = 1) { + mockNotificationDisplayer.displayNotification( + withArg { + it.androidId shouldBe 1 + it.apiNotificationId shouldBe "UUID1" + it.body shouldBe "test message" + it.title shouldBe "test title" + it.isRestoring shouldBe false + it.shownTimeStamp shouldBe 1111 + } + ) + } + coVerify(exactly = 1) { + mockNotificationRepository.createNotification("UUID1", null, null, any(), false, 1, "test title", "test message", any(), any()) + } + } + + test("processNotificationData should restore notification correctly") { + /* Given */ + val context = ApplicationProvider.getApplicationContext() + val mockTime = MockHelper.time(1111) + val mockApplicationService = AndroidMockHelper.applicationService() + every { mockApplicationService.isInForeground } returns true + val mockNotificationDisplayer = mockk() + coEvery { mockNotificationDisplayer.displayNotification(any()) } returns true + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false + val mockNotificationSummaryManager = mockk() + val mockNotificationLifecycleService = mockk() + coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true + coEvery { mockNotificationLifecycleService.notificationReceived(any()) } just runs + + val notificationGenerationProcessor = NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime + ) + + val payload = JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1") + ) + + /* When */ + notificationGenerationProcessor.processNotificationData(context, 1, payload, true, 1111) + + /* Then */ + coVerify(exactly = 1) { + mockNotificationDisplayer.displayNotification( + withArg { + it.androidId shouldBe 1 + it.apiNotificationId shouldBe "UUID1" + it.body shouldBe "test message" + it.title shouldBe "test title" + it.isRestoring shouldBe true + it.shownTimeStamp shouldBe 1111 + } + ) + } + } + + test("processNotificationData should not display notification when external callback indicates not to") { + /* Given */ + val context = ApplicationProvider.getApplicationContext() + val mockTime = MockHelper.time(1111) + val mockApplicationService = AndroidMockHelper.applicationService() + every { mockApplicationService.isInForeground } returns true + val mockNotificationDisplayer = mockk() + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false + coEvery { mockNotificationRepository.createNotification(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()) } just runs + val mockNotificationSummaryManager = mockk() + val mockNotificationLifecycleService = mockk() + coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true + coEvery { mockNotificationLifecycleService.notificationReceived(any()) } just runs + coEvery { mockNotificationLifecycleService.externalRemoteNotificationReceived(any(), any()) } answers { + val receivedEvent = secondArg() + receivedEvent.complete(null) + } + + val notificationGenerationProcessor = NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime + ) + + val payload = JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1") + ) + + /* When */ + notificationGenerationProcessor.processNotificationData(context, 1, payload, false, 1111) + + /* Then */ + } + + test("processNotificationData should display notification when external callback takes longer than 30 seconds") { + /* Given */ + val context = ApplicationProvider.getApplicationContext() + val mockTime = MockHelper.time(1111) + val mockApplicationService = AndroidMockHelper.applicationService() + every { mockApplicationService.isInForeground } returns true + val mockNotificationDisplayer = mockk() + coEvery { mockNotificationDisplayer.displayNotification(any()) } returns true + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false + coEvery { mockNotificationRepository.createNotification(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()) } just runs + val mockNotificationSummaryManager = mockk() + val mockNotificationLifecycleService = mockk() + coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true + coEvery { mockNotificationLifecycleService.notificationReceived(any()) } just runs + coEvery { mockNotificationLifecycleService.externalRemoteNotificationReceived(any(), any()) } coAnswers { + delay(40000) + } + + val notificationGenerationProcessor = NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime + ) + + val payload = JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1") + ) + + /* When */ + notificationGenerationProcessor.processNotificationData(context, 1, payload, true, 1111) + + /* Then */ + coVerify(exactly = 1) { + mockNotificationDisplayer.displayNotification( + withArg { + it.androidId shouldBe 1 + it.apiNotificationId shouldBe "UUID1" + it.body shouldBe "test message" + it.title shouldBe "test title" + it.isRestoring shouldBe true + it.shownTimeStamp shouldBe 1111 + } + ) + } + } + + test("processNotificationData should not display notification when foreground callback indicates not to") { + /* Given */ + val context = ApplicationProvider.getApplicationContext() + val mockTime = MockHelper.time(1111) + val mockApplicationService = AndroidMockHelper.applicationService() + every { mockApplicationService.isInForeground } returns true + val mockNotificationDisplayer = mockk() + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false + coEvery { mockNotificationRepository.createNotification(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()) } just runs + val mockNotificationSummaryManager = mockk() + val mockNotificationLifecycleService = mockk() + coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true + coEvery { mockNotificationLifecycleService.notificationReceived(any()) } just runs + coEvery { mockNotificationLifecycleService.externalNotificationWillShowInForeground(any()) } answers { + val receivedEvent = firstArg() + receivedEvent.complete(null) + } + + val notificationGenerationProcessor = NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime + ) + + val payload = JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1") + ) + + /* When */ + notificationGenerationProcessor.processNotificationData(context, 1, payload, false, 1111) + + /* Then */ + } + + test("processNotificationData should display notification when foreground callback takes longer than 30 seconds") { + /* Given */ + val context = ApplicationProvider.getApplicationContext() + val mockTime = MockHelper.time(1111) + val mockApplicationService = AndroidMockHelper.applicationService() + every { mockApplicationService.isInForeground } returns true + val mockNotificationDisplayer = mockk() + coEvery { mockNotificationDisplayer.displayNotification(any()) } returns true + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false + coEvery { mockNotificationRepository.createNotification(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()) } just runs + val mockNotificationSummaryManager = mockk() + val mockNotificationLifecycleService = mockk() + coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true + coEvery { mockNotificationLifecycleService.notificationReceived(any()) } just runs + coEvery { mockNotificationLifecycleService.externalNotificationWillShowInForeground(any()) } coAnswers { + delay(40000) + } + + val notificationGenerationProcessor = NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime + ) + + val payload = JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1") + ) + + /* When */ + notificationGenerationProcessor.processNotificationData(context, 1, payload, true, 1111) + + /* Then */ + coVerify(exactly = 1) { + mockNotificationDisplayer.displayNotification( + withArg { + it.androidId shouldBe 1 + it.apiNotificationId shouldBe "UUID1" + it.body shouldBe "test message" + it.title shouldBe "test title" + it.isRestoring shouldBe true + it.shownTimeStamp shouldBe 1111 + } + ) + } + } +}) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt new file mode 100644 index 000000000..1492a8515 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt @@ -0,0 +1,102 @@ +package com.onesignal.notifications.internal.limiting + +import android.content.Context +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.test.core.app.ApplicationProvider +import com.onesignal.debug.LogLevel +import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.AndroidMockHelper +import com.onesignal.notifications.extensions.RobolectricTest +import com.onesignal.notifications.internal.data.INotificationRepository +import com.onesignal.notifications.internal.limiting.impl.NotificationLimitManager +import com.onesignal.notifications.internal.summary.INotificationSummaryManager +import io.kotest.core.spec.style.FunSpec +import io.kotest.runner.junit4.KotestTestRunner +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import io.mockk.spyk +import org.junit.runner.RunWith +import org.robolectric.annotation.Config +import org.robolectric.annotation.Implements + +@Config( + packageName = "com.onesignal.example", + shadows = [ShadowINotificationLimitManagerConstants::class], + sdk = [26] +) +@RobolectricTest +@RunWith(KotestTestRunner::class) +class NotificationLimitManagerTests : FunSpec({ + beforeAny { + Logging.logLevel = LogLevel.NONE + } + + test("clearOldestOverLimit should make room for one when at limit") { + /* Given */ + createNotification(ApplicationProvider.getApplicationContext(), 1) + createNotification(ApplicationProvider.getApplicationContext(), 2) + + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.markAsDismissed(any()) } returns true + val mockNotificationSummaryManager = spyk() + + val notificationLimitManager = NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) + + /* When */ + notificationLimitManager.clearOldestOverLimit(1) + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.markAsDismissed(1) } + } + + test("clearOldestOverLimit should not dismiss any when under limit") { + /* Given */ + createNotification(ApplicationProvider.getApplicationContext(), 1) + + val mockNotificationRepository = mockk() + val mockNotificationSummaryManager = spyk() + + val notificationLimitManager = NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) + + /* When */ + notificationLimitManager.clearOldestOverLimit(1) + + /* Then */ + coVerify(exactly = 0) { mockNotificationRepository.markAsDismissed(1) } + } + + test("clearOldestOverLimit should skip dismissing summary notifications") { + /* Given */ + createNotification(ApplicationProvider.getApplicationContext(), 1, true) + createNotification(ApplicationProvider.getApplicationContext(), 2) + + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.markAsDismissed(any()) } returns true + val mockNotificationSummaryManager = spyk() + + val notificationLimitManager = NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) + + /* When */ + notificationLimitManager.clearOldestOverLimit(1) + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.markAsDismissed(2) } + } +}) + +fun createNotification(context: Context, notifId: Int, isSummary: Boolean = false) { + val notifBuilder = NotificationCompat.Builder(context, "") + notifBuilder.setWhen(notifId.toLong()) // Android automatically sets this normally. + if (isSummary) { + // We should not clear summary notifications, these will go away if all child notifications are canceled + notifBuilder.setGroupSummary(true) + } + NotificationManagerCompat.from(context).notify(notifId, notifBuilder.build()) +} + +@Implements(value = INotificationLimitManager.Constants::class, looseSignatures = true) +class ShadowINotificationLimitManagerConstants { + val maxNumberOfNotifications: Int = 2 +} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt new file mode 100644 index 000000000..3ca7383b1 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt @@ -0,0 +1,195 @@ +package com.onesignal.notifications.internal.pushtoken + +import com.onesignal.core.internal.device.IDeviceService +import com.onesignal.debug.LogLevel +import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.MockHelper +import com.onesignal.notifications.internal.registration.IPushRegistrator +import com.onesignal.notifications.shadows.ShadowRoboNotificationManager +import com.onesignal.user.internal.subscriptions.SubscriptionStatus +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.runner.junit4.KotestTestRunner +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import org.junit.runner.RunWith + +@RunWith(KotestTestRunner::class) +class PushTokenManagerTests : FunSpec({ + beforeAny { + Logging.logLevel = LogLevel.NONE + ShadowRoboNotificationManager.reset() + } + + test("retrievePushToken should fail with missing library when android support libraries are missing") { + /* Given */ + val mockPushRegistrator = mockk() + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.MISSING + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response = pushTokenManager.retrievePushToken() + val pushToken = pushTokenManager.pushToken + val pushTokenStatus = pushTokenManager.pushTokenStatus + + /* Then */ + response.token shouldBe null + response.status shouldBe SubscriptionStatus.MISSING_ANDROID_SUPPORT_LIBRARY + pushToken shouldBe null + pushTokenStatus shouldBe SubscriptionStatus.MISSING_ANDROID_SUPPORT_LIBRARY + } + + test("retrievePushToken should fail with outdated library when android support libraries are missing") { + /* Given */ + val mockPushRegistrator = mockk() + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OUTDATED + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response = pushTokenManager.retrievePushToken() + val pushToken = pushTokenManager.pushToken + val pushTokenStatus = pushTokenManager.pushTokenStatus + + /* Then */ + response.token shouldBe null + response.status shouldBe SubscriptionStatus.OUTDATED_ANDROID_SUPPORT_LIBRARY + pushToken shouldBe null + pushTokenStatus shouldBe SubscriptionStatus.OUTDATED_ANDROID_SUPPORT_LIBRARY + } + + test("retrievePushToken should succeed when registration is successful") { + /* Given */ + val mockPushRegistrator = mockk() + coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult("pushToken", SubscriptionStatus.SUBSCRIBED) + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response = pushTokenManager.retrievePushToken() + val pushToken = pushTokenManager.pushToken + val pushTokenStatus = pushTokenManager.pushTokenStatus + + /* Then */ + coVerify(exactly = 1) { mockPushRegistrator.registerForPush() } + response.token shouldBe "pushToken" + response.status shouldBe SubscriptionStatus.SUBSCRIBED + pushToken shouldBe "pushToken" + pushTokenStatus shouldBe SubscriptionStatus.SUBSCRIBED + } + + test("retrievePushToken should fail with failure status from push registrator with config-type error") { + /* Given */ + val mockPushRegistrator = mockk() + coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY) + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response = pushTokenManager.retrievePushToken() + val pushToken = pushTokenManager.pushToken + val pushTokenStatus = pushTokenManager.pushTokenStatus + + /* Then */ + coVerify(exactly = 1) { mockPushRegistrator.registerForPush() } + response.token shouldBe null + response.status shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + pushToken shouldBe null + pushTokenStatus shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + } + + test("retrievePushToken should fail with failure status from push registrator with runtime-type error") { + /* Given */ + val mockPushRegistrator = mockk() + coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION) + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response = pushTokenManager.retrievePushToken() + val pushToken = pushTokenManager.pushToken + val pushTokenStatus = pushTokenManager.pushTokenStatus + + /* Then */ + coVerify(exactly = 1) { mockPushRegistrator.registerForPush() } + response.token shouldBe null + response.status shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION + pushToken shouldBe null + pushTokenStatus shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION + } + + test("retrievePushToken should fail with failure status of config-type error even if subsequent runtime-type error") { + /* Given */ + val mockPushRegistrator = mockk() + coEvery { mockPushRegistrator.registerForPush() } returns + IPushRegistrator.RegisterResult(null, SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY) andThen + IPushRegistrator.RegisterResult(null, SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION) + + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response1 = pushTokenManager.retrievePushToken() + val pushToken1 = pushTokenManager.pushToken + val pushTokenStatus1 = pushTokenManager.pushTokenStatus + val response2 = pushTokenManager.retrievePushToken() + val pushToken2 = pushTokenManager.pushToken + val pushTokenStatus2 = pushTokenManager.pushTokenStatus + + /* Then */ + coVerify(exactly = 2) { mockPushRegistrator.registerForPush() } + response1.token shouldBe null + response1.status shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + pushToken1 shouldBe null + pushTokenStatus1 shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + response2.token shouldBe null + response2.status shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + pushToken2 shouldBe null + pushTokenStatus2 shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + } + + test("retrievePushToken should fail with failure status of config-type error even if previous runtime-type error") { + /* Given */ + val mockPushRegistrator = mockk() + coEvery { mockPushRegistrator.registerForPush() } returns + IPushRegistrator.RegisterResult(null, SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION) andThen + IPushRegistrator.RegisterResult(null, SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY) + + val mockDeviceService = MockHelper.deviceService() + every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK + + val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) + + /* When */ + val response1 = pushTokenManager.retrievePushToken() + val pushToken1 = pushTokenManager.pushToken + val pushTokenStatus1 = pushTokenManager.pushTokenStatus + val response2 = pushTokenManager.retrievePushToken() + val pushToken2 = pushTokenManager.pushToken + val pushTokenStatus2 = pushTokenManager.pushTokenStatus + + /* Then */ + coVerify(exactly = 2) { mockPushRegistrator.registerForPush() } + response1.token shouldBe null + response1.status shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION + pushToken1 shouldBe null + pushTokenStatus1 shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION + response2.token shouldBe null + response2.status shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + pushToken2 shouldBe null + pushTokenStatus2 shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY + } +}) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt new file mode 100644 index 000000000..8f406e93c --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt @@ -0,0 +1,211 @@ +package com.onesignal.notifications.internal.summary + +import com.onesignal.debug.LogLevel +import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.AndroidMockHelper +import com.onesignal.mocks.MockHelper +import com.onesignal.notifications.extensions.RobolectricTest +import com.onesignal.notifications.internal.data.INotificationRepository +import com.onesignal.notifications.internal.display.ISummaryNotificationDisplayer +import com.onesignal.notifications.internal.restoration.INotificationRestoreProcessor +import com.onesignal.notifications.internal.summary.impl.NotificationSummaryManager +import com.onesignal.notifications.shadows.ShadowRoboNotificationManager +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.runner.junit4.KotestTestRunner +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.just +import io.mockk.mockk +import io.mockk.runs +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +@Config( + packageName = "com.onesignal.example", + shadows = [ShadowRoboNotificationManager::class], + sdk = [26] +) +@RobolectricTest +@RunWith(KotestTestRunner::class) +class NotificationSummaryManagerTests : FunSpec({ + beforeAny { + Logging.logLevel = LogLevel.NONE + ShadowRoboNotificationManager.reset() + } + + test("updatePossibleDependentSummaryOnDismiss should take no action when dismissed notification is not part of a group") { + /* Given */ + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.getGroupId(1) } returns null + val mockSummaryNotificationDisplayer = mockk() + val mockNotificationRestoreProcessor = mockk() + + val notificationSummaryManager = NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor + ) + + /* When */ + notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } + } + + test("updatePossibleDependentSummaryOnDismiss should dismiss summary notification when there are no more notifications in group") { + /* Given */ + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.getGroupId(1) } returns "groupId" + coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns listOf() + coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 + coEvery { mockNotificationRepository.markAsConsumed(99, true) } just runs + val mockSummaryNotificationDisplayer = mockk() + val mockNotificationRestoreProcessor = mockk() + + val notificationSummaryManager = NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor + ) + + /* When */ + notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } + coVerify(exactly = 1) { mockNotificationRepository.listNotificationsForGroup("groupId") } + coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } + coVerify(exactly = 1) { mockNotificationRepository.markAsConsumed(99, true) } + ShadowRoboNotificationManager.cancelledNotifications.count() shouldBe 1 + ShadowRoboNotificationManager.cancelledNotifications[0] shouldBe 99 + } + + test("updatePossibleDependentSummaryOnDismiss should update summary notification when there are 2 or more notifications in group") { + /* Given */ + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.getGroupId(1) } returns "groupId" + coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns listOf( + INotificationRepository.NotificationData(2, "notificationId2", "{key: \"value2\"}", 1111, "title2", "message2"), + INotificationRepository.NotificationData(3, "notificationId3", "{key: \"value3\"}", 1111, "title3", "message3") + ) + coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 + val mockSummaryNotificationDisplayer = mockk() + coEvery { mockSummaryNotificationDisplayer.updateSummaryNotification(any()) } just runs + val mockNotificationRestoreProcessor = mockk() + + val notificationSummaryManager = NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor + ) + + /* When */ + notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } + coVerify(exactly = 1) { mockNotificationRepository.listNotificationsForGroup("groupId") } + coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } + coVerify(exactly = 1) { mockSummaryNotificationDisplayer.updateSummaryNotification(any()) } + } + + test("updatePossibleDependentSummaryOnDismiss should restore summary notification when there is 1 notification in group") { + /* Given */ + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.getGroupId(1) } returns "groupId" + coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns listOf( + INotificationRepository.NotificationData(2, "notificationId2", "{key: \"value2\"}", 1111, "title2", "message2") + ) + coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 + val mockSummaryNotificationDisplayer = mockk() + val mockNotificationRestoreProcessor = mockk() + coEvery { mockNotificationRestoreProcessor.processNotification(any()) } just runs + + val notificationSummaryManager = NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor + ) + + /* When */ + notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } + coVerify(exactly = 2) { mockNotificationRepository.listNotificationsForGroup("groupId") } + coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } + coVerify(exactly = 1) { + mockNotificationRestoreProcessor.processNotification( + withArg { + it.androidId shouldBe 2 + it.id shouldBe "notificationId2" + it.createdAt shouldBe 1111 + it.title shouldBe "title2" + it.message shouldBe "message2" + } + ) + } + } + + test("clearNotificationOnSummaryClick should do nothing when there is no notifications in group") { + /* Given */ + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } returns null + val mockSummaryNotificationDisplayer = mockk() + val mockNotificationRestoreProcessor = mockk() + + val notificationSummaryManager = NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor + ) + + /* When */ + notificationSummaryManager.clearNotificationOnSummaryClick("groupId") + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } + } + + test("clearNotificationOnSummaryClick should do something when there is 1 or more notifications in group") { + /* Given */ + val mockConfig = MockHelper.configModelStore { + it.clearGroupOnSummaryClick = true + } + val mockNotificationRepository = mockk() + coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } returns 1 + coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 + val mockSummaryNotificationDisplayer = mockk() + val mockNotificationRestoreProcessor = mockk() + + val notificationSummaryManager = NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + mockConfig, + mockNotificationRestoreProcessor + ) + + /* When */ + notificationSummaryManager.clearNotificationOnSummaryClick("groupId") + + /* Then */ + coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } + coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } + + ShadowRoboNotificationManager.cancelledNotifications.count() shouldBe 1 + ShadowRoboNotificationManager.cancelledNotifications[0] shouldBe 99 + } +}) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt new file mode 100644 index 000000000..eff5fcc5b --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt @@ -0,0 +1,19 @@ +package com.onesignal.mocks + +import androidx.test.core.app.ApplicationProvider +import com.onesignal.core.internal.application.IApplicationService +import io.mockk.every + +/** + * Singleton which provides common mock services when running in an Android environment. + */ +internal object AndroidMockHelper { + + fun applicationService(): IApplicationService { + val mockAppService = MockHelper.applicationService() + + every { mockAppService.appContext } returns ApplicationProvider.getApplicationContext() + + return mockAppService + } +} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt new file mode 100644 index 000000000..90fcf42ae --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt @@ -0,0 +1,48 @@ +package com.onesignal.mocks + +import com.onesignal.core.internal.database.ICursor +import com.onesignal.core.internal.database.IDatabase +import com.onesignal.core.internal.database.IDatabaseProvider +import io.mockk.every +import io.mockk.mockk +import io.mockk.spyk + +/** + * Singleton which provides common mock services. + */ +internal object DatabaseMockHelper { + fun databaseProvider(tableName: String, records: List>? = null): Pair { + val mockOneSignalDatabase = spyk() + + if (records != null) { + val mockCursor = cursor(records!!) + every { + mockOneSignalDatabase.query(tableName, any(), any(), any(), any(), any(), any(), any(), any()) + } answers { + lastArg<(ICursor) -> Unit>().invoke(mockCursor) + } + } + + val mockDatabaseProvider = mockk() + every { mockDatabaseProvider.os } returns mockOneSignalDatabase + + return Pair(mockDatabaseProvider, mockOneSignalDatabase) + } + + fun cursor(records: List>): ICursor { + val mockCursor = mockk() + var index = 0 + every { mockCursor.count } returns records.count() + every { mockCursor.moveToFirst() } answers { index = 0; true } + every { mockCursor.moveToNext() } answers { index++; index < records.count() } + every { mockCursor.getString(any()) } answers { records[index][firstArg()] as String } + every { mockCursor.getFloat(any()) } answers { records[index][firstArg()] as Float } + every { mockCursor.getLong(any()) } answers { records[index][firstArg()] as Long } + every { mockCursor.getInt(any()) } answers { records[index][firstArg()] as Int } + every { mockCursor.getOptString(any()) } answers { records[index][firstArg()] as String? } + every { mockCursor.getOptFloat(any()) } answers { records[index][firstArg()] as Float? } + every { mockCursor.getOptLong(any()) } answers { records[index][firstArg()] as Long? } + every { mockCursor.getOptInt(any()) } answers { records[index][firstArg()] as Int? } + return mockCursor + } +} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt new file mode 100644 index 000000000..bc4b32f86 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt @@ -0,0 +1,118 @@ +package com.onesignal.mocks + +import com.onesignal.core.internal.application.IApplicationService +import com.onesignal.core.internal.config.ConfigModel +import com.onesignal.core.internal.config.ConfigModelStore +import com.onesignal.core.internal.device.IDeviceService +import com.onesignal.core.internal.language.ILanguageContext +import com.onesignal.core.internal.time.ITime +import com.onesignal.session.internal.session.SessionModel +import com.onesignal.session.internal.session.SessionModelStore +import com.onesignal.user.internal.identity.IdentityModel +import com.onesignal.user.internal.identity.IdentityModelStore +import com.onesignal.user.internal.properties.PropertiesModel +import com.onesignal.user.internal.properties.PropertiesModelStore +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import java.util.UUID + +/** + * Singleton which provides common mock services. + */ +object MockHelper { + fun time(time: Long): ITime { + val mockTime = mockk() + every { mockTime.currentTimeMillis } returns time + + return mockTime + } + + fun applicationService(): IApplicationService { + val mockAppService = mockk() + + every { mockAppService.addApplicationLifecycleHandler(any()) } just Runs + + return mockAppService + } + + const val DEFAULT_APP_ID = "appId" + fun configModelStore(action: ((ConfigModel) -> Unit)? = null): ConfigModelStore { + val configModel = ConfigModel() + + configModel.appId = DEFAULT_APP_ID + + if (action != null) { + action(configModel) + } + + val mockConfigStore = mockk() + + every { mockConfigStore.model } returns configModel + + return mockConfigStore + } + + fun identityModelStore(action: ((IdentityModel) -> Unit)? = null): IdentityModelStore { + val identityModel = IdentityModel() + + identityModel.id = "-singleton" + identityModel.onesignalId = UUID.randomUUID().toString() + + if (action != null) { + action(identityModel) + } + + val mockIdentityStore = mockk() + + every { mockIdentityStore.model } returns identityModel + + return mockIdentityStore + } + + fun propertiesModelStore(action: ((PropertiesModel) -> Unit)? = null): PropertiesModelStore { + val propertiesModel = PropertiesModel() + + propertiesModel.id = "-singleton" + propertiesModel.onesignalId = UUID.randomUUID().toString() + + if (action != null) { + action(propertiesModel) + } + + val mockPropertiesStore = mockk() + + every { mockPropertiesStore.model } returns propertiesModel + + return mockPropertiesStore + } + + fun sessionModelStore(action: ((SessionModel) -> Unit)? = null): SessionModelStore { + val sessionModel = SessionModel() + + if (action != null) { + action(sessionModel) + } + + val mockSessionStore = mockk() + + every { mockSessionStore.model } returns sessionModel + + return mockSessionStore + } + + fun languageContext(language: String = "en"): ILanguageContext { + val mockLanguageContext = mockk() + + every { mockLanguageContext.language } returns language + + return mockLanguageContext + } + + fun deviceService(): IDeviceService { + val deviceService = mockk() + every { deviceService.deviceType } returns IDeviceService.DeviceType.Android + return deviceService + } +} diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt new file mode 100644 index 000000000..9719e47c5 --- /dev/null +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt @@ -0,0 +1,118 @@ +/** + * Modified MIT License + * + * Copyright 2017 OneSignal + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * 1. The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 2. All copies of substantial portions of the Software may only be used in connection + * with services provided by OneSignal. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.onesignal.notifications.shadows + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationChannelGroup +import android.app.NotificationManager +import androidx.core.app.NotificationCompat +import org.robolectric.Shadows +import org.robolectric.annotation.Implements +import org.robolectric.shadows.ShadowNotification +import org.robolectric.shadows.ShadowNotificationManager +import java.util.ArrayList +import java.util.LinkedHashMap + +@Implements(value = NotificationManager::class, looseSignatures = true) +class ShadowRoboNotificationManager : ShadowNotificationManager() { + inner class PostedNotification internal constructor(var id: Int, var notif: Notification) { + val shadow: ShadowNotification + get() = Shadows.shadowOf(notif) + } + + public override fun cancelAll() { + val showingNotifs = notifications.keys + notifications.clear() + cancelledNotifications.addAll(showingNotifs) + } + + public override fun cancel(id: Int) { + notifications.remove(id) + cancelledNotifications.add(id) + } + + public override fun cancel(tag: String, id: Int) { + notifications.remove(id) + cancelledNotifications.add(id) + } + + public override fun notify(tag: String, id: Int, notification: Notification) { + lastNotif = notification + lastNotifId = id + notifications[id] = PostedNotification( + id, + notification + ) + super.notify(tag, id, notification) + } + + fun createNotificationChannel(channel: NotificationChannel?) { + lastChannel = channel + super.createNotificationChannel(channel as Any?) + } + + fun createNotificationChannelGroup(group: NotificationChannelGroup?) { + lastChannelGroup = group + super.createNotificationChannelGroup(group as Any?) + } + + companion object { + var lastNotif: Notification? = null + private set + val lastShadowNotif: ShadowNotification + get() = Shadows.shadowOf(lastNotif) + var lastNotifId = 0 + val notifications = LinkedHashMap() + val cancelledNotifications = mutableListOf() + + fun reset() { + notifications.clear() + cancelledNotifications.clear() + lastNotif = null + lastNotifId = 0 + } + + private lateinit var mInstance: ShadowRoboNotificationManager + fun getNotificationsInGroup(group: String): List { + val notifications: MutableList = ArrayList() + for (notification in mInstance.allNotifications) { + if (NotificationCompat.isGroupSummary(notification)) continue + if (group != notification.group) continue + notifications.add(notification) + } + return notifications + } + + var lastChannel: NotificationChannel? = null + var lastChannelGroup: NotificationChannelGroup? = null + } + + init { + mInstance = this + } +} diff --git a/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt b/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt index 1e398c3ea..776ad7a95 100644 --- a/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt @@ -1,6 +1,7 @@ package com.onesignal.session.internal.outcomes import com.onesignal.common.exceptions.BackendException +import com.onesignal.core.internal.device.IDeviceService import com.onesignal.core.internal.http.HttpResponse import com.onesignal.core.internal.http.IHttpClient import com.onesignal.debug.LogLevel @@ -31,7 +32,7 @@ class OutcomeEventsBackendServiceTests : FunSpec({ val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) /* When */ - outcomeEventsController.sendOutcomeEvent("appId", 1, null, evnt) + outcomeEventsController.sendOutcomeEvent("appId", IDeviceService.DeviceType.Android, null, evnt) /* Then */ coVerify { @@ -58,7 +59,7 @@ class OutcomeEventsBackendServiceTests : FunSpec({ val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) /* When */ - outcomeEventsController.sendOutcomeEvent("appId", 1, null, evnt) + outcomeEventsController.sendOutcomeEvent("appId", IDeviceService.DeviceType.Android, null, evnt) /* Then */ coVerify { @@ -85,7 +86,7 @@ class OutcomeEventsBackendServiceTests : FunSpec({ val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) /* When */ - outcomeEventsController.sendOutcomeEvent("appId", 1, false, evnt) + outcomeEventsController.sendOutcomeEvent("appId", IDeviceService.DeviceType.Android, false, evnt) /* Then */ coVerify { @@ -112,7 +113,7 @@ class OutcomeEventsBackendServiceTests : FunSpec({ val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) /* When */ - outcomeEventsController.sendOutcomeEvent("appId", 1, true, evnt) + outcomeEventsController.sendOutcomeEvent("appId", IDeviceService.DeviceType.Android, true, evnt) /* Then */ coVerify { @@ -139,7 +140,7 @@ class OutcomeEventsBackendServiceTests : FunSpec({ val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) /* When */ - outcomeEventsController.sendOutcomeEvent("appId", 1, null, evnt) + outcomeEventsController.sendOutcomeEvent("appId", IDeviceService.DeviceType.Android, null, evnt) /* Then */ coVerify { @@ -167,7 +168,7 @@ class OutcomeEventsBackendServiceTests : FunSpec({ /* When */ val exception = shouldThrowUnit { - outcomeEventsController.sendOutcomeEvent("appId", 1, null, evnt) + outcomeEventsController.sendOutcomeEvent("appId", IDeviceService.DeviceType.Android, null, evnt) } /* Then */ diff --git a/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt b/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt index 5ccfecc98..3ea1c5174 100644 --- a/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt +++ b/OneSignalSDK/onesignal/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt @@ -1,6 +1,7 @@ package com.onesignal.session.internal.outcomes import com.onesignal.common.exceptions.BackendException +import com.onesignal.core.internal.device.IDeviceService import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging import com.onesignal.mocks.MockHelper @@ -106,7 +107,7 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.UNATTRIBUTED evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, null, evnt) } + coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, null, evnt) } } test("send outcome with indirect influences") { @@ -146,7 +147,7 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.INDIRECT evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, false, evnt) } + coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, false, evnt) } } test("send outcome with direct influence") { @@ -186,7 +187,7 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.DIRECT evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, true, evnt) } + coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, true, evnt) } } test("send outcome with weight") { @@ -225,7 +226,7 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.UNATTRIBUTED evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, null, evnt) } + coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, null, evnt) } } test("send unique outcome with unattributed influences") { @@ -266,7 +267,7 @@ class OutcomeEventsControllerTests : FunSpec({ evnt2 shouldBe null - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, any(), any()) } + coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, any(), any()) } } test("send unique outcome with same indirect influences") { @@ -313,7 +314,7 @@ class OutcomeEventsControllerTests : FunSpec({ evnt2 shouldBe null - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, any(), any()) } + coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, any(), any()) } } test("send unique outcome with different indirect influences") { @@ -369,8 +370,8 @@ class OutcomeEventsControllerTests : FunSpec({ evnt2.timestamp shouldBe 0 // timestamp only set when it had to be saved. coVerifySequence { - mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, false, evnt1) - mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, MockHelper.DEFAULT_DEVICE_TYPE, true, evnt2) + mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, false, evnt1) + mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, IDeviceService.DeviceType.Android, true, evnt2) } } @@ -454,7 +455,7 @@ class OutcomeEventsControllerTests : FunSpec({ coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent( "appId", - 1, + IDeviceService.DeviceType.Android, true, withArg { it.name shouldBe "outcomeId1" @@ -467,7 +468,7 @@ class OutcomeEventsControllerTests : FunSpec({ coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent( "appId", - 1, + IDeviceService.DeviceType.Android, false, withArg { it.name shouldBe "outcomeId2" @@ -533,7 +534,7 @@ class OutcomeEventsControllerTests : FunSpec({ coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent( "appId", - 1, + IDeviceService.DeviceType.Android, true, withArg { it.name shouldBe "outcomeId1" @@ -546,7 +547,7 @@ class OutcomeEventsControllerTests : FunSpec({ coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent( "appId", - 1, + IDeviceService.DeviceType.Android, false, withArg { it.name shouldBe "outcomeId2" diff --git a/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/UserManagerTests.kt b/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/UserManagerTests.kt index 5cf78ff85..43ca0439e 100644 --- a/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/UserManagerTests.kt +++ b/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/UserManagerTests.kt @@ -132,7 +132,7 @@ class UserManagerTests : FunSpec({ test("subscriptions are backed by the subscriptions manager") { /* Given */ - val subscriptionList = SubscriptionList(listOf()) + val subscriptionList = SubscriptionList(listOf(), UninitializedPushSubscription()) val mockSubscriptionManager = mockk() every { mockSubscriptionManager.subscriptions } returns subscriptionList every { mockSubscriptionManager.addEmailSubscription(any()) } just runs diff --git a/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt index fd662a71b..0787eb7c6 100644 --- a/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt @@ -19,6 +19,7 @@ import com.onesignal.user.internal.operations.impl.executors.LoginUserOperationE import com.onesignal.user.internal.properties.PropertiesModel import com.onesignal.user.internal.subscriptions.SubscriptionModel import com.onesignal.user.internal.subscriptions.SubscriptionModelStore +import com.onesignal.user.internal.subscriptions.SubscriptionStatus import com.onesignal.user.internal.subscriptions.SubscriptionType import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldBeOneOf @@ -319,9 +320,9 @@ class LoginUserOperationExecutorTests : FunSpec({ SetAliasOperation(appId, localOneSignalId, "aliasLabel1", "aliasValue1-2"), SetAliasOperation(appId, localOneSignalId, "aliasLabel2", "aliasValue2"), DeleteAliasOperation(appId, localOneSignalId, "aliasLabel2"), - CreateSubscriptionOperation(appId, localOneSignalId, "subscriptionId1", SubscriptionType.PUSH, true, "pushToken1", SubscriptionModel.STATUS_SUBSCRIBED), - UpdateSubscriptionOperation(appId, localOneSignalId, "subscriptionId1", SubscriptionType.PUSH, true, "pushToken2", SubscriptionModel.STATUS_SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, "subscriptionId2", SubscriptionType.EMAIL, true, "name@company.com", SubscriptionModel.STATUS_SUBSCRIBED), + CreateSubscriptionOperation(appId, localOneSignalId, "subscriptionId1", SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), + UpdateSubscriptionOperation(appId, localOneSignalId, "subscriptionId1", SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), + CreateSubscriptionOperation(appId, localOneSignalId, "subscriptionId2", SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED), DeleteSubscriptionOperation(appId, localOneSignalId, "subscriptionId2"), SetTagOperation(appId, localOneSignalId, "tagKey1", "tagValue1-1"), SetTagOperation(appId, localOneSignalId, "tagKey1", "tagValue1-2"), @@ -361,7 +362,7 @@ class LoginUserOperationExecutorTests : FunSpec({ it[0].type shouldBe SubscriptionObjectType.ANDROID_PUSH it[0].enabled shouldBe true it[0].token shouldBe "pushToken2" - it[0].notificationTypes shouldBe SubscriptionModel.STATUS_SUBSCRIBED + it[0].notificationTypes shouldBe SubscriptionStatus.SUBSCRIBED } ) } @@ -408,8 +409,8 @@ class LoginUserOperationExecutorTests : FunSpec({ ) val operations = listOf( LoginUserOperation(appId, localOneSignalId, null, null), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionModel.STATUS_SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionModel.STATUS_SUBSCRIBED) + CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), + CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED) ) /* When */ @@ -474,8 +475,8 @@ class LoginUserOperationExecutorTests : FunSpec({ ) val operations = listOf( LoginUserOperation(appId, localOneSignalId, null, null), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionModel.STATUS_SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionModel.STATUS_SUBSCRIBED) + CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), + CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED) ) /* When */ @@ -526,8 +527,8 @@ class LoginUserOperationExecutorTests : FunSpec({ ) val operations = listOf( LoginUserOperation(appId, localOneSignalId, null, null), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionModel.STATUS_SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionModel.STATUS_SUBSCRIBED) + CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), + CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED) ) /* When */ diff --git a/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt b/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt index 1f281f7d9..78788f8c5 100644 --- a/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt @@ -10,6 +10,7 @@ import com.onesignal.user.internal.backend.SubscriptionObjectType import com.onesignal.user.internal.operations.impl.executors.SubscriptionOperationExecutor import com.onesignal.user.internal.subscriptions.SubscriptionModel import com.onesignal.user.internal.subscriptions.SubscriptionModelStore +import com.onesignal.user.internal.subscriptions.SubscriptionStatus import com.onesignal.user.internal.subscriptions.SubscriptionType import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe @@ -45,7 +46,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ mockSubscriptionsModelStore ) - val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionModel.STATUS_SUBSCRIBED)) + val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED)) /* When */ val response = subscriptionOperationExecutor.execute(operations) @@ -61,7 +62,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ SubscriptionObjectType.ANDROID_PUSH, true, "pushToken", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -78,7 +79,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ mockSubscriptionsModelStore ) - val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionModel.STATUS_SUBSCRIBED)) + val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED)) /* When */ val response = subscriptionOperationExecutor.execute(operations) @@ -93,7 +94,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ SubscriptionObjectType.ANDROID_PUSH, true, "pushToken", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -110,7 +111,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ mockSubscriptionsModelStore ) - val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionModel.STATUS_SUBSCRIBED)) + val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED)) /* When */ val response = subscriptionOperationExecutor.execute(operations) @@ -125,7 +126,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ SubscriptionObjectType.ANDROID_PUSH, true, "pushToken", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -145,7 +146,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ ) val operations = listOf( - CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionModel.STATUS_SUBSCRIBED), + CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED), DeleteSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId) ) @@ -172,8 +173,8 @@ class SubscriptionOperationExecutorTests : FunSpec({ ) val operations = listOf( - CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken1", SubscriptionModel.STATUS_SUBSCRIBED), - UpdateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionModel.STATUS_SUBSCRIBED) + CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), + UpdateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED) ) /* When */ @@ -190,7 +191,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ SubscriptionObjectType.ANDROID_PUSH, true, "pushToken2", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -198,7 +199,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ test("update subscription successfully updates subscription") { /* Given */ val mockSubscriptionBackendService = mockk() - coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any(), any(), any()) } just runs + coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any(), any(), any(), any()) } just runs val mockSubscriptionsModelStore = mockk() val subscriptionModel1 = SubscriptionModel() @@ -213,8 +214,8 @@ class SubscriptionOperationExecutorTests : FunSpec({ ) val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionModel.STATUS_SUBSCRIBED), - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken3", SubscriptionModel.STATUS_SUBSCRIBED) + UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), + UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken3", SubscriptionStatus.SUBSCRIBED) ) /* When */ @@ -227,9 +228,10 @@ class SubscriptionOperationExecutorTests : FunSpec({ mockSubscriptionBackendService.updateSubscription( appId, remoteSubscriptionId, + SubscriptionObjectType.ANDROID_PUSH, true, "pushToken3", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -237,7 +239,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ test("update subscription fails with retry when there is a network condition") { /* Given */ val mockSubscriptionBackendService = mockk() - coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any(), any(), any()) } throws BackendException(408) + coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any(), any(), any(), any()) } throws BackendException(408) val mockSubscriptionsModelStore = mockk() val subscriptionOperationExecutor = SubscriptionOperationExecutor( @@ -247,7 +249,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ ) val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionModel.STATUS_SUBSCRIBED) + UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED) ) /* When */ @@ -259,9 +261,10 @@ class SubscriptionOperationExecutorTests : FunSpec({ mockSubscriptionBackendService.updateSubscription( appId, remoteSubscriptionId, + SubscriptionObjectType.ANDROID_PUSH, true, "pushToken2", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -269,7 +272,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ test("update subscription fails without retry when there is a backend error") { /* Given */ val mockSubscriptionBackendService = mockk() - coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any(), any(), any()) } throws BackendException(404) + coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any(), any(), any(), any()) } throws BackendException(404) val mockSubscriptionsModelStore = mockk() val subscriptionOperationExecutor = SubscriptionOperationExecutor( @@ -279,7 +282,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ ) val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionModel.STATUS_SUBSCRIBED) + UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED) ) /* When */ @@ -291,9 +294,10 @@ class SubscriptionOperationExecutorTests : FunSpec({ mockSubscriptionBackendService.updateSubscription( appId, remoteSubscriptionId, + SubscriptionObjectType.ANDROID_PUSH, true, "pushToken2", - SubscriptionModel.STATUS_SUBSCRIBED + SubscriptionStatus.SUBSCRIBED ) } } @@ -313,7 +317,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ ) val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionModel.STATUS_SUBSCRIBED), + UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId) ) diff --git a/OneSignalSDK/settings.gradle b/OneSignalSDK/settings.gradle index 5bbf5dd81..1c417b671 100644 --- a/OneSignalSDK/settings.gradle +++ b/OneSignalSDK/settings.gradle @@ -20,6 +20,3 @@ include ':onesignal' include ':onesignal:inAppMessages' include ':onesignal:location' include ':onesignal:notifications' - -//this will go away soon -include ':unittest' diff --git a/OneSignalSDK/unittest/.gitignore b/OneSignalSDK/unittest/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/OneSignalSDK/unittest/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/OneSignalSDK/unittest/proguard-rules.pro b/OneSignalSDK/unittest/proguard-rules.pro deleted file mode 100644 index b2fbbf24b..000000000 --- a/OneSignalSDK/unittest/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\Program Files (x86)\Android\sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/OneSignalSDK/unittest/src/main/AndroidManifest.xml b/OneSignalSDK/unittest/src/main/AndroidManifest.xml deleted file mode 100644 index 711c30ab3..000000000 --- a/OneSignalSDK/unittest/src/main/AndroidManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/OneSignalSDK/unittest/src/main/java/com/onesignal/example/BlankActivity.java b/OneSignalSDK/unittest/src/main/java/com/onesignal/example/BlankActivity.java deleted file mode 100644 index d52c41661..000000000 --- a/OneSignalSDK/unittest/src/main/java/com/onesignal/example/BlankActivity.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2016 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal.example; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; - -public class BlankActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent intent = new Intent(this, MainActivity.class); - startActivity(intent); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/main/java/com/onesignal/example/MainActivity.java b/OneSignalSDK/unittest/src/main/java/com/onesignal/example/MainActivity.java deleted file mode 100644 index 7c99c0233..000000000 --- a/OneSignalSDK/unittest/src/main/java/com/onesignal/example/MainActivity.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2016 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal.example; - -import android.app.Activity; -import android.os.Bundle; - -public class MainActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - -} diff --git a/OneSignalSDK/unittest/src/main/res/values-night/strings.xml b/OneSignalSDK/unittest/src/main/res/values-night/strings.xml deleted file mode 100644 index 85a82fe92..000000000 --- a/OneSignalSDK/unittest/src/main/res/values-night/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - FFFF0000 - \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/main/res/values/strings.xml b/OneSignalSDK/unittest/src/main/res/values/strings.xml deleted file mode 100644 index 2be8156b8..000000000 --- a/OneSignalSDK/unittest/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - FF00FF00 - \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/InAppMessagingHelpers.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/InAppMessagingHelpers.java deleted file mode 100644 index 74a14e922..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/InAppMessagingHelpers.java +++ /dev/null @@ -1,213 +0,0 @@ -package com.onesignal; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.UUID; - -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestInAppMessageInternal; -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger; -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerKind; - -public class InAppMessagingHelpers { - public static final String TEST_SPANISH_ANDROID_VARIANT_ID = "d8cc-11e4-bed1-df8f05be55ba-a4b3gj7f"; - public static final String TEST_ENGLISH_ANDROID_VARIANT_ID = "11e4-bed1-df8f05be55ba-a4b3gj7f-d8cc"; - public static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba"; - public static final String IAM_CLICK_ID = "12345678-1234-1234-1234-123456789012"; - public static final String IAM_PAGE_ID = "12345678-1234-ABCD-1234-123456789012"; - public static final String IAM_HAS_LIQUID = "has_liquid"; - - // unit tests will create an IAM based off JSON of another IAM - // toJSONObject uses key of "messageId" so we need to replace that with "id" for creating IAM - public static JSONObject convertIAMtoJSONObject(OSInAppMessageInternal inAppMessage) { - JSONObject json = inAppMessage.toJSONObject(); - try { - json.put("id", json.get("messageId")); - json.remove("messageId"); - } catch (JSONException e) { - e.printStackTrace(); - } - - return json; - } - - public static boolean evaluateMessage(OSInAppMessageInternal message) { - return OneSignal.getInAppMessageController().triggerController.evaluateMessageTriggers(message); - } - - public static boolean dynamicTriggerShouldFire(OSTrigger trigger) { - return OneSignal.getInAppMessageController().triggerController.dynamicTriggerController.dynamicTriggerShouldFire(trigger); - } - - public static void resetSessionLaunchTime() { - OSDynamicTriggerController.resetSessionLaunchTime(); - } - - public static void clearTestState() { - OneSignal.pauseInAppMessages(false); - OneSignal.getInAppMessageController().getInAppMessageDisplayQueue().clear(); - } - - // Convenience method that wraps an object in a JSON Array - public static JSONArray wrap(final Object object) { - return new JSONArray() {{ put(object); }}; - } - - private static JSONArray basicTrigger(final OSTriggerKind kind, final String key, final String operator, final Object value) throws JSONException { - JSONObject triggerJson = new JSONObject() {{ - put("id", UUID.randomUUID().toString()); - put("kind", kind.toString()); - put("property", key); - put("operator", operator); - put("value", value); - }}; - - return wrap(wrap(triggerJson)); - } - - public static OSTestInAppMessageInternal buildTestMessageWitRedisplay(final int limit, final long delay) throws JSONException { - return buildTestMessageWithMultipleDisplays(null, limit, delay); - } - - // Most tests build a test message using only one trigger. - // This convenience method makes it easy to build such a message - public static OSTestInAppMessageInternal buildTestMessageWithSingleTrigger(final OSTriggerKind kind, final String key, final String operator, final Object value) throws JSONException { - JSONArray triggersJson = basicTrigger(kind, key, operator, value); - - return buildTestMessage(triggersJson); - } - - public static OSTestInAppMessageInternal buildTestMessageWithSingleTriggerAndRedisplay(final OSTriggerKind kind, final String key, final String operator, - final Object value, int limit, long delay) throws JSONException { - JSONArray triggersJson = basicTrigger(kind, key, operator, value); - - return buildTestMessageWithMultipleDisplays(triggersJson, limit, delay); - } - - private static JSONObject basicIAMJSONObject(final JSONArray triggerJson) throws JSONException { - // builds a test message to test JSON parsing constructor of OSInAppMessage - JSONObject json = new JSONObject() {{ - put("id", UUID.randomUUID().toString()); - put("variants", new JSONObject() {{ - put("android", new JSONObject() {{ - put("es", TEST_SPANISH_ANDROID_VARIANT_ID); - put("en", TEST_ENGLISH_ANDROID_VARIANT_ID); - }}); - }}); - put("max_display_time", 30); - if (triggerJson != null) - put("triggers", triggerJson); - else - put("triggers", new JSONArray()); - put("actions", new JSONArray() {{ - put(buildTestActionJson()); - }}); - }}; - - return json; - } - - public static OSTestInAppMessageInternal buildTestMessageWithLiquid(final JSONArray triggerJson) throws JSONException { - JSONObject json = basicIAMJSONObject(triggerJson); - json.put(IAM_HAS_LIQUID, true); - return new OSTestInAppMessageInternal(json); - } - - public static OSTestInAppMessageInternal buildTestMessageWithSingleTriggerAndLiquid(final OSTriggerKind kind, final String key, final String operator, final Object value) throws JSONException { - JSONArray triggersJson = basicTrigger(kind, key, operator, value); - return buildTestMessageWithLiquid(triggersJson); - } - - private static OSTestInAppMessageInternal buildTestMessageWithMultipleDisplays(final JSONArray triggerJson, final int limit, final long delay) throws JSONException { - JSONObject json = basicIAMJSONObject(triggerJson); - json.put("redisplay", new JSONObject() {{ - put("limit", limit); - put("delay", delay);//in seconds - }}); - - return new OSTestInAppMessageInternal(json); - } - - public static OSTestInAppMessageInternal buildTestMessage(final JSONArray triggerJson) throws JSONException { - return new OSTestInAppMessageInternal(basicIAMJSONObject(triggerJson)); - } - - public static OSTestInAppMessageInternal buildTestMessageWithEndTime(final OSTriggerKind kind, final String key, final String operator, final Object value, final boolean pastEndTime) throws JSONException { - JSONArray triggerJson = basicTrigger(kind, key, operator, value); - JSONObject json = basicIAMJSONObject(triggerJson); - if (pastEndTime) { - json.put("end_time", "1960-01-01T00:00:00.000Z"); - } else { - json.put("end_time", "2200-01-01T00:00:00.000Z"); - } - return new OSTestInAppMessageInternal(json); - } - - public static OSTestInAppMessageInternal buildTestMessageWithMultipleTriggers(ArrayList> triggers) throws JSONException { - JSONArray ors = buildTriggers(triggers); - return buildTestMessage(ors); - } - - public static OSTestInAppMessageInternal buildTestMessageWithMultipleTriggersAndRedisplay(ArrayList> triggers, int limit, long delay) throws JSONException { - JSONArray ors = buildTriggers(triggers); - return buildTestMessageWithMultipleDisplays(ors, limit, delay); - } - - private static JSONArray buildTriggers(ArrayList> triggers) throws JSONException { - JSONArray ors = new JSONArray(); - - for (ArrayList andBlock : triggers) { - JSONArray ands = new JSONArray(); - - for (final OSTestTrigger trigger : andBlock) { - ands.put(new JSONObject() {{ - put("id", UUID.randomUUID().toString()); - put("kind", trigger.kind.toString()); - put("property", trigger.property); - put("operator", trigger.operatorType.toString()); - put("value", trigger.value); - }}); - } - - ors.put(ands); - } - - return ors; - } - - public static OSTestTrigger buildTrigger(final OSTriggerKind kind, final String key, final String operator, final Object value) throws JSONException { - JSONObject triggerJson = new JSONObject() {{ - put("id", UUID.randomUUID().toString()); - put("kind", kind.toString()); - put("property", key); - put("operator", operator); - put("value", value); - }}; - - return new OSTestTrigger(triggerJson); - } - - public static JSONObject buildTestActionJson() throws JSONException { - return new JSONObject() {{ - put("click_type", "button"); - put("id", IAM_CLICK_ID); - put("name", "click_name"); - put("url", "https://www.onesignal.com"); - put("url_target", "webview"); - put("close", true); - put("pageId", IAM_PAGE_ID); - put("data", new JSONObject() {{ - put("test", "value"); - }}); - }}; - } - - public static JSONObject buildTestPageJson() throws JSONException { - return new JSONObject() {{ - put("pageIndex", 1); - put("pageId", IAM_PAGE_ID); - }}; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockHttpURLConnection.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockHttpURLConnection.java deleted file mode 100644 index 51224ab23..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockHttpURLConnection.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2019 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -public class MockHttpURLConnection extends HttpURLConnection { - private boolean didInterruptMockHang; - - public boolean getDidInterruptMockHang() { - return didInterruptMockHang; - } - - public static class MockResponse { - public String responseBody; - public String errorResponseBody; - public boolean mockThreadHang; - public int status; - public Map mockProps = new HashMap<>(); - } - - private MockResponse mockResponse; - - MockHttpURLConnection(URL url, MockResponse response) { - super(url); - mockResponse = response; - } - - @Override - public void disconnect() { - - } - - @Override - public boolean usingProxy() { - return false; - } - - @Override - public void connect() throws IOException { - - } - - @Override - public String getHeaderField(String name) { - return mockResponse.mockProps.get(name); - } - - @Override - public int getResponseCode() throws IOException { - if (mockResponse.mockThreadHang) { - try { - Thread.sleep(120_000); - } catch (InterruptedException e) { - didInterruptMockHang = true; - throw new IOException("Successfully interrupted stuck thread!"); - } - } - - return mockResponse.status; - } - - @Override - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(StandardCharsets.UTF_8.encode(mockResponse.responseBody).array()); - } - - @Override - public InputStream getErrorStream() { - if (mockResponse.errorResponseBody == null) - return null; - - byte[] bytes = mockResponse.errorResponseBody.getBytes(); - return new ByteArrayInputStream(bytes); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSLog.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSLog.java deleted file mode 100644 index 779af8e10..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSLog.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.onesignal; - -public class MockOSLog extends OSLogWrapper { - -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSSharedPreferences.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSSharedPreferences.java deleted file mode 100644 index f61ee7150..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSSharedPreferences.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.onesignal; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Set; - -public class MockOSSharedPreferences extends OneSignalPackagePrivateHelper.OSSharedPreferencesWrapper { - - private HashMap preferences = new HashMap<>(); - - public MockOSSharedPreferences() { - } - - @Override - public String getOutcomesV2KeyName() { - return super.getOutcomesV2KeyName(); - } - - @Override - public String getPreferencesName() { - return super.getPreferencesName(); - } - - @Override - public String getString(String prefsName, String key, String defValue) { - return preferences.get(key) == null ? defValue : (String) preferences.get(key); - } - - @Override - public void saveString(String prefsName, String key, String value) { - preferences.put(key, value); - } - - @Override - public boolean getBool(String prefsName, String key, boolean defValue) { - return preferences.get(key) == null ? defValue : (boolean) preferences.get(key); - } - - @Override - public void saveBool(String prefsName, String key, boolean value) { - preferences.put(key, value); - } - - @Override - public int getInt(String prefsName, String key, int defValue) { - return preferences.get(key) == null ? defValue : (int) preferences.get(key); - } - - @Override - public void saveInt(String prefsName, String key, int value) { - preferences.put(key, value); - } - - @Override - public long getLong(String prefsName, String key, long defValue) { - return preferences.get(key) == null ? defValue : (long) preferences.get(key); - } - - @Override - public void saveLong(String prefsName, String key, long value) { - preferences.put(key, value); - } - - @Nullable - @Override - public Set getStringSet(@NonNull String prefsName, @NonNull String key, @Nullable Set defValue) { - return preferences.get(key) == null ? defValue : (Set) preferences.get(key); - } - - @Override - public void saveStringSet(@NonNull String prefsName, @NonNull String key, @NonNull Set value) { - preferences.put(key, value); - } - - @Override - public Object getObject(String prefsName, String key, Object defValue) { - return preferences.get(key); - } - - @Override - public void saveObject(String prefsName, String key, Object value) { - preferences.put(key, value); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSTimeImpl.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSTimeImpl.java deleted file mode 100644 index f8cdf7c0d..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOSTimeImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.onesignal; - -public class MockOSTimeImpl extends OSTimeImpl { - - private Long mockedTime = null; - private Long mockedElapsedTime = null; - - public void reset() { - mockedTime = null; - mockedElapsedTime = null; - } - - @Override - public long getCurrentTimeMillis() { - return mockedTime != null ? mockedTime : super.getCurrentTimeMillis(); - } - - @Override - public long getElapsedRealtime() { - return mockedElapsedTime != null ? mockedElapsedTime : super.getElapsedRealtime(); - } - - public void freezeTime() { - mockedTime = getCurrentTimeMillis(); - mockedElapsedTime = getElapsedRealtime(); - } - - public void setMockedTime(Long mockedTime) { - this.mockedTime = mockedTime; - } - - public void setMockedElapsedTime(Long mockedForegroundTime) { - this.mockedElapsedTime = mockedForegroundTime; - } - - public void advanceSystemTimeBy(long sec) { - long ms = sec * 1_000L; - setMockedTime(getCurrentTimeMillis() + ms); - } - - public void advanceSystemAndElapsedTimeBy(long sec) { - long ms = sec * 1_000L; - setMockedElapsedTime(getCurrentTimeMillis() + ms); - advanceSystemTimeBy(sec); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOneSignalAPIClient.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOneSignalAPIClient.java deleted file mode 100644 index 11dfaa163..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOneSignalAPIClient.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.onesignal; - -import androidx.annotation.NonNull; - -import org.json.JSONObject; - -public class MockOneSignalAPIClient implements OneSignalAPIClient { - - private static final int FAIL_STATUS_CODE = 500; - private static final String FAIL_STRING_RESPONSE = "error"; - - private boolean success; - private JSONObject lastJsonObjectSent = new JSONObject(); - - /** - */ - public void setSuccess(boolean success) { - this.success = success; - } - - public void resetLastJsonObjectSent() { - this.lastJsonObjectSent = null; - } - - public String getLastJsonObjectSent() { - return lastJsonObjectSent.toString(); - } - - @Override - public void put(String url, JSONObject jsonBody, OneSignalApiResponseHandler responseHandler) { - lastJsonObjectSent = jsonBody; - if (success) - responseHandler.onSuccess(""); - else - responseHandler.onFailure(FAIL_STATUS_CODE, FAIL_STRING_RESPONSE, null); - } - - @Override - public void post(String url, JSONObject jsonBody, OneSignalApiResponseHandler responseHandler) { - lastJsonObjectSent = jsonBody; - if (success) - responseHandler.onSuccess(""); - else - responseHandler.onFailure(FAIL_STATUS_CODE, FAIL_STRING_RESPONSE, null); - } - - @Override - public void get(String url, OneSignalApiResponseHandler responseHandler, @NonNull String cacheKey) { - } - - @Override - public void getSync(String url, OneSignalApiResponseHandler responseHandler, @NonNull String cacheKey) { - } - - @Override - public void putSync(String url, JSONObject jsonBody, OneSignalApiResponseHandler responseHandler) { - lastJsonObjectSent = jsonBody; - if (success) - responseHandler.onSuccess(""); - else - responseHandler.onFailure(FAIL_STATUS_CODE, FAIL_STRING_RESPONSE, null); - } - - @Override - public void postSync(String url, JSONObject jsonBody, OneSignalApiResponseHandler responseHandler) { - lastJsonObjectSent = jsonBody; - if (success) - responseHandler.onSuccess(""); - else - responseHandler.onFailure(FAIL_STATUS_CODE, FAIL_STRING_RESPONSE, null); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOneSignalDBHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOneSignalDBHelper.java deleted file mode 100644 index 2577996a3..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOneSignalDBHelper.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.onesignal; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteCantOpenDatabaseException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteDatabaseLockedException; -import android.os.SystemClock; - -import com.onesignal.outcomes.data.OSOutcomeTableProvider; - -public class MockOneSignalDBHelper implements OneSignalDb { - private static final int DB_OPEN_RETRY_MAX = 5; - private static final int DB_OPEN_RETRY_BACKOFF = 400; - - private Context context; - - public MockOneSignalDBHelper(Context context) { - this.context = context; - } - - public void close() { - OneSignalDbHelper.getInstance(context).close(); - } - - public SQLiteDatabase getSQLiteDatabaseWithRetries() { - int count = 0; - while (true) { - try { - return OneSignalDbHelper.getInstance(context).getWritableDatabase(); - } catch (SQLiteCantOpenDatabaseException | SQLiteDatabaseLockedException e) { - if (++count >= DB_OPEN_RETRY_MAX) - throw e; - SystemClock.sleep(count * DB_OPEN_RETRY_BACKOFF); - } - } - } - - @Override - public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) { - return OneSignalDbHelper.getInstance(context).query(table, columns, selection, selectionArgs, groupBy, having, orderBy); - } - - @Override - public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { - return OneSignalDbHelper.getInstance(context).query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); - } - - @Override - public void insert(String table, String nullColumnHack, ContentValues values) { - OneSignalDbHelper.getInstance(context).insert(table, nullColumnHack, values); - } - - @Override - public void insertOrThrow(String table, String nullColumnHack, ContentValues values) throws SQLException { - OneSignalDbHelper.getInstance(context).insertOrThrow(table, nullColumnHack, values); - } - - @Override - public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { - return OneSignalDbHelper.getInstance(context).update(table, values, whereClause, whereArgs); - } - - @Override - public void delete(String table, String whereClause, String[] whereArgs) { - OneSignalDbHelper.getInstance(context).delete(table, whereClause, whereArgs); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOutcomeEventsController.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOutcomeEventsController.java deleted file mode 100644 index f35dcae6a..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockOutcomeEventsController.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.onesignal; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.onesignal.outcomes.data.OSOutcomeEventsFactory; - -public class MockOutcomeEventsController extends OSOutcomeEventsController { - - public MockOutcomeEventsController(MockSessionManager sessionManager, OSOutcomeEventsFactory factory) { - super(sessionManager, factory); - } - - @Override - public void cleanOutcomes() { - super.cleanOutcomes(); - } - - @Override - public void sendSavedOutcomes() { - super.sendSavedOutcomes(); - } - - public void sendOutcomeEvent(@NonNull String name) { - sendOutcomeEvent(name, null); - } - - @Override - public void sendOutcomeEvent(@NonNull String name, @Nullable OneSignal.OutcomeCallback callback) { - super.sendOutcomeEvent(name, callback); - } - - public void sendUniqueOutcomeEvent(@NonNull String name) { - sendUniqueOutcomeEvent(name, null); - } - - @Override - public void sendUniqueOutcomeEvent(@NonNull String name, @Nullable OneSignal.OutcomeCallback callback) { - super.sendUniqueOutcomeEvent(name, callback); - } - - public void sendOutcomeEventWithValue(@NonNull String name, float value) { - sendOutcomeEventWithValue(name, value, null); - } - - @Override - public void sendOutcomeEventWithValue(@NonNull String name, float value, @Nullable OneSignal.OutcomeCallback callback) { - super.sendOutcomeEventWithValue(name, value, callback); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockSessionManager.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/MockSessionManager.java deleted file mode 100644 index 3d9d0d263..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/MockSessionManager.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.onesignal; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.onesignal.influence.data.OSTrackerFactory; -import com.onesignal.influence.domain.OSInfluence; - -import org.json.JSONObject; - -import java.util.List; - -public class MockSessionManager extends OSSessionManager { - - public MockSessionManager(@NonNull SessionListener sessionListener, OSTrackerFactory trackerFactory, OSLogger logger) { - super(sessionListener, trackerFactory, logger); - } - - @Override - public void initSessionFromCache() { - super.initSessionFromCache(); - } - - @Override - public void addSessionIds(@NonNull JSONObject jsonObject, List endingInfluences) { - super.addSessionIds(jsonObject, endingInfluences); - } - - @Override - public void restartSessionIfNeeded(OneSignal.AppEntryAction entryAction) { - super.restartSessionIfNeeded(entryAction); - } - - @Override - public void onInAppMessageReceived(@Nullable String messageId) { - super.onInAppMessageReceived(messageId); - } - - @Override - public void onDirectInfluenceFromIAMClick(@Nullable String messageId) { - super.onDirectInfluenceFromIAMClick(messageId); - } - - @Override - public void onDirectInfluenceFromIAMClickFinished() { - super.onDirectInfluenceFromIAMClickFinished(); - } - - @Override - public void onNotificationReceived(@Nullable String messageId) { - super.onNotificationReceived(messageId); - } - - public void onDirectInfluenceFromNotificationOpen(@Nullable String notificationId) { - super.onDirectInfluenceFromNotificationOpen(OneSignal.AppEntryAction.NOTIFICATION_CLICK, notificationId); - } - - @Override - public void onDirectInfluenceFromNotificationOpen(OneSignal.AppEntryAction entryAction, @Nullable String notificationId) { - super.onDirectInfluenceFromNotificationOpen(entryAction, notificationId); - } - - @Override - public List getInfluences() { - return super.getInfluences(); - } - - @Override - public void attemptSessionUpgrade(OneSignal.AppEntryAction entryAction) { - super.attemptSessionUpgrade(entryAction); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalNotificationManagerPackageHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalNotificationManagerPackageHelper.java deleted file mode 100644 index f5be567b5..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalNotificationManagerPackageHelper.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.onesignal; - -import android.app.NotificationManager; -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.os.Build; -import android.service.notification.StatusBarNotification; -import androidx.annotation.RequiresApi; - -public class OneSignalNotificationManagerPackageHelper { - - private static abstract class RunnableArg { - abstract void run(T object) throws Exception; - } - - public static String getGrouplessSummaryKey() { - return OneSignalNotificationManager.getGrouplessSummaryKey(); - } - - public static NotificationManager getNotificationManager(Context context) { - return OneSignalNotificationManager.getNotificationManager(context); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - public static StatusBarNotification[] getActiveNotifications(Context context) { - return getNotificationManager(context).getActiveNotifications(); - } - - public static Integer getMostRecentNotifIdFromGroup(OneSignalDbHelper db, String group, boolean isGroupless) { - return OneSignalNotificationManager.getMostRecentNotifIdFromGroup(db, group, isGroupless); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java deleted file mode 100644 index c9463c398..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java +++ /dev/null @@ -1,848 +0,0 @@ -package com.onesignal; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.huawei.hms.push.RemoteMessage; -import com.onesignal.influence.data.OSTrackerFactory; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.robolectric.util.Scheduler; - -import java.lang.reflect.Field; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static org.robolectric.Shadows.shadowOf; - -public class OneSignalPackagePrivateHelper { - - public static final String GOOGLE_SENT_TIME_KEY = OSNotificationController.GOOGLE_SENT_TIME_KEY; - public static final String GOOGLE_TTL_KEY = OSNotificationController.GOOGLE_TTL_KEY; - - public static final String IN_APP_MESSAGES_JSON_KEY = com.onesignal.OSInAppMessageController.IN_APP_MESSAGES_JSON_KEY; - - public static final long MIN_ON_SESSION_TIME_MILLIS = com.onesignal.OneSignal.MIN_ON_SESSION_TIME_MILLIS; - - private static final String LOGCAT_TAG = "OS_PACKAGE_HELPER"; - - private static abstract class RunnableArg { - abstract void run(T object) throws Exception; - } - - private static void processNetworkHandles(RunnableArg runnable) throws Exception { - Set> entrySet; - - entrySet = OneSignalStateSynchronizer.getPushStateSynchronizer().networkHandlerThreads.entrySet(); - for (Map.Entry handlerThread : entrySet) - runnable.run(handlerThread.getValue()); - - entrySet = OneSignalStateSynchronizer.getEmailStateSynchronizer().networkHandlerThreads.entrySet(); - for (Map.Entry handlerThread : entrySet) - runnable.run(handlerThread.getValue()); - - entrySet = OneSignalStateSynchronizer.getSMSStateSynchronizer().networkHandlerThreads.entrySet(); - for (Map.Entry handlerThread : entrySet) - runnable.run(handlerThread.getValue()); - } - - private static boolean startedRunnable; - public static boolean runAllNetworkRunnables() throws Exception { - startedRunnable = false; - - RunnableArg runnable = new RunnableArg() { - @Override - void run(UserStateSynchronizer.NetworkHandlerThread handlerThread) throws Exception { - synchronized (handlerThread.mHandler) { - Scheduler scheduler = shadowOf(handlerThread.getLooper()).getScheduler(); - while (scheduler.runOneTask()) - startedRunnable = true; - } - } - }; - - processNetworkHandles(runnable); - - return startedRunnable; - } - - private static boolean isExecutingRunnable(Scheduler scheduler) throws Exception { - Field isExecutingRunnableField = Scheduler.class.getDeclaredField("isExecutingRunnable"); - isExecutingRunnableField.setAccessible(true); - return (Boolean)isExecutingRunnableField.get(scheduler); - } - - public static void OneSignal_sendPurchases(JSONArray purchases, boolean newAsExisting, OneSignalRestClient.ResponseHandler responseHandler) { - OneSignal.sendPurchases(purchases, newAsExisting, responseHandler); - } - - /** - * Only necessary when not fully init OneSignal SDK - * initWithContext required to setup a notification extension service - */ - public static void OneSignal_setupNotificationServiceExtension() { - OSNotificationController.setupNotificationServiceExtension(OneSignal.appContext); - } - - public static void OneSignal_savePrivacyConsentRequired(boolean required) { - OneSignal_getRemoteParamController().savePrivacyConsentRequired(required); - } - - public static OSRemoteParamController OneSignal_getRemoteParamController() { - return OneSignal.getRemoteParamController(); - } - - public static OSSessionManager.SessionListener OneSignal_getSessionListener() { - return OneSignal.getSessionListener(); - } - - public static void OneSignal_setTime(OSTime time) { - OneSignal.setTime(time); - } - - public static void OneSignal_setSharedPreferences(OSSharedPreferences preferences) { - OneSignal.setSharedPreferences(preferences); - } - - public static void OneSignal_setSessionManager(OSSessionManager sessionManager) { - OneSignal.setSessionManager(sessionManager); - } - - public static void OneSignal_setTrackerFactory(OSTrackerFactory trackerFactory) { - OneSignal.setTrackerFactory(trackerFactory); - } - - public static JSONObject bundleAsJSONObject(Bundle bundle) { - return NotificationBundleProcessor.bundleAsJSONObject(bundle); - } - - public static String toUnescapedEUIDString(JSONObject json) { - return JSONUtils.toUnescapedEUIDString(json); - } - - public static void OneSignal_handleNotificationOpen(Activity context, final JSONArray data, final String notificationId) { - OneSignal.handleNotificationOpen(context, data, notificationId); - } - - public static BigInteger OneSignal_getAccentColor(JSONObject fcmJson) { - return GenerateNotification.getAccentColor(fcmJson); - } - - public static BundleCompat createInternalPayloadBundle(Bundle bundle) { - BundleCompat retBundle = BundleCompatFactory.getInstance(); - retBundle.putString("json_payload", OneSignalPackagePrivateHelper.bundleAsJSONObject(bundle).toString()); - return retBundle; - } - - public static void NotificationBundleProcessor_ProcessFromFCMIntentService(Context context, Bundle bundle) { - NotificationBundleProcessor.processFromFCMIntentService(context, createInternalPayloadBundle(bundle)); - } - - public static void NotificationBundleProcessor_ProcessFromFCMIntentService_NoWrap(Context context, BundleCompat bundle) { - NotificationBundleProcessor.processFromFCMIntentService(context, bundle); - } - - public static void FCMBroadcastReceiver_processBundle(Context context, Bundle bundle) { - OneSignalPackagePrivateHelper.ProcessBundleReceiverCallback bundleReceiverCallback = new OneSignalPackagePrivateHelper.ProcessBundleReceiverCallback() { - @Override - public void onBundleProcessed(@Nullable OneSignalPackagePrivateHelper.ProcessedBundleResult processedResult) { - } - }; - - FCMBroadcastReceiver_processBundle(context, bundle, bundleReceiverCallback); - } - - public static void FCMBroadcastReceiver_processBundle(Context context, Bundle bundle, OneSignalPackagePrivateHelper.ProcessBundleReceiverCallback bundleReceiverCallback) { - NotificationBundleProcessor.processBundleFromReceiver(context, bundle, bundleReceiverCallback); - } - - public static void FCMBroadcastReceiver_onReceived_withIntent(Context context, Intent intent) { - FCMBroadcastReceiver receiver = new FCMBroadcastReceiver(); - intent.setAction("com.google.android.c2dm.intent.RECEIVE"); - receiver.onReceive(context, intent); - } - - public static void FCMBroadcastReceiver_onReceived_withBundle(Context context, Bundle bundle) throws Exception { - FCMBroadcastReceiver receiver = new FCMBroadcastReceiver(); - Intent intent = new Intent(); - intent.setAction("com.google.android.c2dm.intent.RECEIVE"); - intent.putExtras(bundle); - receiver.onReceive(context,intent); - threadAndTaskWait(); - } - - public static void HMSEventBridge_onMessageReceive(final Context context, final RemoteMessage message) { - OneSignalHmsEventBridge.onMessageReceived(context, message); - } - - public static void HMSProcessor_processDataMessageReceived(final Context context, final String jsonStrPayload) { - NotificationPayloadProcessorHMS.processDataMessageReceived(context, jsonStrPayload); - } - - public static int NotificationBundleProcessor_Process(Context context, boolean restoring, JSONObject jsonPayload) { - OSNotificationGenerationJob notificationJob = new OSNotificationGenerationJob(context, jsonPayload); - notificationJob.setRestoring(restoring); - return NotificationBundleProcessor.processJobForDisplay(notificationJob, true); - } - - public static class ProcessBundleReceiverCallback implements com.onesignal.NotificationBundleProcessor.ProcessBundleReceiverCallback { - - @Override - public void onBundleProcessed(@Nullable com.onesignal.NotificationBundleProcessor.ProcessedBundleResult processedResult) { - onBundleProcessed(new ProcessedBundleResult(processedResult)); - } - - public void onBundleProcessed(@Nullable ProcessedBundleResult processedResult) { - - } - } - - public static class ProcessedBundleResult extends NotificationBundleProcessor.ProcessedBundleResult { - com.onesignal.NotificationBundleProcessor.ProcessedBundleResult processedResult; - - public ProcessedBundleResult(com.onesignal.NotificationBundleProcessor.ProcessedBundleResult processedResult) { - this.processedResult = processedResult; - } - - public boolean isProcessed() { - return processedResult.processed(); - } - } - - public static class NotificationTable extends OneSignalDbContract.NotificationTable { - } - - public static class InAppMessageTable extends OneSignalDbContract.InAppMessageTable { - } - - public static class OSNotificationRestoreWorkManager extends com.onesignal.OSNotificationRestoreWorkManager { - public static int getDEFAULT_TTL_IF_NOT_IN_PAYLOAD() { - return DEFAULT_TTL_IF_NOT_IN_PAYLOAD; - } - } - - public static class OSNotificationGenerationJob extends com.onesignal.OSNotificationGenerationJob { - OSNotificationGenerationJob(Context context) { - super(context); - } - - OSNotificationGenerationJob(Context context, JSONObject jsonPayload) { - super(context, jsonPayload); - } - } - - public static class OneSignalSyncServiceUtils_SyncRunnable extends OSSyncService.SyncRunnable { - @Override - protected void stopSync() { - } - } - - public static class FCMBroadcastReceiver extends com.onesignal.FCMBroadcastReceiver {} - - public static class PushRegistratorFCM extends com.onesignal.PushRegistratorFCM { - public PushRegistratorFCM(@NonNull Context context, @Nullable Params params) { - super(context, params); - } - } - - public static class OneSignalRestClient extends com.onesignal.OneSignalRestClient { - public static abstract class ResponseHandler extends com.onesignal.OneSignalRestClient.ResponseHandler { - @Override - public void onSuccess(String response) {} - @Override - public void onFailure(int statusCode, String response, Throwable throwable) {} - } - } - - public static String NotificationChannelManager_createNotificationChannel(Context context, JSONObject payload) { - OSNotificationGenerationJob notificationJob = new OSNotificationGenerationJob(context); - notificationJob.setJsonPayload(payload); - return NotificationChannelManager.createNotificationChannel(notificationJob); - } - - public static void NotificationChannelManager_processChannelList(Context context, JSONArray jsonArray) { - NotificationChannelManager.processChannelList(context, jsonArray); - } - - public static void NotificationOpenedProcessor_processFromContext(Activity context, Intent intent) { - NotificationOpenedProcessor.processFromContext(context, intent); - } - - public static void NotificationSummaryManager_updateSummaryNotificationAfterChildRemoved(Context context, OneSignalDb db, String group, boolean dismissed) { - NotificationSummaryManager.updateSummaryNotificationAfterChildRemoved(context, db, group, dismissed); - } - - public class TestOneSignalPrefs extends com.onesignal.OneSignalPrefs {} - - public static void OneSignal_onAppLostFocus() { - OneSignal.onAppLostFocus(); - } - - public static DelayedConsentInitializationParameters OneSignal_delayedInitParams() { - return OneSignal.getDelayedInitParams(); - } - - public static ConcurrentLinkedQueue OneSignal_taskQueueWaitingForInit() { - return OneSignal.getTaskRemoteController().getTaskQueueWaitingForInit(); - } - - public static void OneSignal_OSTaskController_ShutdownNow() { - OneSignal.getTaskRemoteController().shutdownNow(); - OneSignal.getTaskController().shutdownNow(); - } - - public static boolean OneSignal_requiresUserPrivacyConsent() { - return OneSignal.requiresUserPrivacyConsent(); - } - - public static boolean OneSignal_locationShared() { - return OneSignal.isLocationShared(); - } - - public static boolean OneSignal_areNotificationsEnabledForSubscribedState() { - return OneSignal.areNotificationsEnabledForSubscribedState(); - } - - public static boolean OneSignal_getDisableGMSMissingPrompt() { - return OneSignal.getDisableGMSMissingPrompt(); - } - - public static String OneSignal_appId() { - return OneSignal.appId; - } - - public static boolean OneSignal_isInForeground() { - return OneSignal.isInForeground(); - } - - static public class OSSharedPreferencesWrapper extends com.onesignal.OSSharedPreferencesWrapper {} - - static public class RemoteOutcomeParams extends OneSignalRemoteParams.InfluenceParams { - - public RemoteOutcomeParams() { - this(true, true, true); - } - - public RemoteOutcomeParams(boolean direct, boolean indirect, boolean unattributed) { - directEnabled = direct; - indirectEnabled = indirect; - unattributedEnabled = unattributed; - } - } - - public static class BadgeCountUpdater extends com.onesignal.BadgeCountUpdater { - public static void update(OneSignalDb db, Context context) { - com.onesignal.BadgeCountUpdater.update(db, context); - } - } - - public static class NotificationLimitManager extends com.onesignal.NotificationLimitManager { - public static void clearOldestOverLimitFallback(Context context, int notificationsToMakeRoomFor) { - com.onesignal.NotificationLimitManager.clearOldestOverLimitFallback(context, notificationsToMakeRoomFor); - } - - public static void clearOldestOverLimitStandard(Context context, int notificationsToMakeRoomFor) throws Throwable { - com.onesignal.NotificationLimitManager.clearOldestOverLimitStandard(context, notificationsToMakeRoomFor); - } - } - - public static class OneSignalDbContract extends com.onesignal.OneSignalDbContract {} - - /** In-App Messaging Helpers */ - - public static class OSTestInAppMessageInternal extends OSInAppMessageInternal { - - public OSTestInAppMessageInternal(@NonNull String messageId, int displaysQuantity, long lastDisplayTime, boolean displayed, Set clickIds) { - super(messageId, clickIds, displayed, new OSInAppMessageRedisplayStats(displaysQuantity, lastDisplayTime)); - } - - OSTestInAppMessageInternal(JSONObject json) throws JSONException { - super(json); - } - - public void setMessageId(String messageId) { - this.messageId = messageId; - } - - @Override - protected ArrayList> parseTriggerJson(JSONArray triggersJson) throws JSONException { - ArrayList> parsedTriggers = new ArrayList<>(); - - for (int i = 0; i < triggersJson.length(); i++) { - JSONArray ands = triggersJson.getJSONArray(i); - - ArrayList parsed = new ArrayList<>(); - - for (int j = 0; j < ands.length(); j++) { - OSTrigger trig = new OSTestTrigger(ands.getJSONObject(j)); - - parsed.add(trig); - } - - parsedTriggers.add(parsed); - } - - return parsedTriggers; - } - - @Override - public void setDisplayDuration(double displayDuration) { - super.setDisplayDuration(displayDuration); - } - - @NonNull - @Override - public Set getClickedClickIds() { - return super.getClickedClickIds(); - } - - @Override - public boolean isClickAvailable(String clickId) { - return super.isClickAvailable(clickId); - } - - @Override - public void clearClickIds() { - super.clearClickIds(); - } - - @Override - public void addClickId(String clickId) { - super.addClickId(clickId); - } - - @Override - public double getDisplayDuration() { - return super.getDisplayDuration(); - } - - @Override - public OSTestInAppMessageDisplayStats getRedisplayStats() { - return new OSTestInAppMessageDisplayStats(super.getRedisplayStats()); - } - - @Override - public void setRedisplayStats(int displayQuantity, long lastDisplayTime) { - super.setRedisplayStats(displayQuantity, lastDisplayTime); - } - - public JSONObject toJSONObject() { - return super.toJSONObject(); - } - } - - public static class OSTestInAppMessageDisplayStats extends OSInAppMessageRedisplayStats { - - private OSInAppMessageRedisplayStats displayStats; - - OSTestInAppMessageDisplayStats(OSInAppMessageRedisplayStats displayStats) { - this.displayStats = displayStats; - } - - @Override - public void setDisplayStats(OSInAppMessageRedisplayStats displayStats) { - this.displayStats.setDisplayStats(displayStats); - } - - @Override - public long getLastDisplayTime() { - return this.displayStats.getLastDisplayTime(); - } - - @Override - public void setLastDisplayTime(long lastDisplayTime) { - this.displayStats.setLastDisplayTime(lastDisplayTime); - } - - public void setLastDisplayTimeToCurrent(OSTime time) { - this.displayStats.setLastDisplayTime(time.getCurrentTimeMillis() / 1000); - } - - @Override - public void incrementDisplayQuantity() { - this.displayStats.incrementDisplayQuantity(); - } - - @Override - public int getDisplayQuantity() { - return this.displayStats.getDisplayQuantity(); - } - - @Override - public void setDisplayQuantity(int displayQuantity) { - this.displayStats.setDisplayQuantity(displayQuantity); - } - - @Override - public int getDisplayLimit() { - return this.displayStats.getDisplayLimit(); - } - - @Override - public void setDisplayLimit(int displayLimit) { - this.displayStats.setDisplayLimit(displayLimit); - } - - @Override - public long getDisplayDelay() { - return this.displayStats.getDisplayDelay(); - } - - @Override - public void setDisplayDelay(long displayDelay) { - this.displayStats.setDisplayDelay(displayDelay); - } - - @Override - public boolean shouldDisplayAgain() { - return this.displayStats.shouldDisplayAgain(); - } - - @Override - public boolean isDelayTimeSatisfied() { - return this.displayStats.isDelayTimeSatisfied(); - } - - @Override - public boolean isRedisplayEnabled() { - return this.displayStats.isRedisplayEnabled(); - } - } - - public static class OSTestTrigger extends com.onesignal.OSTrigger { - public OSTestTrigger(JSONObject json) throws JSONException { - super(json); - } - } - - public static class OSTestInAppMessageAction extends com.onesignal.OSInAppMessageAction { - public boolean closes() { - return super.doesCloseMessage(); - } - public String getClickId() { return super.getClickId(); } - - public OSTestInAppMessageAction(JSONObject json) throws JSONException { - super(json); - } - } - - public static void dismissCurrentMessage() { - OSInAppMessageInternal message = OneSignal.getInAppMessageController().getCurrentDisplayedInAppMessage(); - if (message != null) { - OneSignal.getInAppMessageController().messageWasDismissed(message); - } else { - Log.e(LOGCAT_TAG, "No currently displaying IAM to dismiss!"); - } - } - - public static boolean isInAppMessageShowing() { - return OneSignal.getInAppMessageController().isInAppMessageShowing(); - } - - public static String getShowingInAppMessageId() { - return OneSignal.getInAppMessageController().getCurrentDisplayedInAppMessage().messageId; - } - - public static ArrayList getInAppMessageDisplayQueue() { - return OneSignal.getInAppMessageController().getInAppMessageDisplayQueue(); - } - - public static void onMessageActionOccurredOnMessage(@NonNull final OSInAppMessageInternal message, @NonNull final JSONObject actionJson) throws JSONException { - OneSignal.getInAppMessageController().onMessageActionOccurredOnMessage(message, actionJson); - } - - public static void onMessageWasShown(@NonNull OSInAppMessageInternal message) { - OneSignal.getInAppMessageController().onMessageWasShown(message); - } - - public static void onPageChanged(@NonNull OSInAppMessageInternal message, @NonNull final JSONObject eventJson) { - OneSignal.getInAppMessageController().onPageChanged(message, eventJson); - } - - /** IAM Lifecycle */ - public static void onMessageWillDisplay(@NonNull final OSInAppMessageInternal message) { - OneSignal.getInAppMessageController().onMessageWillDisplay(message); - } - - public static void onMessageDidDisplay(@NonNull final OSInAppMessageInternal message) { - OneSignal.getInAppMessageController().onMessageDidDisplay(message); - } - - public static void onMessageWillDismiss(@NonNull final OSInAppMessageInternal message) { - OneSignal.getInAppMessageController().onMessageWillDismiss(message); - } - - public static void onMessageDidDismiss(@NonNull final OSInAppMessageInternal message) { - OneSignal.getInAppMessageController().onMessageDidDismiss(message); - } - - // End IAM Lifecycle - - public static List getRedisplayInAppMessages() { - List messages = OneSignal.getInAppMessageController().getRedisplayedInAppMessages(); - List testMessages = new ArrayList<>(); - - for (OSInAppMessageInternal message : messages) { - try { - JSONObject json = InAppMessagingHelpers.convertIAMtoJSONObject(message); - OSTestInAppMessageInternal testInAppMessage = new OSTestInAppMessageInternal(json); - testInAppMessage.getRedisplayStats().setDisplayStats(message.getRedisplayStats()); - testMessages.add(testInAppMessage); - - } catch (JSONException e) { - e.printStackTrace(); - } - } - return testMessages; - } - - public static boolean hasConfigChangeFlag(Activity activity, int configChangeFlag) { - return OSUtils.hasConfigChangeFlag(activity, configChangeFlag); - } - - public static int getDeviceType() { - return new OSUtils().getDeviceType(); - } - - public abstract class UserState extends com.onesignal.UserState { - UserState(String inPersistKey, boolean load) { - super(inPersistKey, load); - } - } - - public static class WebViewManager extends com.onesignal.WebViewManager { - - public static void callDismissAndAwaitNextMessage() { - lastInstance.dismissAndAwaitNextMessage(null); - } - - public void dismissAndAwaitNextMessage(@Nullable final OneSignalGenericCallback callback) { - super.dismissAndAwaitNextMessage(callback); - } - - protected WebViewManager(@NonNull OSInAppMessageInternal message, @NonNull Activity activity, @NonNull com.onesignal.OSInAppMessageContent content) { - super(message, activity, content); - } - } - - public static class JSONUtils extends com.onesignal.JSONUtils { - - public @Nullable static Map jsonObjectToMap(@Nullable JSONObject json) throws JSONException { - return com.onesignal.JSONUtils.jsonObjectToMap(json); - } - } - - public static class GenerateNotification extends com.onesignal.GenerateNotification {} - - public static class NotificationBundleProcessor extends com.onesignal.NotificationBundleProcessor {} - - public static class OSNotificationFormatHelper extends com.onesignal.OSNotificationFormatHelper {} - - public static class NotificationPayloadProcessorHMS extends com.onesignal.NotificationPayloadProcessorHMS {} - - public static class OSTestNotification extends com.onesignal.OSNotification { - public OSTestNotification(@NonNull JSONObject payload) { - super(payload); - } - - // For testing purposes - public static class OSTestNotificationBuilder { - - private List groupedNotifications; - - private String notificationID; - private String templateName, templateId; - private String title, body; - private JSONObject additionalData; - private String smallIcon; - private String largeIcon; - private String bigPicture; - private String smallIconAccentColor; - private String launchURL; - private String sound; - private String ledColor; - private int lockScreenVisibility = 1; - private String groupKey; - private String groupMessage; - private List actionButtons; - private String fromProjectNumber; - private BackgroundImageLayout backgroundImageLayout; - private String collapseId; - private int priority; - private String rawPayload; - - public OSTestNotificationBuilder() { - } - - public OSTestNotificationBuilder setGroupedNotifications(List groupedNotifications) { - this.groupedNotifications = groupedNotifications; - return this; - } - - public OSTestNotificationBuilder setNotificationID(String notificationID) { - this.notificationID = notificationID; - return this; - } - - public OSTestNotificationBuilder setTemplateName(String templateName) { - this.templateName = templateName; - return this; - } - - public OSTestNotificationBuilder setTemplateId(String templateId) { - this.templateId = templateId; - return this; - } - - public OSTestNotificationBuilder setTitle(String title) { - this.title = title; - return this; - } - - public OSTestNotificationBuilder setBody(String body) { - this.body = body; - return this; - } - - public OSTestNotificationBuilder setAdditionalData(JSONObject additionalData) { - this.additionalData = additionalData; - return this; - } - - public OSTestNotificationBuilder setSmallIcon(String smallIcon) { - this.smallIcon = smallIcon; - return this; - } - - public OSTestNotificationBuilder setLargeIcon(String largeIcon) { - this.largeIcon = largeIcon; - return this; - } - - public OSTestNotificationBuilder setBigPicture(String bigPicture) { - this.bigPicture = bigPicture; - return this; - } - - public OSTestNotificationBuilder setSmallIconAccentColor(String smallIconAccentColor) { - this.smallIconAccentColor = smallIconAccentColor; - return this; - } - - public OSTestNotificationBuilder setLaunchURL(String launchURL) { - this.launchURL = launchURL; - return this; - } - - public OSTestNotificationBuilder setSound(String sound) { - this.sound = sound; - return this; - } - - public OSTestNotificationBuilder setLedColor(String ledColor) { - this.ledColor = ledColor; - return this; - } - - public OSTestNotificationBuilder setLockScreenVisibility(int lockScreenVisibility) { - this.lockScreenVisibility = lockScreenVisibility; - return this; - } - - public OSTestNotificationBuilder setGroupKey(String groupKey) { - this.groupKey = groupKey; - return this; - } - - public OSTestNotificationBuilder setGroupMessage(String groupMessage) { - this.groupMessage = groupMessage; - return this; - } - - public OSTestNotificationBuilder setActionButtons(List actionButtons) { - this.actionButtons = actionButtons; - return this; - } - - public OSTestNotificationBuilder setFromProjectNumber(String fromProjectNumber) { - this.fromProjectNumber = fromProjectNumber; - return this; - } - - public OSTestNotificationBuilder setBackgroundImageLayout(BackgroundImageLayout backgroundImageLayout) { - this.backgroundImageLayout = backgroundImageLayout; - return this; - } - - public OSTestNotificationBuilder setCollapseId(String collapseId) { - this.collapseId = collapseId; - return this; - } - - public OSTestNotificationBuilder setPriority(int priority) { - this.priority = priority; - return this; - } - - public OSTestNotificationBuilder setRawPayload(String rawPayload) { - this.rawPayload = rawPayload; - return this; - } - - public OSNotification build() { - OSNotification payload = new OSNotification(); - payload.setGroupedNotifications(groupedNotifications); - payload.setNotificationId(notificationID); - payload.setTemplateName(templateName); - payload.setTemplateId(templateId); - payload.setTitle(title); - payload.setBody(body); - payload.setAdditionalData(additionalData); - payload.setSmallIcon(smallIcon); - payload.setLargeIcon(largeIcon); - payload.setBigPicture(bigPicture); - payload.setSmallIconAccentColor(smallIconAccentColor); - payload.setLaunchURL(launchURL); - payload.setSound(sound); - payload.setLedColor(ledColor); - payload.setLockScreenVisibility(lockScreenVisibility); - payload.setGroupKey(groupKey); - payload.setGroupMessage(groupMessage); - payload.setActionButtons(actionButtons); - payload.setFromProjectNumber(fromProjectNumber); - payload.setBackgroundImageLayout(backgroundImageLayout); - payload.setCollapseId(collapseId); - payload.setPriority(priority); - payload.setRawPayload(rawPayload); - return payload; - } - } - } - - public static class OSObservable extends com.onesignal.OSObservable { - public OSObservable(String methodName, boolean fireOnMainThread) { - super(methodName, fireOnMainThread); - } - - public void addObserver(ObserverType observer) { - super.addObserver(observer); - } - - public void removeObserver(ObserverType observer) { - super.removeObserver(observer); - } - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalShadowPackageManager.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalShadowPackageManager.java deleted file mode 100644 index b9b24eac1..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalShadowPackageManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.onesignal; - -import android.content.ComponentName; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.Bundle; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowApplicationPackageManager; - -@Implements(className = "android.app.ApplicationPackageManager") -public class OneSignalShadowPackageManager extends ShadowApplicationPackageManager { - - /* - * Mimics the int configChanges int inside of the ActivityInfo class created from the - * activity tag attribute - * - * android:configChanges="keyboard|keyboardHidden|orientation|screenSize" - */ - public static int configChanges; - - /* - * Mimics the Bundle inside of the ApplicationInfo class created from meta-data tags inside the - * AndroidManifest.xml - * - * - */ - public static Bundle metaData; - - /** - * Reset all static values (should be called before each test) - */ - public static void resetStatics() { - configChanges = 0; - metaData = new Bundle(); - } - - /** - * Add a meta data key and String value to the metaData Bundle for placement in the - * shadowed getApplicationInfo - */ - public static void addManifestMetaData(String key, Object value) { - if (value instanceof String) { - metaData.putString(key, value.toString()); - } else if (value instanceof Boolean) { - metaData.putBoolean(key, (Boolean) value); - } else { - // TODO: We should add any other cases we have for different values here - } - } - - @Implementation - protected ActivityInfo getActivityInfo(ComponentName component, int flags) - throws PackageManager.NameNotFoundException { - ActivityInfo activityInfo = super.getActivityInfo(component, flags); - - // Where we replace the ActivityInfo configChanges with our own configChanges to mimic activities with specific flags set - activityInfo.configChanges = configChanges; - return activityInfo; - } - - @Implementation - protected ApplicationInfo getApplicationInfo(String packageName, int flags) - throws PackageManager.NameNotFoundException { - ApplicationInfo applicationInfo = super.getApplicationInfo(packageName, flags); - - // Where we add extra metaData tags into the ApplicationInfo to mimic apps with specific flags set - applicationInfo.metaData.putAll(metaData); - return applicationInfo; - } - -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowBadgeCountUpdater.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowBadgeCountUpdater.java deleted file mode 100644 index f721ecbdc..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowBadgeCountUpdater.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.content.Context; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(BadgeCountUpdater.class) -public class ShadowBadgeCountUpdater { - - public static int lastCount = 0; - - @Implementation - public static void updateCount(int count, Context context) { - lastCount = count; - } - - public static void resetStatics() { - lastCount = 0; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowCustomTabsClient.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowCustomTabsClient.java deleted file mode 100644 index 09f46512f..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowCustomTabsClient.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.support.customtabs.ICustomTabsCallback; -import android.support.customtabs.ICustomTabsService; - -import androidx.browser.customtabs.CustomTabsCallback; -import androidx.browser.customtabs.CustomTabsClient; -import androidx.browser.customtabs.CustomTabsServiceConnection; -import androidx.browser.customtabs.CustomTabsSession; - -import org.robolectric.annotation.Implements; - -import java.lang.reflect.Constructor; -import java.util.Set; - -@Implements(CustomTabsClient.class) -public class ShadowCustomTabsClient { - - public static boolean bindCustomTabsServiceCalled; - public static boolean nullNewSession; - - public static void resetStatics() { - bindCustomTabsServiceCalled = false; - nullNewSession = false; - } - - public boolean warmup(long flags) { - return true; - } - - public static boolean bindCustomTabsService(final Context context, final String packageName, final CustomTabsServiceConnection connection) { - new Thread(new Runnable() { - @Override - public void run() { - try { - Constructor constructor = CustomTabsClient.class.getDeclaredConstructor( - android.support.customtabs.ICustomTabsService.class, - android.content.ComponentName.class, - android.content.Context.class - ); - constructor.setAccessible(true); - CustomTabsClient inst = constructor.newInstance(null, null, null); - - bindCustomTabsServiceCalled = true; - connection.onCustomTabsServiceConnected(null, inst); - } - catch (Throwable t) { - // Catch any errors and make it interrupt all other threads to force the unit test to fail. - t.printStackTrace(); - Set threadSet = Thread.getAllStackTraces().keySet(); - for (Thread thread : threadSet) { - if (thread.getId() != Thread.currentThread().getId()) - thread.interrupt(); - } - } - } - }, "OS_SHADOW_BIND_CUSTOM_TABS").start(); - return true; - } - - public CustomTabsSession newSession(final CustomTabsCallback callback) { - if (nullNewSession) - return null; - - try { - Constructor constructor = CustomTabsSession.class.getDeclaredConstructor( - ICustomTabsService.class, - ICustomTabsCallback.class, - ComponentName.class, - PendingIntent.class - ); - constructor.setAccessible(true); - return constructor.newInstance(null, null, null, null); - }catch (Throwable t) { - t.printStackTrace(); - } - - return null; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowCustomTabsSession.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowCustomTabsSession.java deleted file mode 100644 index b6d8e5d58..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowCustomTabsSession.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.net.Uri; -import android.os.Bundle; -import androidx.browser.customtabs.CustomTabsSession; - -import org.robolectric.annotation.Implements; - -import java.util.List; - -@Implements(CustomTabsSession.class) -public class ShadowCustomTabsSession { - - public static Uri lastURL; - - public boolean mayLaunchUrl(Uri url, Bundle extras, List otherLikelyBundles) { - lastURL = url; - return true; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowDynamicTimer.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowDynamicTimer.java deleted file mode 100644 index 88e8ede4d..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowDynamicTimer.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.onesignal; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -import java.util.ArrayList; -import java.util.Timer; -import java.util.TimerTask; - -@Implements(OSDynamicTriggerTimer.class) -public class ShadowDynamicTimer { - - /** Allows you to control if trigger timers actually get scheduled */ - public static boolean shouldScheduleTimers = true; - - /** Allows us to simply check if a timer was scheduled at all */ - public static boolean hasScheduledTimer = false; - - /** The delay value for the most recently scheduled timer */ - private static long mostRecentlyScheduledTimerDelay = 0; - - // Timers are recorded and force stopped after test to ensure they don't carry over. - private static ArrayList timers = new ArrayList<>(); - private static ArrayList timerTasks = new ArrayList<>(); - - public static void resetStatics() { - cancelTimers(); - shouldScheduleTimers = true; - hasScheduledTimer = false; - mostRecentlyScheduledTimerDelay = 0; - } - private static void cancelTimers() { - for (Timer timer : timers) - timer.cancel(); - timers = new ArrayList<>(); - - for(TimerTask timerTask : timerTasks) - timerTask.cancel(); - timerTasks = new ArrayList<>(); - } - - /** Allows us to see when the OSDynamicTriggerController schedules a timer */ - @Implementation - public static void scheduleTrigger(TimerTask task, String triggerId, long delay) { - mostRecentlyScheduledTimerDelay = delay; - - if (shouldScheduleTimers) { - hasScheduledTimer = true; - Timer timer = new Timer("trigger_test:" + triggerId); - timer.schedule(task, delay); - timers.add(timer); - timerTasks.add(task); - } - } - - public static double mostRecentTimerDelaySeconds() { - return (double)mostRecentlyScheduledTimerDelay / 1000.0f; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFCMBroadcastReceiver.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFCMBroadcastReceiver.java deleted file mode 100644 index 1f0c75d92..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFCMBroadcastReceiver.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.content.BroadcastReceiver; - -import org.robolectric.annotation.Implements; - -@Implements(BroadcastReceiver.class) -public class ShadowFCMBroadcastReceiver { - - public static boolean calledAbortBroadcast; - public static Integer lastResultCode; - - public static void resetStatics() { - calledAbortBroadcast = false; - lastResultCode = null; - } - - public boolean isOrderedBroadcast() { - return true; - } - - public void abortBroadcast() { - calledAbortBroadcast = true; - } - - public void setResultCode(int code) { - lastResultCode = code; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFirebaseAnalytics.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFirebaseAnalytics.java deleted file mode 100644 index 5b39dbc75..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFirebaseAnalytics.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2018 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.os.Bundle; - -import org.robolectric.annotation.Implements; - -@Implements(com.google.firebase.analytics.FirebaseAnalytics.class) -public class ShadowFirebaseAnalytics { - - public static String lastEventString; - public static Bundle lastEventBundle; - - public static void resetStatics() { - lastEventString = null; - lastEventBundle = null; - } - - public void logEvent(String event, Bundle bundle) { - lastEventString = event; - lastEventBundle = bundle; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFirebaseApp.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFirebaseApp.java deleted file mode 100644 index a9530386d..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFirebaseApp.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.onesignal; - -import android.content.Context; - -import androidx.annotation.NonNull; - -import com.google.firebase.FirebaseApp; -import com.google.firebase.FirebaseOptions; - -import org.robolectric.annotation.Implements; - -@Implements(com.google.firebase.FirebaseApp.class) -public class ShadowFirebaseApp { - - @NonNull - public static FirebaseApp initializeApp(@NonNull Context context, @NonNull FirebaseOptions options, @NonNull String name) { - // Throw simulates Firebase library not bundled with app - throw new RuntimeException(); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFocusHandler.kt b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFocusHandler.kt deleted file mode 100644 index b3f379f2b..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFocusHandler.kt +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Modified MIT License - * - * - * Copyright 2022 OneSignal - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.onesignal - -import android.content.Context -import com.onesignal.OSFocusHandler.Companion.onLostFocusDoWork -import org.robolectric.annotation.Implementation -import org.robolectric.annotation.Implements - -@Implements(OSFocusHandler::class) -class ShadowFocusHandler { - - @Implementation - fun startOnStartFocusWork() { - hasStopped = false - OneSignal.onAppStartFocusLogic() - } - - @Implementation - fun startOnStopFocusWork() { - hasStopped = true - } - - @Implementation - fun startOnLostFocusWorker(tag: String, delay: Long, context: Context) { - onLostFocusDoWork() - } - - companion object { - var hasStopped = false - - fun resetStatics() { - hasStopped = false - } - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFusedLocationApiWrapper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFusedLocationApiWrapper.java deleted file mode 100644 index 733f08179..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFusedLocationApiWrapper.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.location.Location; - -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.location.LocationListener; -import com.google.android.gms.location.LocationRequest; - -import org.robolectric.annotation.Implements; - -@Implements(GMSLocationController.FusedLocationApiWrapper.class) -public class ShadowFusedLocationApiWrapper { - - public static Double lat, log; - public static Float accuracy; - public static Integer type; - public static Long time; - - public static void resetStatics() { - lat = 1.0; - log = 2.0; - accuracy = 3.0f; - type = 0; - time = 12345L; - } - - public static void requestLocationUpdates(GoogleApiClient googleApiClient, LocationRequest locationRequest, LocationListener locationListener) { - } - - public static void removeLocationUpdates(GoogleApiClient googleApiClient, LocationListener locationListener) { - } - - public static Location getLastLocation(GoogleApiClient googleApiClient) { - Location location = new Location(""); - location.setLatitude(lat); location.setLongitude(log); - location.setAccuracy(accuracy); - location.setTime(time); - - return location; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGMSLocationController.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGMSLocationController.java deleted file mode 100644 index 445f44fa3..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGMSLocationController.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2018 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import org.robolectric.annotation.Implements; - -@Implements(GMSLocationController.class) -public class ShadowGMSLocationController { - - public static Integer apiFallbackTime = GMSLocationController.API_FALLBACK_TIME; - - public static void reset() { - apiFallbackTime = GMSLocationController.API_FALLBACK_TIME; - } - - public static int getApiFallbackWait() { - return apiFallbackTime; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGMSLocationUpdateListener.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGMSLocationUpdateListener.java deleted file mode 100644 index d576d710a..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGMSLocationUpdateListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.onesignal; - -import android.location.Location; - -import com.huawei.hms.location.HWLocation; -import com.huawei.hms.location.LocationResult; - -import org.robolectric.annotation.Implements; - -import java.util.ArrayList; -import java.util.List; - -@Implements(GMSLocationController.LocationUpdateListener.class) -public class ShadowGMSLocationUpdateListener { - - public static void provideFakeLocation(Location location) { - GMSLocationController.locationUpdateListener.onLocationChanged(location); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGenerateNotification.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGenerateNotification.java deleted file mode 100644 index eea540ce3..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGenerateNotification.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.onesignal; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(GenerateNotification.class) -public class ShadowGenerateNotification { - - private static boolean runningOnMainThreadCheck = false; - - @Implementation - public static void isRunningOnMainThreadCheck() { - // Remove Main thread check and throw - runningOnMainThreadCheck = true; - } - - public static boolean isRunningOnMainThreadCheckCalled() { - return runningOnMainThreadCheck; - } - - public static void resetStatics() { - runningOnMainThreadCheck = false; - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGoogleApiClientBuilder.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGoogleApiClientBuilder.java deleted file mode 100644 index ca12c8e96..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGoogleApiClientBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import androidx.annotation.NonNull; - -import com.google.android.gms.common.api.GoogleApiClient; - -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.RealObject; - -@Implements(GoogleApiClient.Builder.class) -public class ShadowGoogleApiClientBuilder { - - @RealObject private GoogleApiClient.Builder realBuilder; - - public static GoogleApiClient.ConnectionCallbacks connectionCallback; - - public GoogleApiClient.Builder addConnectionCallbacks(@NonNull GoogleApiClient.ConnectionCallbacks connectionCallback) { - ShadowGoogleApiClientBuilder.connectionCallback = connectionCallback; - - return realBuilder; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGoogleApiClientCompatProxy.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGoogleApiClientCompatProxy.java deleted file mode 100644 index 155455146..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGoogleApiClientCompatProxy.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import org.robolectric.annotation.Implements; - -@Implements(GoogleApiClientCompatProxy.class) -public class ShadowGoogleApiClientCompatProxy { - - public static boolean skipOnConnected; - - public static void restSetStaticFields() { - skipOnConnected = false; - } - - public void connect() { - if (!skipOnConnected) - ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null); - } - - public void disconnect() { } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGooglePlayServicesUtil.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGooglePlayServicesUtil.java deleted file mode 100644 index dd9a81899..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowGooglePlayServicesUtil.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2016 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.content.Context; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; - -import org.robolectric.annotation.Implements; - -@Implements(GooglePlayServicesUtil.class) -public class ShadowGooglePlayServicesUtil { - - public static int isGooglePlayServicesAvailable(Context context) { - return ConnectionResult.SUCCESS; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHMSFusedLocationProviderClient.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHMSFusedLocationProviderClient.java deleted file mode 100644 index d578e95a5..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHMSFusedLocationProviderClient.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2020 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.content.Context; -import android.location.Location; -import android.os.Handler; -import android.os.Looper; - -import com.huawei.hmf.tasks.Task; -import com.huawei.hmf.tasks.a.i; -import com.huawei.hms.location.FusedLocationProviderClient; -import com.huawei.hms.location.LocationCallback; -import com.huawei.hms.location.LocationRequest; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(FusedLocationProviderClient.class) -public class ShadowHMSFusedLocationProviderClient { - - Context context; - public static Double lat, log; - public static Float accuracy; - public static Integer type; - public static Long time; - public static boolean shadowTask = false; - public static boolean skipOnGetLocation = false; - - public static void resetStatics() { - lat = 1.0; - log = 2.0; - accuracy = 3.0f; - type = 0; - time = 12345L; - shadowTask = false; - skipOnGetLocation = false; - } - - @Implementation - public void __constructor__(Context context) { - this.context = context; - } - - public static Location getLocation() { - Location location = new Location(""); - location.setLatitude(lat); - location.setLongitude(log); - location.setAccuracy(accuracy); - location.setTime(time); - return location; - } - - @Implementation - public i getLastLocation() { - final i locationTask = new i<>(); - if (shadowTask || skipOnGetLocation) - return locationTask; - - timerLocationComplete(locationTask); - return locationTask; - - } - - @Implementation - public i requestLocationUpdates(LocationRequest var1, LocationCallback var2, Looper var3) { - return new i<>(); - } - - @Implementation - public Task removeLocationUpdates(LocationCallback var1) { - return new i<>(); - } - - private static void timerLocationComplete(final i locationTask) { - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - locationTask.a(getLocation()); - } - }, 1000); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHMSLocationUpdateListener.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHMSLocationUpdateListener.java deleted file mode 100644 index 63d649454..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHMSLocationUpdateListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.onesignal; - -import com.huawei.hms.location.HWLocation; -import com.huawei.hms.location.LocationResult; - -import org.robolectric.annotation.Implements; - -import java.util.ArrayList; -import java.util.List; - -@Implements(HMSLocationController.LocationUpdateListener.class) -public class ShadowHMSLocationUpdateListener { - - public static void provideFakeLocation_Huawei(HWLocation location) { - List locations = new ArrayList<>(); - locations.add(location); - LocationResult locationResult = LocationResult.create(locations); - HMSLocationController.locationUpdateListener.onLocationResult(locationResult); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsInstanceId.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsInstanceId.java deleted file mode 100644 index 9b85af1ad..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsInstanceId.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.onesignal; - -import android.content.Context; - -import androidx.annotation.Nullable; - -import com.huawei.hms.aaid.HmsInstanceId; -import com.huawei.hms.common.ApiException; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(HmsInstanceId.class) -public class ShadowHmsInstanceId { - - static final String DEFAULT_MOCK_HMS_TOKEN_VALUE = "MockHMSToken"; - - public static @Nullable String token; - public static @Nullable ApiException throwException; - - public static void resetStatics() { - token = DEFAULT_MOCK_HMS_TOKEN_VALUE; - throwException = null; - } - - @Implementation - public void __constructor__(Context context) { - } - - @Implementation - public String getToken(String var1, String var2) throws ApiException { - if (throwException != null) - throw throwException; - return token; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsNotificationPayloadProcessor.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsNotificationPayloadProcessor.java deleted file mode 100644 index 2c11e524f..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsNotificationPayloadProcessor.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.onesignal; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(NotificationPayloadProcessorHMS.class) -public class ShadowHmsNotificationPayloadProcessor { - - private static @Nullable - String messageData; - - public static void resetStatics() { - messageData = null; - } - - @Implementation - public static void processDataMessageReceived(@NonNull final Context context, @Nullable String data) { - messageData = data; - } - - @Nullable - public static String getMessageData() { - return messageData; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsRemoteMessage.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsRemoteMessage.java deleted file mode 100644 index 1e213b39a..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHmsRemoteMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.onesignal; - -import androidx.annotation.Nullable; - -import com.huawei.hms.push.RemoteMessage; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(RemoteMessage.class) -public class ShadowHmsRemoteMessage { - - @Nullable - public static String data; - public static int ttl; - public static long sentTime; - - @Implementation - public String getData() { - return data; - } - - @Implementation - public int getTtl() { - return ttl; - } - - public long getSentTime() { - return sentTime; - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHuaweiTask.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHuaweiTask.java deleted file mode 100644 index e9ecbaaf8..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowHuaweiTask.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2020 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import com.huawei.hmf.tasks.OnSuccessListener; -import com.huawei.hmf.tasks.Task; -import com.huawei.hmf.tasks.TaskExecutors; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.RealObject; - -@Implements(com.huawei.hmf.tasks.a.i.class) -public class ShadowHuaweiTask { - - @RealObject - private com.huawei.hmf.tasks.a.i task; - - public static OnSuccessListener successListener; - public static Object result = null; - - public static void resetStatics() { - result = null; - } - - // We will likely need to change this behavior when upgrading HMS Location to 5.0.0+ - @Implementation - public Task addOnSuccessListener(OnSuccessListener var1) { - successListener = var1; - Task taskResult = task.addOnSuccessListener(TaskExecutors.uiThread(), var1); - - if (result != null) - callSuccessListener(result); - return taskResult; - } - - public static void callSuccessListener(Object result) { - successListener.onSuccess(result); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowJobService.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowJobService.java deleted file mode 100644 index 626e937da..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowJobService.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2018 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.app.job.JobParameters; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(android.app.job.JobService.class) -public class ShadowJobService { - @Implementation - public final void jobFinished(JobParameters params, boolean needsReschedule) { - // Do nothing, real implementation throws due to onBind not being used - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowLocationUpdateListener.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowLocationUpdateListener.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationLimitManager.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationLimitManager.java deleted file mode 100644 index 135c79258..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationLimitManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.onesignal; - -import org.robolectric.annotation.Implements; - -@Implements(NotificationLimitManager.class) -public class ShadowNotificationLimitManager { - private static int MAX_NUMBER_OF_NOTIFICATIONS_INT = 2; - - public static int getMaxNumberOfNotificationsInt() { - return MAX_NUMBER_OF_NOTIFICATIONS_INT; - } - - public static String getMaxNumberOfNotificationsString() { - return Integer.toString(MAX_NUMBER_OF_NOTIFICATIONS_INT); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationManagerCompat.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationManagerCompat.java deleted file mode 100644 index 5e6e94c3a..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationManagerCompat.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2016 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import androidx.core.app.NotificationManagerCompat; - -import org.robolectric.annotation.Implements; - -@Implements(NotificationManagerCompat.class) -public class ShadowNotificationManagerCompat { - public static boolean enabled = true; - - public boolean areNotificationsEnabled() { - return enabled; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationReceivedEvent.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationReceivedEvent.java deleted file mode 100644 index 3b8598a71..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowNotificationReceivedEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.onesignal; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(OSNotificationReceivedEvent.class) -public class ShadowNotificationReceivedEvent { - - private static boolean runningOnMainThreadCheck = false; - - @Implementation - public static boolean isRunningOnMainThread() { - // Remove Main thread check and throw - runningOnMainThreadCheck = true; - return false; - } - - public static boolean isRunningOnMainThreadCheckCalled() { - return runningOnMainThreadCheck; - } - - public static void resetStatics() { - runningOnMainThreadCheck = false; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSUtils.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSUtils.java deleted file mode 100644 index cc2b64d69..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSUtils.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.onesignal; - -import android.content.Context; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(OSUtils.class) -public class ShadowOSUtils { - - public static String carrierName; - public static int subscribableStatus; - - // FireOS: ADM - public static boolean supportsADM; - public boolean supportsADM() { - return supportsADM; - } - - // Google: GCM / FCM - public static boolean hasFCMLibrary; - boolean hasFCMLibrary() { - return hasFCMLibrary; - } - - public static boolean isGMSInstalledAndEnabled; - public static boolean isGMSInstalledAndEnabled() { - return isGMSInstalledAndEnabled; - } - - // Huawei: HMS - public static boolean hasHMSAvailability; - public static boolean hasHMSAvailability() { - return hasHMSAvailability; - } - - public static boolean hasHMSPushKitLibrary; - public static boolean hasHMSPushKitLibrary() { - return hasHMSPushKitLibrary; - } - - public static boolean hasHMSAGConnectLibrary; - public static boolean hasHMSAGConnectLibrary() { - return hasHMSAGConnectLibrary; - } - - public static boolean isHMSCoreInstalledAndEnabled; - public static boolean isHMSCoreInstalledAndEnabled() { - return isHMSCoreInstalledAndEnabled; - } - - public static boolean isHMSCoreInstalledAndEnabledFallback() { - return isHMSCoreInstalledAndEnabled; - } - - public static void hasAllRecommendedFCMLibraries(boolean value) { - isGMSInstalledAndEnabled = value; - hasFCMLibrary = value; - } - - public static void hasAllRecommendedHMSLibraries(boolean value) { - // required - hasHMSPushKitLibrary = value; - hasHMSAGConnectLibrary = value; - // recommended - hasHMSAvailability = value; - } - - public static void supportsHMS(boolean value) { - hasAllRecommendedHMSLibraries(value); - isHMSCoreInstalledAndEnabled = true; - } - - /** - * Reset all static values (should be called before each test) - */ - public static void resetStatics() { - carrierName = "test1"; - subscribableStatus = 1; - - supportsADM = false; - hasFCMLibrary = false; - isGMSInstalledAndEnabled = false; - hasHMSAvailability = false; - hasHMSPushKitLibrary = false; - hasHMSAGConnectLibrary = false; - isHMSCoreInstalledAndEnabled = false; - } - - public String getCarrierName() { - return carrierName; - } - - int initializationChecker(Context context, String oneSignalAppId) { - return subscribableStatus; - } - - @Implementation - public static int getRandomDelay(int minDelay, int maxDelay) { - // unit tests fail when ReceiveReceiptWorker runs with a delay so make no delay for unit tests - return 0; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSViewUtils.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSViewUtils.java deleted file mode 100644 index 440706577..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSViewUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.onesignal; - -import android.app.Activity; -import androidx.annotation.NonNull; - -import org.robolectric.annotation.Implements; - -@Implements(OSViewUtils.class) -public class ShadowOSViewUtils { - - public static boolean isActivityFullyReady(@NonNull Activity activity) { - return true; - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSWebView.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSWebView.java deleted file mode 100644 index 027552689..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOSWebView.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.onesignal; - -import android.webkit.ValueCallback; - -import com.onesignal.WebViewManager.OSJavaScriptInterface; -import com.test.onesignal.TestHelpers; - -import org.json.JSONException; -import org.json.JSONObject; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowWebView; - -import java.util.ArrayList; -import java.util.List; - -@Implements(OSWebView.class) -public class ShadowOSWebView extends ShadowWebView { - - public static String lastData; - private static List> evalJSCallbacks; - - public static void resetStatics() { - lastData = null; - evalJSCallbacks = new ArrayList<>(); - } - - private static final JSONObject MOCK_IAM_PAGE_META_DATA; - static { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("rect", new JSONObject().put("height", 100)); - } catch (JSONException t) { - t.printStackTrace(); - } - MOCK_IAM_PAGE_META_DATA = jsonObject; - } - - private static final String MOCK_IAM_RENDERING_COMPLETE_TOP_BANNER; - static { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject - .put(OSJavaScriptInterface.EVENT_TYPE_KEY, OSJavaScriptInterface.EVENT_TYPE_RENDERING_COMPLETE) - .put(OSJavaScriptInterface.IAM_DISPLAY_LOCATION_KEY, WebViewManager.Position.TOP_BANNER) - .put(OSJavaScriptInterface.IAM_PAGE_META_DATA_KEY, MOCK_IAM_PAGE_META_DATA); - } catch (JSONException t) { - t.printStackTrace(); - } - MOCK_IAM_RENDERING_COMPLETE_TOP_BANNER = jsonObject.toString(); - } - - @Implementation - public void loadData(String data, String mimeType, String encoding) { - TestHelpers.assertMainThread(); - lastData = data; - - OSJavaScriptInterface jsInterface = (OSJavaScriptInterface)getJavascriptInterface(WebViewManager.OSJavaScriptInterface.JS_OBJ_NAME); - jsInterface.postMessage(MOCK_IAM_RENDERING_COMPLETE_TOP_BANNER); - } - - public void evaluateJavascript(String script, ValueCallback resultCallback) { - evalJSCallbacks.add(resultCallback); - } - - static public void fireEvalJSCallbacks() { - for(ValueCallback callback : evalJSCallbacks) - callback.onReceiveValue(MOCK_IAM_PAGE_META_DATA.toString()); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignal.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignal.java deleted file mode 100644 index baa9b0fce..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignal.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.onesignal; - -import android.util.Log; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(OneSignal.class) -public class ShadowOneSignal { - - public static String messages = ""; - - public static void Log(final OneSignal.LOG_LEVEL level, String message, Throwable throwable) { - messages += message; - Log.e("", message, throwable); - } - - @Implementation - public static void fireNotificationOpenedHandler(final OSNotificationOpenedResult openedResult) { - OneSignal.notificationOpenedHandler.notificationOpened(openedResult); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalDbHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalDbHelper.java deleted file mode 100644 index 9344b1cc3..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalDbHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.onesignal; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; - -import org.robolectric.annotation.Implements; - -@Implements(OneSignalDbHelper.class) -public class ShadowOneSignalDbHelper { - public static int DATABASE_VERSION; - public static boolean ignoreDuplicatedFieldsOnUpgrade; - - private static OneSignalDbHelper sInstance; - - public static void restSetStaticFields() { - ignoreDuplicatedFieldsOnUpgrade = false; - sInstance = null; - DATABASE_VERSION = OneSignalDbHelper.DATABASE_VERSION; - } - - public static int getDbVersion() { - return DATABASE_VERSION; - } - - public void onCreate(SQLiteDatabase db) { - db.execSQL(OneSignalDbHelper.SQL_CREATE_ENTRIES); - for (String ind : OneSignalDbHelper.SQL_INDEX_ENTRIES) { - db.execSQL(ind); - } - } - - public static synchronized OneSignalDbHelper getInstance(Context context) { - if (sInstance == null) - sInstance = new OneSignalDbHelper(context.getApplicationContext()); - return sInstance; - } - - // Suppress errors related to duplicates when testing DB data migrations - public static void safeExecSQL(SQLiteDatabase db, String sql) { - try { - db.execSQL(sql); - } catch (SQLiteException e) { - if (!ignoreDuplicatedFieldsOnUpgrade) - throw e; - String causeMsg = e.getCause().getMessage(); - if (!causeMsg.contains("duplicate") && !causeMsg.contains("already exists")) - throw e; - } - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalNotificationManager.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalNotificationManager.java deleted file mode 100644 index b112b879d..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalNotificationManager.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.onesignal; - -import android.content.Context; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(OneSignalNotificationManager.class) -public class ShadowOneSignalNotificationManager { - - private static boolean notificationChannelEnabled = true; - - public static void setNotificationChannelEnabled(boolean notificationChannelEnabled) { - ShadowOneSignalNotificationManager.notificationChannelEnabled = notificationChannelEnabled; - } - - @Implementation - public static boolean areNotificationsEnabled(Context context, String channelId) { - return notificationChannelEnabled; - } - - /** - * Reset all static values (should be called before each test) - */ - public static void resetStatics() { - notificationChannelEnabled = true; - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java deleted file mode 100644 index 68d7a75ad..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java +++ /dev/null @@ -1,445 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2018 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import com.test.onesignal.RestClientValidator; - -import org.json.JSONException; -import org.json.JSONObject; -import org.robolectric.annotation.Implements; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; - -import static com.onesignal.UserState.DEVICE_TYPE_EMAIL; -import static com.onesignal.UserState.DEVICE_TYPE_SMS; - -@Implements(OneSignalRestClient.class) -public class ShadowOneSignalRestClient { - - public static final String PUSH_USER_ID = "a2f7f967-e8cc-11e4-bed1-118f05be4511"; - public static final String EMAIL_USER_ID = "b007f967-98cc-11e4-bed1-118f05be4522"; - public static final String SMS_USER_ID = "d007f967-98cc-11e4-bed1-118f05be4522"; - private static final String REQUIRES_USER_PRIVACY_CONSENT = "requires_user_privacy_consent"; - private static final String RECEIVE_RECEIPTS_ENABLE = "receive_receipts_enable"; - - public enum REST_METHOD { - GET, POST, PUT - } - - public static class Request { - public REST_METHOD method; - public JSONObject payload; - public String url; - - Request(REST_METHOD method, JSONObject payload, String url) { - this.method = method; - this.payload = payload; - this.url = url; - } - - @Override - public String toString() { - return "Request{" + - "method=" + method + - ", payload=" + payload + - ", url='" + url + '\'' + - '}'; - } - } - - private static class PendingResponse { - boolean success; - String response; - OneSignalRestClient.ResponseHandler responseHandler; - Object waitingThread; - - PendingResponse(boolean success, String response, OneSignalRestClient.ResponseHandler responseHandler) { - this.success = success; - this.response = response; - this.responseHandler = responseHandler; - } - - PendingResponse(Object waitingThread) { - this.waitingThread = waitingThread; - } - } - - public static List successfulGETResponses = new ArrayList<>(); - public static ArrayList requests; - public static String lastUrl, failResponse, nextSuccessResponse, nextSuccessfulGETResponse, nextSuccessfulRegistrationResponse, pushUserId, emailUserId, smsUserId, failMethod; - public static Pattern nextSuccessfulGETResponsePattern; - public static JSONObject lastPost; - public static boolean failNext, failNextPut, failAll, failPosts, failGetParams; - public static int failHttpCode; - public static int networkCallCount; - - - // Pauses any network callbacks from firing. - // Also blocks any sync network calls. - public static boolean freezeResponses; - private static ConcurrentHashMap pendingResponses = new ConcurrentHashMap<>(); - - private static String remoteParamsGetHtmlResponse = null; - private static final String REMOTE_PARAMS = " {" + - "\"awl_list\":{}," + - "\"android_sender_id\":\"87654321\"," + - "\"chnl_lst\":[]," + - "\"enterp\":false," + - "\"outcomes\":{" + - "\"direct\":{\"enabled\":true}," + - "\"indirect\":{" + - "\"notification_attribution\":{" + - "\"minutes_since_displayed\":60," + - "\"limit\":10},\"enabled\":true" + - "}," + - "\"unattributed\":{" + - "\"enabled\":true" + - "}" + - "}," + - "\"receive_receipts_enable\":false," + - "\"unsubscribe_on_notifications_disabled\":true," + - "\"disable_gms_missing_prompt\":true," + - "\"location_shared\":true" + - "}"; - private static final String IAM_GET_HTML_RESPONSE; - static { - String value = null; - try { - value = new JSONObject() - .put("html", "") - .put("display_duration", 0.0) - .toString(); - } catch (JSONException e) { } - IAM_GET_HTML_RESPONSE = value; - } - - public static void resetStatics() { - pushUserId = PUSH_USER_ID; - emailUserId = EMAIL_USER_ID; - smsUserId = SMS_USER_ID; - - requests = new ArrayList<>(); - lastPost = null; - networkCallCount = 0; - - nextSuccessfulGETResponse = null; - nextSuccessfulGETResponsePattern = null; - - failMethod = null; - failResponse = "{}"; - nextSuccessfulRegistrationResponse = null; - nextSuccessResponse = null; - failNext = false; - failNextPut = false; - failAll = false; - failPosts = false; - failGetParams = false; - failHttpCode = 400; - - freezeResponses = false; - pendingResponses = new ConcurrentHashMap<>(); - remoteParamsGetHtmlResponse = null; - } - - public static void unFreezeResponses() { - if (!freezeResponses) - return; - freezeResponses = false; - for (Object thread : pendingResponses.keySet()) { - if (thread instanceof Thread) { - System.out.println("Start thread notify: " + thread); - synchronized (thread) { - thread.notifyAll(); - } - System.out.println("End thread notify: " + thread); - } - } - } - - public static void setNextSuccessfulJSONResponse(JSONObject response) throws JSONException { - nextSuccessResponse = response.toString(1); - } - - public static void setNextFailureJSONResponse(JSONObject response) throws JSONException { - failResponse = response.toString(1); - } - - public static void setNextSuccessfulGETJSONResponse(JSONObject response) throws JSONException { - nextSuccessfulGETResponse = response.toString(1); - } - - public static void setNextSuccessfulRegistrationResponse(JSONObject response) throws JSONException { - nextSuccessfulRegistrationResponse = response.toString(1); - } - - public static void setSuccessfulGETJSONResponses(JSONObject... responses) throws JSONException { - for (JSONObject response : responses) { - successfulGETResponses.add(response.toString(1)); - } - } - - public static void setRemoteParamsRequirePrivacyConsent(boolean requirePrivacyConsent) throws JSONException { - JSONObject remoteParams = new JSONObject().put(REQUIRES_USER_PRIVACY_CONSENT, requirePrivacyConsent); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - } - - public static void setRemoteParamsReceiveReceiptsEnable(boolean requirePrivacyConsent) throws JSONException { - JSONObject remoteParams = new JSONObject().put(RECEIVE_RECEIPTS_ENABLE, requirePrivacyConsent); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - } - - public static void setRemoteParamsGetHtmlResponse(JSONObject params) throws JSONException { - JSONObject remoteParams = new JSONObject(REMOTE_PARAMS); - Iterator keys = params.keys(); - - while (keys.hasNext()) { - String key = keys.next(); - remoteParams.put(key, params.get(key)); - } - remoteParamsGetHtmlResponse = remoteParams.toString(); - } - - public static void setAndRemoveKeyFromRemoteParams(String key) throws JSONException { - JSONObject remoteParams = new JSONObject(REMOTE_PARAMS); - if (remoteParams.has(key)) { - remoteParams.remove(key); - } - remoteParamsGetHtmlResponse = remoteParams.toString(); - } - - public static void setRemoteParamsGetHtmlResponse(String response) { - remoteParamsGetHtmlResponse = response; - } - - public static void setRemoteParamsGetHtmlResponse() { - remoteParamsGetHtmlResponse = REMOTE_PARAMS; - } - - private static void freezeSyncCall() { - if (!freezeResponses) - return; - - Object toLock = Thread.currentThread(); - pendingResponses.put(toLock, new PendingResponse(toLock)); - synchronized (toLock) { - try { - toLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public static boolean isAFrozenThread(Thread thread) { - synchronized (thread) { - boolean isIt = pendingResponses.containsKey(thread); - return isIt; - } - } - - private static void trackRequest(REST_METHOD method, JSONObject payload, String url) throws JSONException { - if (method == REST_METHOD.POST || method == REST_METHOD.PUT) - lastPost = payload; - lastUrl = url; - networkCallCount++; - - Request request = new Request(method, payload, url); - requests.add(request); - - RestClientValidator.validateRequest(request); - - System.out.println(networkCallCount + ":" + method + "@URL:" + url + "\nBODY: " + payload); - } - - private static boolean suspendResponse( - boolean success, - String response, - OneSignalRestClient.ResponseHandler responseHandler) { - if (!freezeResponses || responseHandler == null) - return false; - - pendingResponses.put(responseHandler, new PendingResponse(success, response, responseHandler)); - return true; - } - - private static boolean doFail(OneSignalRestClient.ResponseHandler responseHandler, boolean doFail) { - if (failNext || failAll || doFail || handleFailMethod(lastUrl, responseHandler)) { - if (!suspendResponse(false, failResponse, responseHandler)) - responseHandler.onFailure(failHttpCode, failResponse, new Exception()); - failNext = failNextPut = false; - return true; - } - - return false; - } - - private static boolean doFail(OneSignalRestClient.ResponseHandler responseHandler) { - return doFail(responseHandler, false); - } - - private static void mockPost(String url, JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) { - if (doFail(responseHandler, failPosts)) return; - - String retJson; - - if (nextSuccessfulRegistrationResponse != null && url.contains("players")) { - retJson = nextSuccessfulRegistrationResponse; - nextSuccessfulRegistrationResponse = null; - } - else if (url.contains("on_session")) - retJson = "{}"; - else { - int device_type = jsonBody.optInt("device_type", 0); - String id; - switch (device_type) { - case DEVICE_TYPE_EMAIL: - id = emailUserId; - break; - case DEVICE_TYPE_SMS: - id = smsUserId; - break; - default: - id = pushUserId; - } - retJson = "{\"id\": \"" + id + "\"}"; - } - - if (nextSuccessResponse != null) { - if (responseHandler != null) { - if (!suspendResponse(true, nextSuccessResponse, responseHandler)) - responseHandler.onSuccess(nextSuccessResponse); - } - nextSuccessResponse = null; - } - else if (responseHandler != null) { - if (!suspendResponse(true, retJson, responseHandler)) - responseHandler.onSuccess(retJson); - } - } - - public static void post(String url, JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) throws JSONException { - trackRequest(REST_METHOD.POST, jsonBody, url); - mockPost(url, jsonBody, responseHandler); - } - - public static void postSync(String url, JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) throws JSONException { - trackRequest(REST_METHOD.POST, jsonBody, url); - freezeSyncCall(); - mockPost(url, jsonBody, responseHandler); - } - - public static void putSync(String url, JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) throws JSONException { - trackRequest(REST_METHOD.PUT, jsonBody, url); - - freezeSyncCall(); - - if (doFail(responseHandler, failNextPut)) return; - - String response = "{\"id\": \"" + pushUserId + "\"}"; - if (!suspendResponse(true, response, responseHandler)) - responseHandler.onSuccess(response); - } - - public static void put(String url, JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) throws JSONException { - trackRequest(REST_METHOD.PUT, jsonBody, url); - - if (doFail(responseHandler, failNextPut)) return; - - responseHandler.onSuccess("{}"); - } - - public static void get(final String url, final OneSignalRestClient.ResponseHandler responseHandler, String cacheKey) throws JSONException { - trackRequest(REST_METHOD.GET, null, url); - if (failGetParams && doFail(responseHandler, true)) return; - - if (handleRemoteParamsIfAvailable(url, responseHandler)) - return; - - if (handleGetIAM(url, responseHandler)) - return; - - if (doNextSuccessfulGETResponse(url, responseHandler)) - return; - - if (nextSuccessResponse != null) { - responseHandler.onSuccess(nextSuccessResponse); - nextSuccessResponse = null; - } - } - - public static void getSync(final String url, final OneSignalRestClient.ResponseHandler responseHandler, String cacheKey) throws JSONException { - trackRequest(REST_METHOD.GET, null, url); - - if (doFail(responseHandler)) return; - - if (doNextSuccessfulGETResponse(url, responseHandler)) - return; - - if (handleGetIAM(url, responseHandler)) - return; - - responseHandler.onSuccess("{}"); - } - - private static boolean doNextSuccessfulGETResponse(final String url, final OneSignalRestClient.ResponseHandler responseHandler) { - if (nextSuccessfulGETResponse != null && - (nextSuccessfulGETResponsePattern == null || nextSuccessfulGETResponsePattern.matcher(url).matches())) { - responseHandler.onSuccess(nextSuccessfulGETResponse); - nextSuccessfulGETResponse = null; - return true; - } else if (successfulGETResponses.size() > 0) { - responseHandler.onSuccess(successfulGETResponses.remove(0)); - return true; - } - return false; - } - - private static boolean handleGetIAM(final String url, final OneSignalRestClient.ResponseHandler responseHandler) { - if (!url.startsWith("in_app_messages")) - return false; - - responseHandler.onSuccess(IAM_GET_HTML_RESPONSE); - return true; - } - - private static boolean handleRemoteParamsIfAvailable(final String url, final OneSignalRestClient.ResponseHandler responseHandler) { - if (remoteParamsGetHtmlResponse == null || !url.contains("android_params")) - return false; - - responseHandler.onSuccess(remoteParamsGetHtmlResponse); - return true; - } - - private static boolean handleFailMethod(final String url, final OneSignalRestClient.ResponseHandler responseHandler) { - return failMethod != null && url.contains(failMethod); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClientWithMockConnection.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClientWithMockConnection.java deleted file mode 100644 index 33b3de53e..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClientWithMockConnection.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2019 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; - -@Implements(OneSignalRestClient.class) -public class ShadowOneSignalRestClientWithMockConnection { - - public static MockHttpURLConnection lastConnection; - public static MockHttpURLConnection.MockResponse mockResponse; - - public static void resetStatics() { - mockResponse = new MockHttpURLConnection.MockResponse() {{ - responseBody = "{}"; - status = 200; - }}; - lastConnection = null; - } - - public static int getThreadTimeout(int timeout) { - return 1; - } - - @Implementation - public static HttpURLConnection newHttpURLConnection(String url) throws IOException { - lastConnection = new MockHttpURLConnection( - new URL("https://onesignal.com/api/v1/" + url), - mockResponse - ); - return lastConnection; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalWithMockSetupContextListeners.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalWithMockSetupContextListeners.java deleted file mode 100644 index 77fb53bdf..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalWithMockSetupContextListeners.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.onesignal; - -import com.onesignal.language.LanguageContext; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -/** - * This shadow is added for the test initWithContext_setupContextListenersNotCompleted_doesNotProduceNPE - * Changes the behavior of one method without affecting other unit tests using ShadowOneSignal - */ -@Implements(OneSignal.class) -public class ShadowOneSignalWithMockSetupContextListeners { - - /** - * Simulates setupContextListeners() in initWithContext() not completing. - * However, languageContext initialization is needed for later, so that is the only code kept - */ - @Implementation - public static void setupContextListeners(boolean wasAppContextNull) { - - // Do work here that should only happen once or at the start of a new lifecycle - if (wasAppContextNull) { - OneSignal.languageContext = new LanguageContext(OneSignal.getSharedPreferences()); - } - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorADM.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorADM.java deleted file mode 100644 index 75d840e48..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorADM.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.content.Context; - -import org.robolectric.annotation.Implements; - -import static com.onesignal.ShadowPushRegistratorFCM.regId; - -@Implements(PushRegistratorADM.class) -public class ShadowPushRegistratorADM { - - private static boolean skipComplete; - - private static PushRegistrator.RegisteredHandler lastCallback; - - public static void resetStatics() { - skipComplete = false; - - lastCallback = null; - } - - public void registerForPush(final Context context, String noKeyNeeded, final PushRegistrator.RegisteredHandler callback) { - lastCallback = callback; - - if (!skipComplete) - fireCallback(regId); - } - - public static void fireCallback(String id) { - if (lastCallback == null) - return; - - lastCallback.complete(id, 1); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorFCM.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorFCM.java deleted file mode 100644 index 271901592..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorFCM.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.content.Context; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.RealObject; - -import static org.robolectric.shadow.api.Shadow.directlyOn; - -@Implements(PushRegistratorAbstractGoogle.class) -public class ShadowPushRegistratorFCM { - - @RealObject private PushRegistratorAbstractGoogle realInstance; - - public static final String regId = "aspdfoh0fhj02hr-2h"; - - public static boolean fail; - public static boolean skipComplete; - public static String lastProjectNumber; - - private static PushRegistrator.RegisteredHandler lastCallback; - - public static void resetStatics() { - skipComplete = false; - fail = false; - lastProjectNumber = null; - lastCallback = null; - } - - public static void manualFireRegisterForPush() { - lastCallback.complete(regId, UserState.PUSH_STATUS_SUBSCRIBED); - } - - @Implementation - public void registerForPush(Context context, String senderId, PushRegistrator.RegisteredHandler callback) { - PushRegistratorAbstractGoogle pushRegistrator = directlyOn(realInstance, PushRegistratorAbstractGoogle.class); - pushRegistrator.registerForPush(context, senderId, callback); - - lastProjectNumber = senderId; - lastCallback = callback; - - if (!skipComplete) - callback.complete(fail ? null : regId, fail ? -7 : 1); - } - - @Implementation - public void internalRegisterForPush(String senderId) {} - - public static void fireLastCallback() { - lastCallback.complete(fail ? null : regId, fail ? -7 : 1); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorHMS.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorHMS.java deleted file mode 100644 index 52e1d35a6..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowPushRegistratorHMS.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.onesignal; - -import android.os.Looper; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -/** - * ONLY use to mock the timeout for old EMUI9 device. - * ShadowHmsInstanceId takes cares of the normal flow - */ -@Implements(PushRegistratorHMS.class) -public class ShadowPushRegistratorHMS { - - public static boolean backgroundSuccessful; - - public static void resetStatics() { - backgroundSuccessful = false; - } - - @Implementation - public static void doTimeOutWait() { - if (backgroundSuccessful) { - // prepare required since doTimeOutWait will be run from a new background thread. - Looper.prepare(); - new HmsMessageServiceOneSignal().onNewToken(ShadowHmsInstanceId.DEFAULT_MOCK_HMS_TOKEN_VALUE, null); - } - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowReceiveReceiptController.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowReceiveReceiptController.java deleted file mode 100644 index edbde2bb1..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowReceiveReceiptController.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.onesignal; - -import androidx.work.Constraints; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(OSReceiveReceiptController.class) -public class ShadowReceiveReceiptController { - - // Removes the constraint `setRequiredNetworkType(NetworkType.CONNECTED)` which was causing unit tests to fail - @Implementation - public Constraints buildConstraints() { - return Constraints.NONE; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowResources.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowResources.java deleted file mode 100644 index b8db7de24..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowResources.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.onesignal; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(value = android.content.res.Resources.class) -public class ShadowResources { - - // Returns 0 to mimic no resources found - @Implementation - public int getIdentifier(String name, String defType, String defPackage) { - return 0; - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowRoboNotificationManager.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowRoboNotificationManager.java deleted file mode 100644 index ae369c902..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowRoboNotificationManager.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2017 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.onesignal; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationChannelGroup; -import android.app.NotificationManager; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; - -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowNotification; -import org.robolectric.shadows.ShadowNotificationManager; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; - -import static org.robolectric.Shadows.shadowOf; - -@Implements(value = NotificationManager.class, looseSignatures = true) -public class ShadowRoboNotificationManager extends ShadowNotificationManager { - - public class PostedNotification { - - PostedNotification(int id, Notification notif) { - this.id = id; this.notif = notif; - } - - public int id; - public Notification notif; - - public ShadowNotification getShadow() { - return shadowOf(notif); - } - } - - private static Notification lastNotif; - - public static Notification getLastNotif() { - return lastNotif; - } - public static ShadowNotification getLastShadowNotif() { - return shadowOf(lastNotif); - } - - public static int lastNotifId; - - public static LinkedHashMap notifications = new LinkedHashMap<>(); - - private static ShadowRoboNotificationManager mInstance; - public ShadowRoboNotificationManager() { - mInstance = this; - } - - @Override - public void cancelAll() { - super.cancelAll(); - notifications.clear(); - } - - @Override - public void cancel(int id) { - super.cancel(id); - notifications.remove(id); - } - - @Override - public void cancel(String tag, int id) { - super.cancel(tag, id); - notifications.remove(id); - } - - @Override - public void notify(String tag, int id, Notification notification) { - lastNotif = notification; - lastNotifId = id; - notifications.put(id, new PostedNotification(id, lastNotif)); - super.notify(tag, id, notification); - } - - public static @NonNull List getNotificationsInGroup(@NonNull String group) { - List notifications = new ArrayList<>(); - for (Notification notification : mInstance.getAllNotifications()) { - if (NotificationCompat.isGroupSummary(notification)) - continue; - if (!group.equals(notification.getGroup())) - continue; - notifications.add(notification); - } - return notifications; - } - - public static NotificationChannel lastChannel; - public void createNotificationChannel(NotificationChannel channel) { - lastChannel = channel; - super.createNotificationChannel((Object)channel); - } - - public static NotificationChannelGroup lastChannelGroup; - public void createNotificationChannelGroup(NotificationChannelGroup group) { - lastChannelGroup = group; - super.createNotificationChannelGroup((Object)group); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowTimeoutHandler.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowTimeoutHandler.java deleted file mode 100644 index f14debcbb..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowTimeoutHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.onesignal; - - -import androidx.annotation.NonNull; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -import java.util.HashMap; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - * Shadow class to emulate handler post delay work, Roboelectric runs everything under a custom MainThread - * it also shadows its Loopers under a ShadowLooper.class, if we use looper outside Roboelectric custom thread - * handler and looper will end disconnected and will end on a deadlock. - * To solve this problem, for cases were we run Loopers under a custom thread, we shadow the TimeoutHandler - * to emulate the same behaviour - */ -@Implements(OSTimeoutHandler.class) -public class ShadowTimeoutHandler { - - private static boolean mockDelay = false; - private static long mockDelayMillis = 1; - - private HashMap executorHashMap = new HashMap<>(); - - public static void setMockDelayMillis(long mockDelayMillis) { - mockDelay = true; - ShadowTimeoutHandler.mockDelayMillis = mockDelayMillis; - } - - @Implementation - public void startTimeout(long timeout, @NonNull Runnable runnable) { - destroyTimeout(runnable); - OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Running startTimeout with timeout: " + timeout + " and runnable: " + runnable.toString()); - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - executor.schedule(runnable, mockDelay ? mockDelayMillis : timeout, TimeUnit.MILLISECONDS); - executorHashMap.put(runnable, executor); - } - - @Implementation - public void destroyTimeout(Runnable runnable) { - OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Running destroyTimeout with runnable: " + runnable.toString()); - ScheduledThreadPoolExecutor executor = executorHashMap.get(runnable); - if (executor != null) { - executor.shutdownNow(); - } - } - - public static void resetStatics() { - mockDelay = false; - mockDelayMillis = 1; - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java deleted file mode 100644 index fd3549b69..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java +++ /dev/null @@ -1,137 +0,0 @@ -// Clears static properties on OneSignal to simulate an app cold start. - -package com.onesignal; - -import org.json.JSONArray; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -public class StaticResetHelper { - - private static Collection classes = new ArrayList<>(); - - public static void load() { - OSLogger logger = new OSLogWrapper(); - classes.add(new ClassState(OneSignal.class, field -> { - if (field.getName().equals("unprocessedOpenedNotifis")) { - field.set(null, new ArrayList()); - return true; - } else if (field.getName().equals("remoteParamController")) { - field.set(null, new OSRemoteParamController()); - return true; - } else if (field.getName().equals("taskController")) { - field.set(null, new OSTaskController(logger)); - return true; - } else if (field.getName().equals("taskRemoteController")) { - field.set(null, new OSTaskRemoteController(OneSignal.getRemoteParamController(), logger)); - return true; - } else if (field.getName().equals("inAppMessageControllerFactory")) { - field.set(null, new OSInAppMessageControllerFactory()); - return true; - } - return false; - })); - - classes.add(new ClassState(OneSignalStateSynchronizer.class, field - -> { - if (field.getName().equals("userStatePushSynchronizer") || field.getName().equals("userStateEmailSynchronizer")) { - field.set(null, null); - return true; - } - return false; - })); - - classes.add(new ClassState(OneSignalDbHelper.class, null)); - classes.add(new ClassState(LocationController.class, null)); - classes.add(new ClassState(OSInAppMessageController.class, null)); - classes.add(new ClassState(ActivityLifecycleListener.class, null)); - classes.add(new ClassState(OSDynamicTriggerController.class, field -> { - if (field.getName().equals("sessionLaunchTime")) { - field.set(null, new Date()); - return true; - } - return false; - })); - classes.add(new ClassState(OSSessionManager.class, null)); - classes.add(new ClassState(MockSessionManager.class, null)); - classes.add(new ClassState(OSNotificationWorkManager.class, field -> { - if (field.getName().equals("notificationIds")) { - field.set(null, OSUtils.newConcurrentSet()); - return true; - } - return false; - })); - } - - private interface OtherFieldHandler { - boolean onOtherField(Field field) throws Exception; - } - - static private class ClassState { - private OtherFieldHandler otherFieldHandler; - private Class stateClass; - private Map orginalVals = new HashMap<>(); - - ClassState(Class inClass, OtherFieldHandler inOtherFieldHandler) { - stateClass = inClass; - otherFieldHandler = inOtherFieldHandler; - } - - private Object tryClone(Object v) throws Exception { - if (v instanceof Cloneable - && !Modifier.isFinal(v.getClass().getModifiers())) - return v.getClass().getMethod("clone").invoke(v); - return v; - } - - private void saveStaticValues() throws Exception { - Field[] allFields = stateClass.getDeclaredFields(); - for (Field field : allFields) { - int fieldModifiers = field.getModifiers(); - if (Modifier.isStatic(fieldModifiers) - && !Modifier.isFinal(fieldModifiers)) { - field.setAccessible(true); - Object value = tryClone(field.get(null)); - orginalVals.put(field, value); - } - } - } - - private void restSetStaticFields() throws Exception { - // appContext is manually set to null first since so many things depend on it. - OneSignal.appContext = null; - for (Map.Entry entry : orginalVals.entrySet()) { - Field field = entry.getKey(); - field.setAccessible(true); - - Object value = entry.getValue(); - if (otherFieldHandler == null || !otherFieldHandler.onOtherField(field)) - field.set(null, tryClone(value)); - } - } - } - - public static void saveStaticValues() throws Exception { - for (ClassState aClass : classes) - aClass.saveStaticValues(); - } - - public static void restSetStaticFields() throws Exception { - for (ClassState aClass : classes) - aClass.restSetStaticFields(); - - clearWebViewManger(); - } - - private static void clearWebViewManger() throws NoSuchFieldException, IllegalAccessException { - Field field = WebViewManager.class.getDeclaredField("lastInstance"); - field.setAccessible(true); - field.set(null, null); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/OSOutcomeEventDB.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/OSOutcomeEventDB.java deleted file mode 100644 index 70e8c22ab..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/OSOutcomeEventDB.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.onesignal.outcomes; - -import com.onesignal.influence.domain.OSInfluenceType; - -import org.json.JSONArray; - -import java.util.Objects; - -public class OSOutcomeEventDB { - - private OSInfluenceType iamInfluenceType; - private OSInfluenceType notificationInfluenceType; - - private JSONArray iamIds; - private JSONArray notificationIds; - - private String name; - private long timestamp; - private Float weight; - - public OSOutcomeEventDB(OSInfluenceType iamInfluenceType, - OSInfluenceType notificationInfluenceType, - String iamId, String notificationId, - String name, long timestamp, Float weight) { - this.iamInfluenceType = iamInfluenceType; - this.notificationInfluenceType = notificationInfluenceType; - JSONArray iamIds = new JSONArray(); - iamIds.put(iamId); - this.iamIds = iamIds; - JSONArray notificationIds = new JSONArray(); - iamIds.put(notificationId); - this.notificationIds = notificationIds; - this.name = name; - this.timestamp = timestamp; - this.weight = weight; - } - - public OSOutcomeEventDB(OSInfluenceType iamInfluenceType, - OSInfluenceType notificationInfluenceType, - JSONArray iamIds, JSONArray notificationIds, - String name, long timestamp, Float weight) { - this.iamInfluenceType = iamInfluenceType; - this.notificationInfluenceType = notificationInfluenceType; - this.iamIds = iamIds; - this.notificationIds = notificationIds; - this.name = name; - this.timestamp = timestamp; - this.weight = weight; - } - - public OSInfluenceType getIamInfluenceType() { - return iamInfluenceType; - } - - public void setIamInfluenceType(OSInfluenceType iamInfluenceType) { - this.iamInfluenceType = iamInfluenceType; - } - - public OSInfluenceType getNotificationInfluenceType() { - return notificationInfluenceType; - } - - public void setNotificationInfluenceType(OSInfluenceType notificationInfluenceType) { - this.notificationInfluenceType = notificationInfluenceType; - } - - public JSONArray getNotificationIds() { - return notificationIds; - } - - public void setNotificationIds(JSONArray notificationIds) { - this.notificationIds = notificationIds; - } - - public JSONArray getIamIds() { - return iamIds; - } - - public void setIamIds(JSONArray iamIds) { - this.iamIds = iamIds; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public long getTimestamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public Float getWeight() { - return weight; - } - - public void setWeight(Float weight) { - this.weight = weight; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OSOutcomeEventDB that = (OSOutcomeEventDB) o; - return timestamp == that.timestamp && - iamInfluenceType == that.iamInfluenceType && - notificationInfluenceType == that.notificationInfluenceType && - Objects.equals(iamIds, that.iamIds) && - Objects.equals(notificationIds, that.notificationIds) && - Objects.equals(name, that.name) && - Objects.equals(weight, that.weight); - } - - @Override - public int hashCode() { - return Objects.hash(iamInfluenceType, notificationInfluenceType, iamIds, notificationIds, name, timestamp, weight); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/data/MockOSCachedUniqueOutcomeTable.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/data/MockOSCachedUniqueOutcomeTable.java deleted file mode 100644 index 98d11c4df..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/data/MockOSCachedUniqueOutcomeTable.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.onesignal.outcomes.data; - -public class MockOSCachedUniqueOutcomeTable { - - public static final String ID = CachedUniqueOutcomeTable.ID; - public static final String TABLE_NAME_V1 = CachedUniqueOutcomeTable.TABLE_NAME_V1; - public static final String TABLE_NAME_V2 = CachedUniqueOutcomeTable.TABLE_NAME_V2; - public static final String COLUMN_NAME_NOTIFICATION_ID = CachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID; - public static final String COLUMN_CHANNEL_INFLUENCE_ID = CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID; - public static final String COLUMN_CHANNEL_TYPE = CachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE; - public static final String COLUMN_NAME_NAME = CachedUniqueOutcomeTable.COLUMN_NAME_NAME; - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/data/MockOSOutcomeEventsTable.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/data/MockOSOutcomeEventsTable.java deleted file mode 100644 index df4e8c1e9..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/data/MockOSOutcomeEventsTable.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.onesignal.outcomes.data; - -public class MockOSOutcomeEventsTable { - - public static final String TABLE_NAME = OutcomeEventsTable.TABLE_NAME; - // Influence ids - public static final String COLUMN_NAME_NOTIFICATION_IDS = OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS; - public static final String COLUMN_NAME_IAM_IDS = OutcomeEventsTable.COLUMN_NAME_IAM_IDS; - // Influence type; - public static final String COLUMN_NAME_SESSION = OutcomeEventsTable.COLUMN_NAME_SESSION; - public static final String COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE = OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE; - public static final String COLUMN_NAME_IAM_INFLUENCE_TYPE = OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE; - // Outcome data - public static final String COLUMN_NAME_NAME = OutcomeEventsTable.COLUMN_NAME_NAME; - public static final String COLUMN_NAME_WEIGHT = OutcomeEventsTable.COLUMN_NAME_WEIGHT; - public static final String COLUMN_NAME_TIMESTAMP = OutcomeEventsTable.COLUMN_NAME_TIMESTAMP; -} diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/domain/OSCachedUniqueOutcomeName.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/domain/OSCachedUniqueOutcomeName.java deleted file mode 100644 index eca759b97..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/outcomes/domain/OSCachedUniqueOutcomeName.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.onesignal.outcomes.domain; - -import com.onesignal.influence.domain.OSInfluenceChannel; - -import static com.onesignal.influence.domain.OSInfluenceChannel.NOTIFICATION; - -public class OSCachedUniqueOutcomeName extends OSCachedUniqueOutcome { - - private String name; - - public OSCachedUniqueOutcomeName(String name, String notificationId) { - this(name, notificationId, NOTIFICATION); - } - - public OSCachedUniqueOutcomeName(String name, String notificationId, String channel) { - this(name, notificationId, OSInfluenceChannel.fromString(channel)); - } - - public OSCachedUniqueOutcomeName(String name, String notificationId, OSInfluenceChannel channel) { - super(notificationId, channel); - this.name = name; - } - - @Override - public String getInfluenceId() { - return super.getInfluenceId(); - } - - public String getName() { - return name; - } - - @Override - public OSInfluenceChannel getChannel() { - return super.getChannel(); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/DatabaseRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/DatabaseRunner.java deleted file mode 100644 index 15e2f5e9f..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/DatabaseRunner.java +++ /dev/null @@ -1,648 +0,0 @@ -package com.test.onesignal; - -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.InAppMessagingHelpers; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalPackagePrivateHelper.InAppMessageTable; -import com.onesignal.OneSignalPackagePrivateHelper.NotificationTable; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestInAppMessageInternal; -import com.onesignal.OSOutcomeEvent; -import com.onesignal.ShadowOneSignalDbHelper; -import com.onesignal.StaticResetHelper; -import com.onesignal.influence.domain.OSInfluenceChannel; -import com.onesignal.influence.domain.OSInfluenceType; -import com.onesignal.outcomes.data.MockOSCachedUniqueOutcomeTable; -import com.onesignal.outcomes.data.MockOSOutcomeEventsTable; -import com.onesignal.outcomes.OSOutcomeEventDB; -import com.onesignal.outcomes.data.OSOutcomeTableProvider; -import com.onesignal.outcomes.domain.OSCachedUniqueOutcomeName; - -import org.json.JSONArray; -import org.json.JSONException; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.util.HashMap; -import java.util.List; - -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerKind; -import static com.test.onesignal.TestHelpers.getAllNotificationRecords; -import static com.test.onesignal.TestHelpers.getAllOutcomesRecords; -import static com.test.onesignal.TestHelpers.getAllOutcomesRecordsDBv5; -import static com.test.onesignal.TestHelpers.getAllUniqueOutcomeNotificationRecordsDB; -import static com.test.onesignal.TestHelpers.getAllUniqueOutcomeNotificationRecordsDBv5; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalDbHelper.class - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -public class DatabaseRunner { - - private static final String INTEGER_PRIMARY_KEY_TYPE = " INTEGER PRIMARY KEY"; - private static final String TEXT_TYPE = " TEXT"; - private static final String INT_TYPE = " INTEGER"; - private static final String FLOAT_TYPE = " FLOAT"; - private static final String TIMESTAMP_TYPE = " TIMESTAMP"; - private static final String COMMA_SEP = ","; - - private MockOneSignalDBHelper dbHelper; - private OSOutcomeTableProvider outcomeTableProvider; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - - outcomeTableProvider = new OSOutcomeTableProvider(); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - } - - @After - public void afterEachTest() throws Exception { - TestHelpers.afterTestCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - } - - @Test - public void shouldUpgradeDbFromV2ToV3() { - // 1. Init DB as version 2 and add one notification record - ShadowOneSignalDbHelper.DATABASE_VERSION = 2; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - writableDatabase.beginTransaction(); - ContentValues values = new ContentValues(); - values.put(NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID, 1); - writableDatabase.insertOrThrow(NotificationTable.TABLE_NAME, null, values); - writableDatabase.setTransactionSuccessful(); - writableDatabase.endTransaction(); - writableDatabase.setVersion(2); - writableDatabase.close(); - - // 2. Clear the cache of the DB so it reloads the file. - ShadowOneSignalDbHelper.restSetStaticFields(); - ShadowOneSignalDbHelper.ignoreDuplicatedFieldsOnUpgrade = true; - - // 3. Opening the DB will auto trigger the update. - HashMap notif = getAllNotificationRecords(dbHelper).get(0); - - long createdTime = (Long) notif.get(NotificationTable.COLUMN_NAME_CREATED_TIME); - long expireTime = (Long) notif.get(NotificationTable.COLUMN_NAME_EXPIRE_TIME); - assertEquals(createdTime + (72L * (60 * 60)), expireTime); - } - - @Test - public void shouldUpgradeDbFromV3ToV4() throws Exception { - // 1. Init DB as version 3 - ShadowOneSignalDbHelper.DATABASE_VERSION = 3; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSOutcomeEventsTable.TABLE_NAME + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - writableDatabase.setVersion(3); - writableDatabase.close(); - - OSOutcomeEvent event = new OSOutcomeEvent(OSInfluenceType.UNATTRIBUTED, new JSONArray().put("notificationId"), "name", 0, 0); - ContentValues values = new ContentValues(); - values.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE, event.getSession().toString().toLowerCase()); - values.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS, event.getNotificationIds().toString()); - values.put(MockOSOutcomeEventsTable.COLUMN_NAME_NAME, event.getName()); - values.put(MockOSOutcomeEventsTable.COLUMN_NAME_TIMESTAMP, event.getTimestamp()); - values.put(MockOSOutcomeEventsTable.COLUMN_NAME_WEIGHT, event.getWeight()); - - // 3. Clear the cache of the DB so it reloads the file. - ShadowOneSignalDbHelper.restSetStaticFields(); - ShadowOneSignalDbHelper.ignoreDuplicatedFieldsOnUpgrade = true; - - // 4. Opening the DB will auto trigger the update. - List events = getAllOutcomesRecordsDBv5(dbHelper); - - assertEquals(events.size(), 0); - - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - // 5. Table now must exist - writableDatabase.insert(MockOSOutcomeEventsTable.TABLE_NAME, null, values); - writableDatabase.close(); - - List outcomeEvents = getAllOutcomesRecords(dbHelper); - - assertEquals(outcomeEvents.size(), 1); - } - - private static final String SQL_CREATE_OUTCOME_REVISION1_ENTRIES = - "CREATE TABLE outcome (" + - "_id INTEGER PRIMARY KEY, " + - "session TEXT," + - "notification_ids TEXT, " + - "name TEXT, " + - "timestamp TIMESTAMP, " + - "params TEXT " + - ")"; - - private static final String SQL_CREATE_UNIQUE_OUTCOME_REVISION1_ENTRIES = - "CREATE TABLE " + MockOSCachedUniqueOutcomeTable.TABLE_NAME_V1 + " (" + - MockOSCachedUniqueOutcomeTable.ID + INTEGER_PRIMARY_KEY_TYPE + COMMA_SEP + - MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID + TEXT_TYPE + COMMA_SEP + - MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME + TEXT_TYPE + - ");"; - - @Test - public void shouldUpgradeDbFromV4ToV5() { - // 1. Init DB as version 4 - ShadowOneSignalDbHelper.DATABASE_VERSION = 4; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v4 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION1_ENTRIES); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2 + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - writableDatabase.setVersion(4); - writableDatabase.close(); - - OSCachedUniqueOutcomeName notification = new OSCachedUniqueOutcomeName("outcome", "notificationId", OSInfluenceChannel.NOTIFICATION); - ContentValues values = new ContentValues(); - values.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE, notification.getChannel().toString()); - values.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID, notification.getInfluenceId()); - values.put(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME, notification.getName()); - - // 3. Clear the cache of the DB so it reloads the file. - ShadowOneSignalDbHelper.restSetStaticFields(); - ShadowOneSignalDbHelper.ignoreDuplicatedFieldsOnUpgrade = true; - - // 4. Opening the DB will auto trigger the update. - List notifications = getAllUniqueOutcomeNotificationRecordsDB(dbHelper); - assertEquals(notifications.size(), 0); - - // 5. Table now must exist - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - writableDatabase.insert(MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2, null, values); - writableDatabase.close(); - - List uniqueOutcomeNotifications = getAllUniqueOutcomeNotificationRecordsDB(dbHelper); - - assertEquals(1, uniqueOutcomeNotifications.size()); - } - - private static final String SQL_CREATE_OUTCOME_REVISION2_ENTRIES = - "CREATE TABLE outcome (" + - "_id INTEGER PRIMARY KEY, " + - "session TEXT," + - "notification_ids TEXT, " + - "name TEXT, " + - "timestamp TIMESTAMP, " + - "weight FLOAT " + - ")"; - - - @Test - public void shouldUpgradeDbFromV5ToV6() { - // 1. Init outcome table as version 5 - ShadowOneSignalDbHelper.DATABASE_VERSION = 5; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v5 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION1_ENTRIES); - writableDatabase.execSQL(SQL_CREATE_UNIQUE_OUTCOME_REVISION1_ENTRIES); - - // Insert one outcome record so we can test migration keeps it later on - ContentValues values = new ContentValues(); - values.put("name", "a"); - writableDatabase.insertOrThrow("outcome", null, values); - writableDatabase.setVersion(5); - writableDatabase.close(); - - // 2. restSetStaticFields so the db reloads and upgrade is done to version 6 - ShadowOneSignalDbHelper.restSetStaticFields(); - - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // 3. Ensure the upgrade kept our existing record - Cursor cursor = writableDatabase.query( - "outcome", - null, - null, - null, - null, - null, - null - ); - assertTrue(cursor.moveToFirst()); - assertEquals("a", cursor.getString(cursor.getColumnIndex("name"))); - - // 4. Ensure new weight column exists - values = new ContentValues(); - values.put("weight", 1); - long successful = writableDatabase.insert("outcome", null, values); - assertFalse(successful == -1); - - // 5. Ensure params column does NOT exists - values = new ContentValues(); - values.put("params", 1); - successful = writableDatabase.insert("outcome", null, values); - writableDatabase.close(); - assertEquals(-1, successful); - } - - @Test - public void shouldUpgradeDbFromV6ToV7() throws JSONException { - // 1. Init DB as version 6 - ShadowOneSignalDbHelper.DATABASE_VERSION = 6; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v6 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION2_ENTRIES); - writableDatabase.execSQL(SQL_CREATE_UNIQUE_OUTCOME_REVISION1_ENTRIES); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + InAppMessageTable.TABLE_NAME + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - writableDatabase.setVersion(6); - writableDatabase.close(); - - // Create an IAM - final OSTestInAppMessageInternal inAppMessage = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null); - - inAppMessage.setDisplayedInSession(true); - - ContentValues values = new ContentValues(); - values.put(InAppMessageTable.COLUMN_NAME_MESSAGE_ID, inAppMessage.getMessageId()); - values.put(InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY, inAppMessage.getRedisplayStats().getDisplayQuantity()); - values.put(InAppMessageTable.COLUMN_NAME_LAST_DISPLAY, inAppMessage.getRedisplayStats().getLastDisplayTime()); - values.put(InAppMessageTable.COLUMN_CLICK_IDS, inAppMessage.getClickedClickIds().toString()); - values.put(InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION, inAppMessage.isDisplayedInSession()); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - - // 4. Opening the DB will auto trigger the update. - List savedInAppMessages = TestHelpers.getAllInAppMessages(dbHelper); - assertEquals(savedInAppMessages.size(), 0); - - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - // 5. Table now must exist - writableDatabase.insert(InAppMessageTable.TABLE_NAME, null, values); - writableDatabase.close(); - - List savedInAppMessagesAfterCreation = TestHelpers.getAllInAppMessages(dbHelper); - - assertEquals(savedInAppMessagesAfterCreation.size(), 1); - OSTestInAppMessageInternal savedInAppMessage = savedInAppMessagesAfterCreation.get(0); - assertEquals(savedInAppMessage.getRedisplayStats().getDisplayQuantity(), inAppMessage.getRedisplayStats().getDisplayQuantity()); - assertEquals(savedInAppMessage.getRedisplayStats().getLastDisplayTime(), inAppMessage.getRedisplayStats().getLastDisplayTime()); - assertEquals(savedInAppMessage.getClickedClickIds().toString(), inAppMessage.getClickedClickIds().toString()); - assertEquals(savedInAppMessage.isDisplayedInSession(), inAppMessage.isDisplayedInSession()); - } - - @Test - public void shouldUpgradeDbFromV7ToV8CacheUniqueOutcomeTable() throws JSONException { - // 1. Init DB as version 7 - ShadowOneSignalDbHelper.DATABASE_VERSION = 7; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v7 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION2_ENTRIES); - writableDatabase.execSQL(SQL_CREATE_UNIQUE_OUTCOME_REVISION1_ENTRIES); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2 + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - - // Set data to check that modification on table keep data - OSCachedUniqueOutcomeName cachedOutcomeBeforeUpdate = new OSCachedUniqueOutcomeName("outcome", "notificationId", OSInfluenceChannel.NOTIFICATION); - ContentValues uniqueOutcomeValuesBeforeUpdate = new ContentValues(); - uniqueOutcomeValuesBeforeUpdate.put(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID, cachedOutcomeBeforeUpdate.getInfluenceId()); - uniqueOutcomeValuesBeforeUpdate.put(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME, cachedOutcomeBeforeUpdate.getName()); - - writableDatabase.insert(MockOSCachedUniqueOutcomeTable.TABLE_NAME_V1, null, uniqueOutcomeValuesBeforeUpdate); - - List cachedOutcomesBeforeUpdate = getAllUniqueOutcomeNotificationRecordsDBv5(dbHelper); - assertEquals(1, cachedOutcomesBeforeUpdate.size()); - - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - writableDatabase.setVersion(7); - writableDatabase.close(); - - ContentValues uniqueOutcomeValues = new ContentValues(); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID, cachedOutcomeBeforeUpdate.getInfluenceId()); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE, cachedOutcomeBeforeUpdate.getChannel().toString()); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME, cachedOutcomeBeforeUpdate.getName()); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - ShadowOneSignalDbHelper.ignoreDuplicatedFieldsOnUpgrade = true; - - // 4. Opening the DB will auto trigger the update to DB version 8. - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - List uniqueOutcomeNotifications = getAllUniqueOutcomeNotificationRecordsDB(dbHelper); - assertEquals(1, uniqueOutcomeNotifications.size()); - assertEquals(cachedOutcomeBeforeUpdate.getInfluenceId(), uniqueOutcomeNotifications.get(0).getInfluenceId()); - assertEquals(cachedOutcomeBeforeUpdate.getChannel(), uniqueOutcomeNotifications.get(0).getChannel()); - assertEquals(cachedOutcomeBeforeUpdate.getName(), uniqueOutcomeNotifications.get(0).getName()); - } - - @Test - public void shouldUpgradeDbFromV7ToV8OutcomesTable() { - // 1. Init DB as version 7 - ShadowOneSignalDbHelper.DATABASE_VERSION = 7; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v7 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION2_ENTRIES); - writableDatabase.execSQL(SQL_CREATE_UNIQUE_OUTCOME_REVISION1_ENTRIES); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2 + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - - // Set data to check that modification on table keep data - OSOutcomeEventDB outcomeEventDB = new OSOutcomeEventDB(OSInfluenceType.DIRECT, OSInfluenceType.INDIRECT, - "iam_id", "notificationId", "outcome_outcome", 1234, (float) 1234); - - ContentValues outcomeValues = new ContentValues(); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS, outcomeEventDB.getNotificationIds().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_SESSION, outcomeEventDB.getNotificationInfluenceType().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NAME, outcomeEventDB.getName()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_WEIGHT, outcomeEventDB.getWeight()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_TIMESTAMP, outcomeEventDB.getTimestamp()); - - writableDatabase.insert(MockOSOutcomeEventsTable.TABLE_NAME, null, outcomeValues); - - List outcomesSavedBeforeUpdate = getAllOutcomesRecordsDBv5(dbHelper); - assertEquals(1, outcomesSavedBeforeUpdate.size()); - - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - writableDatabase.setVersion(7); - writableDatabase.close(); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - ShadowOneSignalDbHelper.ignoreDuplicatedFieldsOnUpgrade = true; - - // 4. Opening the DB will auto trigger the update to DB version 8. - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - List outcomesSaved = getAllOutcomesRecords(dbHelper); - assertEquals(1, outcomesSaved.size()); - OSOutcomeEventDB outcomeSaved = outcomesSaved.get(0); - - assertEquals(outcomeEventDB.getName(), outcomeSaved.getName()); - assertEquals(outcomeEventDB.getWeight(), outcomeSaved.getWeight()); - assertEquals(outcomeEventDB.getTimestamp(), outcomeSaved.getTimestamp()); - assertEquals(outcomeEventDB.getNotificationIds(), outcomeSaved.getNotificationIds()); - assertEquals(outcomeEventDB.getNotificationInfluenceType(), outcomeSaved.getNotificationInfluenceType()); - assertEquals(new JSONArray(), outcomeSaved.getIamIds()); - assertEquals(OSInfluenceType.UNATTRIBUTED, outcomeSaved.getIamInfluenceType()); - } - - @Test - public void shouldUpgradeDbFromV3ToV8UniqueOutcomeTable() { - // 1. Init DB as version 3 - ShadowOneSignalDbHelper.DATABASE_VERSION = 3; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2 + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - writableDatabase.setVersion(3); - writableDatabase.close(); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - - // 4. Opening the DB will auto trigger the update to DB version 8. - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - OSCachedUniqueOutcomeName uniqueOutcomeName = new OSCachedUniqueOutcomeName("outcome", "notificationId", OSInfluenceChannel.NOTIFICATION); - ContentValues uniqueOutcomeValues = new ContentValues(); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID, uniqueOutcomeName.getInfluenceId()); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE, uniqueOutcomeName.getChannel().toString()); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME, uniqueOutcomeName.getName()); - - writableDatabase.insert(MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2, null, uniqueOutcomeValues); - - List uniqueOutcomeNotifications = getAllUniqueOutcomeNotificationRecordsDB(dbHelper); - assertEquals(1, uniqueOutcomeNotifications.size()); - assertEquals(uniqueOutcomeName.getInfluenceId(), uniqueOutcomeNotifications.get(0).getInfluenceId()); - assertEquals(uniqueOutcomeName.getChannel(), uniqueOutcomeNotifications.get(0).getChannel()); - assertEquals(uniqueOutcomeName.getName(), uniqueOutcomeNotifications.get(0).getName()); - } - - @Test - public void shouldUpgradeDbFromV3ToV8OutcomeTable() { - // 1. Init DB as version 3 - ShadowOneSignalDbHelper.DATABASE_VERSION = 3; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSOutcomeEventsTable.TABLE_NAME + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - writableDatabase.setVersion(3); - writableDatabase.close(); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - - // 4. Opening the DB will auto trigger the update to DB version 8. - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - OSOutcomeEventDB outcomeEventDB = new OSOutcomeEventDB(OSInfluenceType.DIRECT, OSInfluenceType.INDIRECT, - "iam_id", "notificationId", "outcome_outcome", 1234, (float) 1234); - - ContentValues outcomeValues = new ContentValues(); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS, outcomeEventDB.getNotificationIds().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_IAM_IDS, outcomeEventDB.getIamIds().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE, outcomeEventDB.getNotificationInfluenceType().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE, outcomeEventDB.getIamInfluenceType().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NAME, outcomeEventDB.getName()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_WEIGHT, outcomeEventDB.getWeight()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_TIMESTAMP, outcomeEventDB.getTimestamp()); - - writableDatabase.insert(MockOSOutcomeEventsTable.TABLE_NAME, null, outcomeValues); - - List outcomesSaved = getAllOutcomesRecords(dbHelper); - assertEquals(1, outcomesSaved.size()); - OSOutcomeEventDB outcomeSaved = outcomesSaved.get(0); - - assertEquals(outcomeEventDB.getName(), outcomeSaved.getName()); - assertEquals(outcomeEventDB.getWeight(), outcomeSaved.getWeight()); - assertEquals(outcomeEventDB.getTimestamp(), outcomeSaved.getTimestamp()); - assertEquals(outcomeEventDB.getNotificationIds(), outcomeSaved.getNotificationIds()); - assertEquals(outcomeEventDB.getNotificationInfluenceType(), outcomeSaved.getNotificationInfluenceType()); - assertEquals(outcomeEventDB.getIamIds(), outcomeSaved.getIamIds()); - assertEquals(outcomeEventDB.getIamInfluenceType(), outcomeSaved.getIamInfluenceType()); - } - - @Test - public void shouldUpgradeDbFromV4ToV8UniqueOutcomeTable() { - // 1. Init DB as version 4 - ShadowOneSignalDbHelper.DATABASE_VERSION = 4; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v4 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION2_ENTRIES); - - Cursor cursor = writableDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type ='table' AND name='" + MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2 + "'", null); - - boolean exist = false; - if (cursor != null) { - exist = cursor.getCount() > 0; - cursor.close(); - } - // 2. Table must not exist - assertFalse(exist); - writableDatabase.setVersion(4); - writableDatabase.close(); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - - // 4. Opening the DB will auto trigger the update to DB version 8. - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - OSCachedUniqueOutcomeName uniqueOutcomeName = new OSCachedUniqueOutcomeName("outcome", "notificationId", OSInfluenceChannel.NOTIFICATION); - ContentValues uniqueOutcomeValues = new ContentValues(); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID, uniqueOutcomeName.getInfluenceId()); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE, uniqueOutcomeName.getChannel().toString()); - uniqueOutcomeValues.put(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME, uniqueOutcomeName.getName()); - - writableDatabase.insert(MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2, null, uniqueOutcomeValues); - - List uniqueOutcomeNotifications = getAllUniqueOutcomeNotificationRecordsDB(dbHelper); - assertEquals(1, uniqueOutcomeNotifications.size()); - assertEquals(uniqueOutcomeName.getInfluenceId(), uniqueOutcomeNotifications.get(0).getInfluenceId()); - assertEquals(uniqueOutcomeName.getChannel(), uniqueOutcomeNotifications.get(0).getChannel()); - assertEquals(uniqueOutcomeName.getName(), uniqueOutcomeNotifications.get(0).getName()); - } - - @Test - public void shouldUpgradeDbFromV4ToV8OutcomeTable() { - // 1. Init DB as version 4 - ShadowOneSignalDbHelper.DATABASE_VERSION = 4; - SQLiteDatabase writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - // Create table with the schema we had in DB v4 - writableDatabase.execSQL(SQL_CREATE_OUTCOME_REVISION1_ENTRIES); - Cursor cursor = writableDatabase.query(MockOSOutcomeEventsTable.TABLE_NAME, null, null, null, null, null, null); - - boolean exist = false; - if (cursor != null) { - String[] columns = cursor.getColumnNames(); - exist = columns.length == 6; - cursor.close(); - } - // 2. Table must not exist - assertTrue(exist); - writableDatabase.setVersion(4); - writableDatabase.close(); - - // 3. Clear the cache of the DB so it reloads the file and next getSQLiteDatabaseWithRetries will auto trigger the update - ShadowOneSignalDbHelper.restSetStaticFields(); - - // 4. Opening the DB will auto trigger the update to DB version 8. - writableDatabase = dbHelper.getSQLiteDatabaseWithRetries(); - - OSOutcomeEventDB outcomeEventDB = new OSOutcomeEventDB(OSInfluenceType.DIRECT, OSInfluenceType.INDIRECT, - "iam_id", "notificationId", "outcome_outcome", 1234, (float) 1234); - - ContentValues outcomeValues = new ContentValues(); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS, outcomeEventDB.getNotificationIds().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_IAM_IDS, outcomeEventDB.getIamIds().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE, outcomeEventDB.getNotificationInfluenceType().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE, outcomeEventDB.getIamInfluenceType().toString()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_NAME, outcomeEventDB.getName()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_WEIGHT, outcomeEventDB.getWeight()); - outcomeValues.put(MockOSOutcomeEventsTable.COLUMN_NAME_TIMESTAMP, outcomeEventDB.getTimestamp()); - - dbHelper.insert(MockOSOutcomeEventsTable.TABLE_NAME, null, outcomeValues); - - List outcomesSaved = getAllOutcomesRecords(dbHelper); - assertEquals(1, outcomesSaved.size()); - OSOutcomeEventDB outcomeSaved = outcomesSaved.get(0); - - assertEquals(outcomeEventDB.getName(), outcomeSaved.getName()); - assertEquals(outcomeEventDB.getWeight(), outcomeSaved.getWeight()); - assertEquals(outcomeEventDB.getTimestamp(), outcomeSaved.getTimestamp()); - assertEquals(outcomeEventDB.getNotificationIds(), outcomeSaved.getNotificationIds()); - assertEquals(outcomeEventDB.getNotificationInfluenceType(), outcomeSaved.getNotificationInfluenceType()); - assertEquals(outcomeEventDB.getIamIds(), outcomeSaved.getIamIds()); - assertEquals(outcomeEventDB.getIamInfluenceType(), outcomeSaved.getIamInfluenceType()); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/DeviceTypeTestsRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/DeviceTypeTestsRunner.java deleted file mode 100644 index ac65fcb5c..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/DeviceTypeTestsRunner.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.test.onesignal; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.OneSignal; -import com.onesignal.ShadowOSUtils; -import com.onesignal.StaticResetHelper; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import static com.onesignal.OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_ANDROID; -import static com.onesignal.OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_FIREOS; -import static com.onesignal.OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_HUAWEI; -import static com.onesignal.OneSignalPackagePrivateHelper.getDeviceType; -import static org.junit.Assert.assertEquals; - -@Config( - packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -public class DeviceTypeTestsRunner { - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - } - - @AfterClass - public static void afterEverything() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - } - - @After - public void afterEachTest() throws Exception { - TestHelpers.afterTestCleanup(); - } - - @Test - public void noAvailablePushChannels_defaultsToAndroid() { - assertEquals(DEVICE_TYPE_ANDROID, getDeviceType()); - } - - @Test - public void onlyADM_isFireOS() { - ShadowOSUtils.supportsADM = true; - assertEquals(DEVICE_TYPE_FIREOS, getDeviceType()); - } - - @Test - public void onlyFCM_isAndroid() { - ShadowOSUtils.hasFCMLibrary = true; - assertEquals(DEVICE_TYPE_ANDROID, getDeviceType()); - } - - @Test - public void FCMAndGMSEnabled_isAndroid() { - ShadowOSUtils.isGMSInstalledAndEnabled = true; - ShadowOSUtils.hasFCMLibrary = true; - assertEquals(DEVICE_TYPE_ANDROID, getDeviceType()); - } - - @Test - public void supportedHMS_isHuawei() { - ShadowOSUtils.isHMSCoreInstalledAndEnabled = true; - ShadowOSUtils.hasAllRecommendedHMSLibraries(true); - - assertEquals(DEVICE_TYPE_HUAWEI, getDeviceType()); - } - - @Test - public void supportsFCMAndHMS_PreferAndroid() { - ShadowOSUtils.isGMSInstalledAndEnabled = true; - ShadowOSUtils.hasFCMLibrary = true; - - ShadowOSUtils.isHMSCoreInstalledAndEnabled = true; - ShadowOSUtils.hasAllRecommendedHMSLibraries(true); - - // Prefer Google Services over Huawei if both available - assertEquals(DEVICE_TYPE_ANDROID, getDeviceType()); - } - - @Test - public void hasFCMButNoGMSOnDeviceAndHasHMS_isHuawei() { - ShadowOSUtils.isGMSInstalledAndEnabled = false; - ShadowOSUtils.hasFCMLibrary = true; - - ShadowOSUtils.isHMSCoreInstalledAndEnabled = true; - ShadowOSUtils.hasAllRecommendedHMSLibraries(true); - - // Use HMS since device does not have the "Google Play services" app or it is disabled - assertEquals(DEVICE_TYPE_HUAWEI, getDeviceType()); - } - - @Test - public void noPushSDKsAndOnlyHMSCoreInstalled_isHuawei() { - ShadowOSUtils.isHMSCoreInstalledAndEnabled = true; - assertEquals(DEVICE_TYPE_HUAWEI, getDeviceType()); - } - - @Test - public void noPushSDKsAndOnlyGoogleServicesInstalled_isAndroid() { - ShadowOSUtils.isGMSInstalledAndEnabled = true; - assertEquals(DEVICE_TYPE_ANDROID, getDeviceType()); - } - - @Test - public void supportsFCMAndADM_PreferADM() { - ShadowOSUtils.isGMSInstalledAndEnabled = true; - ShadowOSUtils.hasFCMLibrary = true; - - ShadowOSUtils.supportsADM = true; - - // Prefer ADM as if available it will always be native to the device - assertEquals(DEVICE_TYPE_FIREOS, getDeviceType()); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/HMSDataMessageReceivedIntegrationTestsRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/HMSDataMessageReceivedIntegrationTestsRunner.java deleted file mode 100644 index 9d4aa1a8b..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/HMSDataMessageReceivedIntegrationTestsRunner.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.os.Bundle; -import android.util.Log; - -import com.huawei.hms.push.RemoteMessage; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalPackagePrivateHelper.NotificationPayloadProcessorHMS; -import com.onesignal.ShadowBadgeCountUpdater; -import com.onesignal.ShadowGenerateNotification; -import com.onesignal.ShadowHmsNotificationPayloadProcessor; -import com.onesignal.ShadowHmsRemoteMessage; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowRoboNotificationManager; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.checkerframework.checker.nullness.qual.NonNull; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.util.UUID; - -import static com.onesignal.OneSignalHmsEventBridge.HMS_SENT_TIME_KEY; -import static com.onesignal.OneSignalHmsEventBridge.HMS_TTL_KEY; -import static com.onesignal.OneSignalPackagePrivateHelper.HMSEventBridge_onMessageReceive; -import static com.onesignal.OneSignalPackagePrivateHelper.HMSProcessor_processDataMessageReceived; -import static com.onesignal.OneSignalPackagePrivateHelper.OSNotificationFormatHelper.PAYLOAD_OS_NOTIFICATION_ID; -import static com.onesignal.OneSignalPackagePrivateHelper.OSNotificationFormatHelper.PAYLOAD_OS_ROOT_CUSTOM; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; - -@Config( - packageName = "com.onesignal.example", - shadows = { - ShadowRoboNotificationManager.class, - ShadowNotificationManagerCompat.class - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -public class HMSDataMessageReceivedIntegrationTestsRunner { - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - - private static final String ALERT_TEST_MESSAGE_BODY = "Test Message body"; - - private MockOSTimeImpl time; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - - ShadowOSUtils.supportsHMS(true); - - time = new MockOSTimeImpl(); - OneSignal_setTime(time); - - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - } - - @AfterClass - public static void afterEverything() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - } - - @After - public void afterEachTest() throws Exception { - TestHelpers.afterTestCleanup(); - } - - private static @NonNull String helperBasicOSPayload() throws JSONException { - return new JSONObject() {{ - put(PAYLOAD_OS_ROOT_CUSTOM, new JSONObject() {{ - put(PAYLOAD_OS_NOTIFICATION_ID, UUID.randomUUID().toString()); - }}); - put("alert", ALERT_TEST_MESSAGE_BODY); - }}.toString(); - } - - @Test - public void nullData_shouldNotThrow() { - NotificationPayloadProcessorHMS.processDataMessageReceived(blankActivity, null); - } - - @Test - public void blankData_shouldNotThrow() { - NotificationPayloadProcessorHMS.processDataMessageReceived(blankActivity, ""); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void basicPayload_shouldDisplayNotification() throws Exception { - blankActivityController.pause(); - HMSProcessor_processDataMessageReceived(blankActivity, helperBasicOSPayload()); - threadAndTaskWait(); - - assertEquals(ALERT_TEST_MESSAGE_BODY, ShadowRoboNotificationManager.getLastShadowNotif().getBigText()); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class, ShadowHmsRemoteMessage.class, ShadowBadgeCountUpdater.class }) - public void ttl_shouldNotDisplayNotification() throws Exception { - blankActivityController.pause(); - - long sentTime = 1_635_971_895_940L; - int ttl = 60; - - time.setMockedTime(sentTime * 1_000); - - ShadowHmsRemoteMessage.data = helperBasicOSPayload(); - ShadowHmsRemoteMessage.ttl = ttl; - ShadowHmsRemoteMessage.sentTime = sentTime; - - HMSEventBridge_onMessageReceive(blankActivity, new RemoteMessage(new Bundle())); - threadAndTaskWait(); - - assertEquals(0, ShadowBadgeCountUpdater.lastCount); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class, ShadowHmsRemoteMessage.class, ShadowBadgeCountUpdater.class, ShadowHmsNotificationPayloadProcessor.class }) - public void ttl_shouldDisplayNotificationWithNoTTLandSentTime() throws Exception { - blankActivityController.pause(); - - long sentTime = 1_635_971_895_940L; - - time.setMockedTime(sentTime * 1_000); - long setSentTime = time.getCurrentTimeMillis(); - - ShadowHmsRemoteMessage.data = helperBasicOSPayload(); - - HMSEventBridge_onMessageReceive(blankActivity, new RemoteMessage(new Bundle())); - threadAndTaskWait(); - - String messageData = ShadowHmsNotificationPayloadProcessor.getMessageData(); - JSONObject jsonObject = new JSONObject(messageData); - - assertEquals(OneSignalPackagePrivateHelper.OSNotificationRestoreWorkManager.getDEFAULT_TTL_IF_NOT_IN_PAYLOAD(), jsonObject.getInt(HMS_TTL_KEY)); - assertEquals(setSentTime, jsonObject.getLong(HMS_SENT_TIME_KEY)); - } - - // NOTE: More tests can be added but they would be duplicated with GenerateNotificationRunner - // In 4.0.0 or later these should be written in a reusable way between HMS, FCM, and ADM -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessageIntegrationTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessageIntegrationTests.java deleted file mode 100644 index 6c16cf91d..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessageIntegrationTests.java +++ /dev/null @@ -1,1954 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.InAppMessagingHelpers; -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockSessionManager; -import com.onesignal.OSInAppMessageAction; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestInAppMessageInternal; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger; -import com.onesignal.OneSignalPackagePrivateHelper.TestOneSignalPrefs; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowDynamicTimer; -import com.onesignal.ShadowGMSLocationController; -import com.onesignal.ShadowJobService; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOSViewUtils; -import com.onesignal.ShadowOSWebView; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; -import com.onesignal.influence.data.OSTrackerFactory; - -import org.awaitility.Awaitility; -import org.awaitility.Duration; -import org.awaitility.core.ThrowingRunnable; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerKind; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSharedPreferences; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory; -import static com.onesignal.OneSignalPackagePrivateHelper.dismissCurrentMessage; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.RestClientAsserts.assertMeasureOnV2AtIndex; -import static com.test.onesignal.TestHelpers.assertMainThread; -import static com.test.onesignal.TestHelpers.fastColdRestartApp; -import static com.test.onesignal.TestHelpers.pauseActivity; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; -import static org.junit.Assert.fail; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowPushRegistratorFCM.class, - ShadowOSUtils.class, - ShadowGMSLocationController.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowNotificationManagerCompat.class, - ShadowJobService.class, - ShadowDynamicTimer.class, - ShadowOSWebView.class, - ShadowOSViewUtils.class - }, - sdk = 21 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class InAppMessageIntegrationTests { - - private static final String ONESIGNAL_APP_ID = "b2f7f966-d8cc-11e4-bed1-df8f05be55ba"; - private static final String IAM_CLICK_ID = "button_id_123"; - private static final String IAM_OUTCOME_NAME = "outcome_name"; - private static final String IAM_TAG_KEY = "test1"; - private static final float IAM_OUTCOME_WEIGHT = 5; - private static final long SIX_MONTHS_TIME_SECONDS = 6 * 30 * 24 * 60 * 60; - private static final int LIMIT = 5; - private static final int DELAY = 60; - private MockOSTimeImpl time; - private MockOSSharedPreferences preferences; - private OSTrackerFactory trackerFactory; - private MockSessionManager sessionManager; - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - - private MockOneSignalDBHelper dbHelper; - - @BeforeClass - public static void setupClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - - Field OneSignal_CurrentSubscription = OneSignal.class.getDeclaredField("subscribableStatus"); - OneSignal_CurrentSubscription.setAccessible(true); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - ShadowDynamicTimer.shouldScheduleTimers = true; - time = new MockOSTimeImpl(); - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - TestHelpers.beforeTestInitAndCleanup(); - - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - } - - @After - public void afterEachTest() throws Exception { - // reset back to the default - ShadowDynamicTimer.shouldScheduleTimers = true; - ShadowDynamicTimer.hasScheduledTimer = false; - OneSignal.setInAppMessageClickHandler(null); - InAppMessagingHelpers.clearTestState(); - TestHelpers.afterTestCleanup(); - } - - @Test - public void testDisableInAppMessagingPreventsMessageDisplay() throws Exception { - final OSTestInAppMessageInternal testMessage = InAppMessagingHelpers.buildTestMessageWithSingleTrigger(OSTriggerKind.CUSTOM, "test_key", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 3); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(testMessage); - }}); - - OneSignalInit(); - threadAndTaskWait(); - - // the SDK now has the in app message but it cannot be shown yet since the trigger is not valid - // we will now disable in-app messages - OneSignal.pauseInAppMessages(true); - - // We will set the trigger. However, since messaging is disabled, the message should not be shown - OneSignal.addTrigger("test_key", 3); - - // Make sure 1 IAM is in the display queue - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Make sure no IAM is showing - assertFalse(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - - @Test - public void testPauseInAppMessageGetterAndSetter() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - assertFalse(OneSignal.isInAppMessagingPaused()); - - OneSignal.pauseInAppMessages(true); - assertTrue(OneSignal.isInAppMessagingPaused()); - } - - @Test - public void testMessagesDoNotDisplayPastEndTime() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithEndTime(OSTriggerKind.CUSTOM, "test_key", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 3, true); - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // the SDK should read the message from registration JSON, set up a timer, and once - // the timer fires the message should get shown. - OneSignalInit(); - threadAndTaskWait(); - - // We will set the trigger. However, since the end time is in the past the message should not be shown - OneSignal.addTrigger("test_key", 3); - // Make no IAMs are in the display queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Make sure no IAM is showing - assertFalse(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - - @Test - public void testMessagesDoDisplayBeforeEndTime() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithEndTime(OSTriggerKind.CUSTOM, "test_key", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 3, false); - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // the SDK should read the message from registration JSON, set up a timer, and once - // the timer fires the message should get shown. - OneSignalInit(); - threadAndTaskWait(); - - // We will set the trigger. However, since the end time is in the past the message should not be shown - OneSignal.addTrigger("test_key", 3); - // Make no IAMs are in the display queue - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Make sure no IAM is showing - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - - /** - * Since it is possible for multiple in-app messages to be valid at the same time, we've implemented - * a queue so that the SDK does not try to display both messages at the same time. - */ - @Test - public void testMultipleMessagesDoNotBothDisplay() throws Exception { - initializeSdkWithMultiplePendingMessages(); - - OneSignal.addTriggers(new HashMap() {{ - put("test_1", 3); - put("test_2", 2); - }}); - threadAndTaskWait(); - - // Make sure 2 items are in the display queue - assertEquals(2, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Make sure an IAM is showing - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - - // Dismiss the message - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - threadAndTaskWait(); - - // Make sure 1 item is in the display queue - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Make sure an IAM is showing - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - - // Dismiss the message - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - threadAndTaskWait(); - - // Make sure no items are in the display queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Make sure no IAM is showing - assertFalse(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - - // This tests both rotating the device or the app being resumed. - @Test - public void testMessageDismissingWhileDeviceIsRotating() throws Exception { - initializeSdkWithMultiplePendingMessages(); - - // 1. Add trigger to show IAM - OneSignal.addTriggers(new HashMap() {{ - put("test_1", 3); - put("test_2", 2); - }}); - threadAndTaskWait(); - - // 2. Assert two IAM in the queue and 1 is showing - assertEquals(2, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - - // 3. Rotate device - This will kick off a JS task to get the new height - blankActivityController.pause(); - blankActivityController.resume(); - - // 4. Dismiss the IAM - OneSignalPackagePrivateHelper.WebViewManager.callDismissAndAwaitNextMessage(); - threadAndTaskWait(); - - // 5. Now fire resize event which was scheduled in step 3. - // Test that this does not throw and handles this missing IAM view. - ShadowOSWebView.fireEvalJSCallbacks(); - - // 6. Make sure only 1 IAM ios left in queue now and it is showing - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - - // This test reproduces https://github.com/OneSignal/OneSignal-Android-SDK/issues/1000 - @Test - public void testMessageDismissingWhileNewActivityIsBeingStarted() throws Exception { - initializeSdkWithMultiplePendingMessages(); - - // 1. Add trigger to show IAM - OneSignal.addTriggers(new HashMap() {{ - put("test_2", 2); - }}); - - // 2. Activity IAM is displaying over is dismissed - blankActivityController.stop(); - - // 3. IAM is dismissed before a new Activity is shown - OneSignalPackagePrivateHelper.WebViewManager.callDismissAndAwaitNextMessage(); - - // 4. An Activity put in to focus, successful we don't throw. - blankActivityController.resume(); - } - - - private void nextResponseMultiplePendingMessages() throws JSONException { - final OSTestInAppMessageInternal testFirstMessage = InAppMessagingHelpers.buildTestMessageWithSingleTrigger(OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 3); - final OSTestInAppMessageInternal testSecondMessage = InAppMessagingHelpers.buildTestMessageWithSingleTrigger(OSTriggerKind.CUSTOM, "test_2", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(testFirstMessage); - add(testSecondMessage); - }}); - } - - // initializes the SDK with multiple mock in-app messages and sets triggers so that - // both in-app messages become valid and can be displayed - private void initializeSdkWithMultiplePendingMessages() throws Exception { - nextResponseMultiplePendingMessages(); - OneSignalInit(); - threadAndTaskWait(); - } - - @Test - public void testTimedMessageIsDisplayedOncePerSession() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.GREATER_THAN.toString(), - 0.05, - 10, - 0); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // the SDK should read the message from registration JSON, set up a timer, and once - // the timer fires the message should get shown. - OneSignalInit(); - threadAndTaskWait(); - - // wait until the timer fires after 50ms and make sure the message gets displayed - // we already have tests to make sure that the timer is actually being scheduled - // for the correct amount of time, so all we are doing here is checking to - // make sure the message actually gets displayed once the timer fires - Awaitility.await() - .atMost(new Duration(1_000, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .until(() -> OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size() == 1); - - // After IAM is added to display queue we now need to wait until it is shown - Awaitility.await() - .atMost(new Duration(1_000, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .untilAsserted(new ThrowingRunnable() { - @Override - public void run() { - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - }); - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - - // Check that the IAM is not displayed again - Awaitility.await() - .atMost(new Duration(1_000, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .until(() -> OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size() == 0); - } - - @Test - public void testAfterLastInAppTimeIsDisplayedOncePerSession() throws Exception { - final OSTestInAppMessageInternal message1 = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.GREATER_THAN.toString(), - 0.05, - 10, - 0); - - ArrayList> triggers2 = new ArrayList>() {{ - add(new ArrayList() {{ - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.SESSION_TIME, null, OSTestTrigger.OSTriggerOperator.GREATER_THAN.toString(), 0.1)); - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.TIME_SINCE_LAST_IN_APP, null, OSTestTrigger.OSTriggerOperator.GREATER_THAN.toString(), 0.05)); - }}); - }}; - final OSTestInAppMessageInternal message2 = InAppMessagingHelpers.buildTestMessageWithMultipleTriggersAndRedisplay(triggers2, 10, 0); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message1); - add(message2); - }}); - - // the SDK should read the message from registration JSON, set up a timer, and once - // the timer fires the message should get shown. - OneSignalInit(); - threadAndTaskWait(); - - // wait until the timer fires after 50ms and make sure the message gets displayed - // we already have tests to make sure that the timer is actually being scheduled - // for the correct amount of time, so all we are doing here is checking to - // make sure the message actually gets displayed once the timer fires - Awaitility.await() - .atMost(new Duration(150, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .untilAsserted(() -> { - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - try { - assertEquals(message1.getMessageId(), OneSignalPackagePrivateHelper.getShowingInAppMessageId()); - } catch (NullPointerException e) { - // Awaitility won't retry if something is thrown, but will if an assert fails. - fail("Should not throw"); - } - }); - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - - // Second in app should now display - Awaitility.await() - .atMost(new Duration(1, TimeUnit.SECONDS)) - .pollInterval(new Duration(100, TimeUnit.MILLISECONDS)) - .untilAsserted(() -> { - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - try { - assertEquals(message2.getMessageId(), OneSignalPackagePrivateHelper.getShowingInAppMessageId()); - } catch (NullPointerException e) { - // Awaitility won't retry if something is thrown, but will if an assert fails. - fail("Should not throw"); - } - }); - - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - - // Check that the IAM is not displayed again - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - /** - * If an in-app message should only be shown if (A) session_duration is > 30 seconds and - * (B) a key/value trigger is set, and it should not set up a timer until all of the non-timer - * based triggers for that message evaluate to true - *

- * For this test, a timer should never be scheduled because the key/value 'test_key' trigger - * will not be set until the session duration has already exceeded the minimum (0.05 seconds) - */ - @Test - public void testTimedMessageDisplayedAfterAllTriggersValid() throws Exception { - ArrayList> triggers = new ArrayList>() {{ - add(new ArrayList() {{ - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.CUSTOM, "test_key", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), "squirrel")); - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.SESSION_TIME, null, OSTestTrigger.OSTriggerOperator.GREATER_THAN.toString(), 0.01)); - }}); - }}; - - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithMultipleTriggers(triggers); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - OneSignalInit(); - threadAndTaskWait(); - - // no timer should be scheduled since 'test_key' != 'squirrel' - assertFalse(ShadowDynamicTimer.hasScheduledTimer); - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // since we are not actually waiting on any logic to finish, sleeping here is fine - Thread.sleep(20); - - // the message still should not be displayed - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // after setting this trigger the message should be displayed immediately - OneSignal.addTrigger("test_key", "squirrel"); - threadAndTaskWait(); - - // the message should now have been displayed - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - assertFalse(ShadowDynamicTimer.hasScheduledTimer); - } - - @Test - public void testMessageDisplayedAfterAddTriggerEqualWithStringVsNumber() throws Exception { - // Set IAM with EQUAL trigger with number value as string - final OSTestInAppMessageInternal message = - InAppMessagingHelpers.buildTestMessageWithSingleTrigger(OSTriggerKind.CUSTOM, "test", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), "5"); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // after setting this trigger the message should be displayed immediately - OneSignal.addTrigger("test", 5.0); - threadAndTaskWait(); - - // the message should now have been displayed - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - dismissCurrentMessage(); - } - - - @Test - public void testMessageDisplayedAfterAddTriggerEqualWithStringVsNumberFloat() throws Exception { - // Set IAM with EQUAL trigger with number value as string - final OSTestInAppMessageInternal message = - InAppMessagingHelpers.buildTestMessageWithSingleTrigger(OSTriggerKind.CUSTOM, "test", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), "5.5"); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // after setting this trigger the message should be displayed immediately - OneSignal.addTrigger("test", 5.50); - threadAndTaskWait(); - - // the message should now have been displayed - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - dismissCurrentMessage(); - } - - @Test - public void useCachedInAppListOnQuickColdRestart() throws Exception { - // 1. Start app - initializeSdkWithMultiplePendingMessages(); - // 2. Swipe away app - fastColdRestartApp(); - // 3. Cold Start app - initializeSdkWithMultiplePendingMessages(); - - // Should used cached triggers since we won't be making an on_session call. - // Testing for this by trying to add a trigger that should display an IAM - OneSignal.addTrigger("test_2", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void useCachedInAppListOnQuickColdRestartWhenInitFromAppClass() throws Exception { - // 1. Start app - nextResponseMultiplePendingMessages(); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - blankActivityController.resume(); - threadAndTaskWait(); - - // 2. Swipe away app - fastColdRestartApp(); - // 3. Cold Start app - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - blankActivityController.resume(); - threadAndTaskWait(); - - // Should used cached triggers since we won't be making an on_session call. - // Testing for this by trying to add a trigger that should display an IAM - OneSignal.addTrigger("test_2", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void doNotReshowInAppIfDismissed_evenAfterColdRestart() throws Exception { - // 1. Start app - initializeSdkWithMultiplePendingMessages(); - // 2. Trigger showing In App and dismiss it - OneSignal.addTrigger("test_2", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // 3. Swipe away app - fastColdRestartApp(); - // 4. Cold Start app - initializeSdkWithMultiplePendingMessages(); - // 5. Set same trigger, should not display again - OneSignal.addTrigger("test_2", 2); - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void testReshowInAppMessageIfAppBackgrounded() throws Exception { - // 1. Start app - initializeSdkWithMultiplePendingMessages(); - // 2. Trigger showing In App and dismiss it - OneSignal.addTrigger("test_2", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - // 3. Emulate backgrounding app - pauseActivity(blankActivityController); - blankActivityController.destroy(); - threadAndTaskWait(); - // 4. Put activity back to foreground - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - OneSignalInit(); - threadAndTaskWait(); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - - @Test - public void reshowInAppIfDisplayedButNeverDismissedAfterColdRestart() throws Exception { - // 1. Start app - initializeSdkWithMultiplePendingMessages(); - // 2. Trigger showing In App - OneSignal.addTrigger("test_2", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // 3. Swipe away app - fastColdRestartApp(); - // 4. Cold Start app - initializeSdkWithMultiplePendingMessages(); - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // 5. Set same trigger, should now display again, since it was never dismissed - OneSignal.addTrigger("test_2", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void testInAppMessageOnlyReceivesClickIdOnce() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - // 2. Count IAM as clicked - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - }}; - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // 3. Ensure click is sent - ShadowOneSignalRestClient.Request iamImpressionRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals("in_app_messages/" + message.getMessageId() + "/click", iamImpressionRequest.url); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // 4. Call IAM clicked again, ensure a 2nd network call is not made. - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // Verify clickId was persisted locally - Set testClickedMessages = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_CLICKED_CLICK_IDS_IAMS, - null - ); - assertEquals(1, testClickedMessages.size()); - } - - @Test - public void testInAppMessageClickActionOutcome() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray outcomes = new JSONArray(); - outcomes.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - }}); - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("outcomes", outcomes); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // 3. Ensure outcome is sent - ShadowOneSignalRestClient.Request iamOutcomeRequest = ShadowOneSignalRestClient.requests.get(3); - - assertEquals("outcomes/measure", iamOutcomeRequest.url); - // Requests: Param request + Players Request + Click request + Outcome Request - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - assertFalse(iamOutcomeRequest.payload.has("weight")); - assertFalse(iamOutcomeRequest.payload.has("direct")); - assertEquals(IAM_OUTCOME_NAME, iamOutcomeRequest.payload.get("id")); - assertEquals(1, iamOutcomeRequest.payload.get("device_type")); - } - - @Test - public void testInAppMessageClickActionOutcomeV2() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - trackerFactory = new OSTrackerFactory(preferences, new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - - OneSignal_setSharedPreferences(preferences); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray outcomes = new JSONArray(); - outcomes.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - }}); - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("outcomes", outcomes); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // 3. Ensure outcome is sent - assertMeasureOnV2AtIndex(3, "outcome_name", new JSONArray().put(message.getMessageId()), new JSONArray(), null, null); - } - - @Test - public void testInAppMessageClickActionOutcomeWithValue() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray outcomesWithWeight = new JSONArray(); - outcomesWithWeight.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - put("weight", IAM_OUTCOME_WEIGHT); - }}); - JSONObject actionWithWeight = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("outcomes", outcomesWithWeight); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, actionWithWeight); - - // 3. Ensure outcome is sent - ShadowOneSignalRestClient.Request iamOutcomeRequest = ShadowOneSignalRestClient.requests.get(3); - - assertEquals("outcomes/measure", iamOutcomeRequest.url); - // Requests: Param request + Players Request + Click request + Outcome Request - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - assertEquals(IAM_OUTCOME_WEIGHT, iamOutcomeRequest.payload.get("weight")); - assertEquals(IAM_OUTCOME_NAME, iamOutcomeRequest.payload.get("id")); - assertFalse(iamOutcomeRequest.payload.has("direct")); - assertEquals(1, iamOutcomeRequest.payload.get("device_type")); - } - - @Test - public void testOnIAMActionSendsOutcome_usingOutcomesV2() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - trackerFactory = new OSTrackerFactory(preferences, new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - - OneSignal_setSharedPreferences(preferences); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - final OSInAppMessageAction[] lastAction = new OSInAppMessageAction[1]; - OneSignal.setInAppMessageClickHandler(new OneSignal.OSInAppMessageClickHandler() { - @Override - public void inAppMessageClicked(OSInAppMessageAction result) { - lastAction[0] = result; - // Ensure we are on the main thread when running the callback, since the app developer - // will most likely need to update UI. - assertMainThread(); - - OneSignal.sendOutcome("test"); - try { - // Ensure outcome is sent - assertMeasureOnV2AtIndex(4, "test", new JSONArray().put(message.getMessageId()), new JSONArray(), null, null); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, - new JSONObject() {{ - put("id", "button_id_123"); - put("name", "my_click_name"); - }} - ); - - // Ensure we fire public callback that In-App was clicked. - assertEquals(lastAction[0].getClickName(), "my_click_name"); - } - - @Test - public void testOnIAMActionSendsOutcome_afterDismiss_usingOutcomesV2() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - trackerFactory = new OSTrackerFactory(preferences, new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - - OneSignal_setSharedPreferences(preferences); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - final OSInAppMessageAction[] lastAction = new OSInAppMessageAction[1]; - OneSignal.setInAppMessageClickHandler(new OneSignal.OSInAppMessageClickHandler() { - @Override - public void inAppMessageClicked(OSInAppMessageAction result) { - lastAction[0] = result; - // Ensure we are on the main thread when running the callback, since the app developer - // will most likely need to update UI. - assertMainThread(); - } - }); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, - new JSONObject() {{ - put("id", "button_id_123"); - put("name", "my_click_name"); - }} - ); - - // Ensure we fire public callback that In-App was clicked. - assertEquals(lastAction[0].getClickName(), "my_click_name"); - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - - OneSignal.sendOutcome("test1"); - try { - // Ensure outcome is sent but with INDIRECT influence from IAM - assertMeasureOnV2AtIndex(5, "test1", null, null, new JSONArray().put(message.getMessageId()), new JSONArray()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - @Test - public void testInAppMessageClickActionMultipleOutcomes() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray outcomes = new JSONArray(); - outcomes.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - put("weight", IAM_OUTCOME_WEIGHT); - }}); - outcomes.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - }}); - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("outcomes", outcomes); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // 3. Ensure outcome is sent - ShadowOneSignalRestClient.Request iamOutcomeRequest = ShadowOneSignalRestClient.requests.get(3); - ShadowOneSignalRestClient.Request secondIamOutcomeRequest = ShadowOneSignalRestClient.requests.get(4); - - assertEquals("outcomes/measure", iamOutcomeRequest.url); - assertEquals("outcomes/measure", secondIamOutcomeRequest.url); - // Requests: Param request + Players Request + Click request + Outcome Request x 2 - assertEquals(5, ShadowOneSignalRestClient.requests.size()); - - assertEquals(IAM_OUTCOME_WEIGHT, iamOutcomeRequest.payload.get("weight")); - assertEquals(IAM_OUTCOME_NAME, iamOutcomeRequest.payload.get("id")); - assertEquals(1, iamOutcomeRequest.payload.get("device_type")); - - assertFalse(secondIamOutcomeRequest.payload.has("weight")); - assertEquals(IAM_OUTCOME_NAME, secondIamOutcomeRequest.payload.get("id")); - assertEquals(1, secondIamOutcomeRequest.payload.get("device_type")); - } - - @Test - public void testInAppMessageClickActionDisabledOutcomes() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Disable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false)); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray outcomes = new JSONArray(); - outcomes.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - }}); - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("outcomes", outcomes); - }}; - - // 3. Send IAM action - // With unattributed outcomes disable no outcome request should happen - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - // Requests: Param request + Players Request + Click request - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - assertEquals("in_app_messages/" + message.getMessageId() + "/click", ShadowOneSignalRestClient.requests.get(2).url); - } - - @Test - public void testInAppMessageClickActionUniqueOutcome() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Enable influence outcomes - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray outcomes = new JSONArray(); - outcomes.put(new JSONObject() {{ - put("name", IAM_OUTCOME_NAME); - put("unique", true); - }}); - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("outcomes", outcomes); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - threadAndTaskWait(); - - // 3. Ensure outcome is sent - ShadowOneSignalRestClient.Request iamOutcomeRequest = ShadowOneSignalRestClient.requests.get(3); - - assertEquals("outcomes/measure", iamOutcomeRequest.url); - // Requests: Param request + Players Request + Click request + Outcome Request - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - assertEquals(IAM_OUTCOME_NAME, iamOutcomeRequest.payload.get("id")); - assertEquals(1, iamOutcomeRequest.payload.get("device_type")); - - // 4. Call IAM clicked again, ensure no 2nd outcome call is made. - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - // 5. Check no additional request was made - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - } - - @Test - public void testInAppMessageClickActionSendTag() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONObject addTags = new JSONObject() {{ - put(IAM_TAG_KEY, IAM_TAG_KEY); - }}; - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("tags", new JSONObject() {{ - put("adds", addTags); - }}); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - threadAndTaskWait(); - // 3. Ensure players call is made - ShadowOneSignalRestClient.Request iamSendTagRequest = ShadowOneSignalRestClient.requests.get(3); - - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", iamSendTagRequest.url); - // Requests: Param request + Players Request + Click request + Tag Request - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - JsonAsserts.equals(addTags, (JSONObject) iamSendTagRequest.payload.get("tags")); - } - - @Test - public void testInAppMessageClickActionRemoveTag() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - OneSignal.sendTags(new JSONObject("{" + IAM_TAG_KEY + ": \"value1\"}")); - threadAndTaskWait(); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONArray removeTags = new JSONArray(); - removeTags.put(IAM_TAG_KEY); - JSONObject actionRemove = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("tags", new JSONObject() {{ - put("removes", removeTags); - }}); - }}; - - JSONObject objectExpected = new JSONObject() {{ - put(IAM_TAG_KEY, ""); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, actionRemove); - threadAndTaskWait(); - // 3. Ensure players call is made - ShadowOneSignalRestClient.Request iamSendTagRequest = ShadowOneSignalRestClient.requests.get(3); - - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", iamSendTagRequest.url); - // Requests: Param request + Players Request + Click request + Tag Request - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - JsonAsserts.equals(objectExpected, (JSONObject) iamSendTagRequest.payload.get("tags")); - } - - @Test - public void testInAppMessageClickActionSendAndRemoveTag() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null - ); - - final JSONObject addTags = new JSONObject() {{ - put(IAM_TAG_KEY, IAM_TAG_KEY); - }}; - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("tags", new JSONObject() {{ - put("adds", addTags); - }}); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - threadAndTaskWait(); - // 3. Ensure players call is made - ShadowOneSignalRestClient.Request iamSendTagRequest = ShadowOneSignalRestClient.requests.get(3); - - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", iamSendTagRequest.url); - // Requests: Param request + Players Request + Click request + Tag Request - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - JsonAsserts.equals(addTags, (JSONObject) iamSendTagRequest.payload.get("tags")); - - final JSONArray removeTags = new JSONArray(); - removeTags.put(IAM_TAG_KEY); - final JSONObject[] lastGetTags = new JSONObject[1]; - JSONObject actionRemove = new JSONObject() {{ - put("id", IAM_CLICK_ID); - put("tags", new JSONObject() {{ - put("removes", removeTags); - }}); - }}; - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, actionRemove); - threadAndTaskWait(); - OneSignal.getTags(new OneSignal.OSGetTagsHandler() { - @Override - public void tagsAvailable(JSONObject tags) { - lastGetTags[0] = tags; - } - }); - threadAndTaskWait(); - // 3. Ensure no tags - assertEquals(1, lastGetTags.length); - assertEquals(0, lastGetTags[0].length()); - } - - @Test - public void testInAppMessageOnlyReceivesOneClick_onColdRestart() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null); - - // 2. Count IAM as clicked - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - }}; - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // 3. Cold restart app and re-init OneSignal - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - - // 4. Click on IAM again - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // Since the app restart and another message shown callback only 1 more request should exist - // So verify 4 requests exist (3 old and 1 new) - ShadowOneSignalRestClient.Request mostRecentRequest = ShadowOneSignalRestClient.requests.get(3); - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - - // Now verify the most recent request was not a click request - boolean isIamClickUrl = mostRecentRequest.url.equals("in_app_messages/" + message.getMessageId() + "/click"); - assertFalse(isIamClickUrl); - } - - @Test - public void testInAppMessageOnlyReceivesOneImpression() throws Exception { - // Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null); - - // Call message shown callback and verify only 3 requests exist (3rd being the iam impression request) - OneSignalPackagePrivateHelper.onMessageWasShown(message); - - ShadowOneSignalRestClient.Request iamImpressionRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", iamImpressionRequest.url); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // Call message shown again and make sure no other requests were made, so the impression tracking exists locally - OneSignalPackagePrivateHelper.onMessageWasShown(message); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // Verify impressioned messageId was persisted locally - Set testImpressionedMessages = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_IMPRESSIONED_IAMS, - null - ); - assertEquals(1, testImpressionedMessages.size()); - } - - @Test - public void testInAppMessageOnlyReceivesOneImpression_onColdRestart() throws Exception { - // Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), - null); - - // Trigger the impression request and caching of the impressioned messageId - OneSignalPackagePrivateHelper.onMessageWasShown(message); - - // Cold restart app and re-init OneSignal - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - - OneSignalPackagePrivateHelper.onMessageWasShown(message); - - // Since the app restart and another message shown callback only 1 more request should exist - // So verify 4 requests exist (3 old and 1 new) - ShadowOneSignalRestClient.Request mostRecentRequest = ShadowOneSignalRestClient.requests.get(3); - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - - // Now verify the most recent request was not a impression request - boolean isImpressionUrl = mostRecentRequest.url.equals("in_app_messages/" + message.getMessageId() + "/impression"); - assertFalse(isImpressionUrl); - } - - @Test - public void testInAppMessageDisplayMultipleTimes() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check impression request - int requestSize = ShadowOneSignalRestClient.requests.size(); - ShadowOneSignalRestClient.Request iamImpressionRequest = ShadowOneSignalRestClient.requests.get(requestSize - 1); - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", iamImpressionRequest.url); - - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAMs was removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - long lastDisplayTime = OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime(); - assertTrue(lastDisplayTime > 0); - - // Change time for delay to be covered - time.advanceSystemTimeBy(DELAY); - // Set same trigger, should display again - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check impression request is sent again - int requestSizeAfterRedisplay = ShadowOneSignalRestClient.requests.size(); - ShadowOneSignalRestClient.Request iamImpressionRequestAfterRedisplay = ShadowOneSignalRestClient.requests.get(requestSizeAfterRedisplay - 1); - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", iamImpressionRequestAfterRedisplay.url); - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAMs was removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(2, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - assertTrue( OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime() - lastDisplayTime >= DELAY); - } - - @Test - public void testInAppMessageDisplayMultipleTimes_sessionDurationTrigger() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay(OSTriggerKind.SESSION_TIME, "", - OSTestTrigger.OSTriggerOperator.GREATER_THAN.toString(), 0.05, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // No schedule should happen, IAM should evaluate to true - Awaitility.await() - .atMost(new Duration(1_000, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .untilAsserted(new ThrowingRunnable() { - @Override - public void run() throws Exception { - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - }); - - // After IAM is added to display queue we now need to wait until it is shown - Awaitility.await() - .atMost(new Duration(1_000, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .untilAsserted(new ThrowingRunnable() { - @Override - public void run() throws Exception { - assertTrue(OneSignalPackagePrivateHelper.isInAppMessageShowing()); - } - }); - - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAMs was removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - long lastDisplayTime = OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime(); - assertTrue(lastDisplayTime > 0); - - // Change time for delay to be covered - time.advanceSystemTimeBy(DELAY); - fastColdRestartApp(); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // No schedule should happen since session time period is very small, should evaluate to true on first run - // Wait for redisplay logic - Awaitility.await() - .atMost(new Duration(1_000, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .untilAsserted(new ThrowingRunnable() { - @Override - public void run() { - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - }); - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAMs was removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(2, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - assertTrue( OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime() - lastDisplayTime >= DELAY); - } - - @Test - public void testInAppMessageDisplayMultipleTimes_NoTriggers() throws Exception { - final long currentTimeInSeconds = System.currentTimeMillis() / 1000; - - // Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWitRedisplay(LIMIT, DELAY); - message.getRedisplayStats().setLastDisplayTime(currentTimeInSeconds); - message.getRedisplayStats().setDisplayQuantity(1); - message.setDisplayedInSession(true); - // Save IAM on DB - TestHelpers.saveIAM(message, dbHelper); - // Save IAM for dismiss - TestOneSignalPrefs.saveStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_DISMISSED_IAMS, - new HashSet<>(Collections.singletonList(message.getMessageId())) - ); - - // Check IAM was saved correctly - List savedInAppMessages = TestHelpers.getAllInAppMessages(dbHelper); - assertEquals(savedInAppMessages.size(), 1); - assertTrue(savedInAppMessages.get(0).isDisplayedInSession()); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - // Change time for delay to be covered - time.advanceSystemTimeBy(DELAY); - - // Init OneSignal with IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // First init will start a new session, then the IAM should be shown - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAM was removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Restart OneSignal - fastColdRestartApp(); - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - OneSignalInit(); - threadAndTaskWait(); - - // Change time for delay to be covered - time.advanceSystemTimeBy(DELAY * 2); - // Add trigger to call evaluateInAppMessage - OneSignal.addTrigger("test_1", 2); - // IAM shouldn't display again because It don't have triggers - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void testInAppMessageDisplayMultipleTimes_RemoveTrigger() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.NOT_EXISTS.toString(), 2, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - // Init OneSignal with IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Because trigger doesn't exist IAM will be shown immediately - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAM was removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - long lastDisplayTime = OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime(); - assertTrue(lastDisplayTime > 0); - - OneSignal.addTrigger("test_1", 2); - // Wait for the delay between redisplay - time.advanceSystemTimeBy(DELAY); - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Remove trigger, IAM should display again - OneSignal.removeTriggerForKey("test_1"); - // Check that IAM is queue for redisplay - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void testInAppMessageNoDisplayMultipleTimes_Delay() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal with IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - long lastDisplayTime = OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime(); - assertTrue(lastDisplayTime > 0); - - // Set trigger, will evaluate IAMs again - OneSignal.addTrigger("test_1", 2); - - // Check that the IAM was not displayed again because time between display is not covered - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - assertEquals(lastDisplayTime, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime()); - } - - @Test - public void testInAppMessageNoDisplayMultipleTimes_Limit() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, 1, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal with IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - long lastDisplayTime = OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime(); - assertTrue(lastDisplayTime > 0); - - // Wait for the delay between redisplay - time.advanceSystemTimeBy(DELAY); - - // Set trigger, will evaluate IAMs again - OneSignal.addTrigger("test_1", 2); - - // Check that the IAM was not displayed again because Limit of display is 1 - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - assertEquals(lastDisplayTime, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime()); - } - - @Test - public void testInAppMessageDisplayMultipleTimes_onColdRestart() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal with IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Check impression request - int requestSize = ShadowOneSignalRestClient.requests.size(); - ShadowOneSignalRestClient.Request iamImpressionRequest = ShadowOneSignalRestClient.requests.get(requestSize - 1); - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", iamImpressionRequest.url); - - // Dismiss IAM will make display quantity increase and last display time to change - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check IAM removed from queue - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - long lastDisplayTime = OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime(); - assertTrue(lastDisplayTime > 0); - - // Wait for the delay between redisplay - time.advanceSystemTimeBy(DELAY); - // Swipe away app - fastColdRestartApp(); - // Cold Start app - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - OneSignalInit(); - threadAndTaskWait(); - // Check No IAMs - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Set same trigger, should display again - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Check impression request is sent again - int requestSizeAfterRedisplay = ShadowOneSignalRestClient.requests.size(); - ShadowOneSignalRestClient.Request iamImpressionRequestAfterRedisplay = ShadowOneSignalRestClient.requests.get(requestSizeAfterRedisplay - 1); - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", iamImpressionRequestAfterRedisplay.url); - - OneSignalPackagePrivateHelper.dismissCurrentMessage(); - // Check if data after dismiss is set correctly - assertEquals(1, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().size()); - assertEquals(2, OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getDisplayQuantity()); - assertTrue(OneSignalPackagePrivateHelper.getRedisplayInAppMessages().get(0).getRedisplayStats().getLastDisplayTime() - lastDisplayTime >= DELAY); - } - - @Test - public void testInAppMessageMultipleRedisplayReceivesClickId() throws Exception { - // Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // Create an IAM - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - assertTrue(message.getClickedClickIds().isEmpty()); - // Count IAM as clicked - JSONObject action = new JSONObject() {{ - put("id", IAM_CLICK_ID); - }}; - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // Ensure click is sent - ShadowOneSignalRestClient.Request firstIAMClickRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals("in_app_messages/" + message.getMessageId() + "/click", firstIAMClickRequest.url); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // Call IAM clicked again, ensure a 2nd network call isn't made. - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // Verify clickId was persisted locally - Set testClickedMessages = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_CLICKED_CLICK_IDS_IAMS, - null - ); - assertEquals(1, testClickedMessages.size()); - // Verify click id is associated with message - assertEquals(1, message.getClickedClickIds().size()); - assertTrue(message.getClickedClickIds().contains(IAM_CLICK_ID)); - - message.clearClickIds(); - assertTrue(message.getClickedClickIds().isEmpty()); - - // Click should be received twice - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // Call IAM clicked again, ensure a 2nd network call is made. - ShadowOneSignalRestClient.Request secondIAMClickRequest = ShadowOneSignalRestClient.requests.get(3); - assertEquals("in_app_messages/" + message.getMessageId() + "/click", secondIAMClickRequest.url); - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - - // Verify clickId was persisted locally - Set secondRestClickedMessages = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_CLICKED_CLICK_IDS_IAMS, - null - ); - assertEquals(1, secondRestClickedMessages.size()); - - // Verify click id is associated with message - assertEquals(1, message.getClickedClickIds().size()); - assertTrue(message.getClickedClickIds().contains(IAM_CLICK_ID)); - - // Call IAM clicked again - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, action); - - // Call IAM clicked again, ensure a 3nd network call isn't made. - assertEquals("in_app_messages/" + message.getMessageId() + "/click", secondIAMClickRequest.url); - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - } - - @Test - public void testCachedIAMSharedPreferenceAndSQL_cleanedAfterSixMonths() throws Exception { - final long currentTimeInSeconds = System.currentTimeMillis() / 1_000L; - - // 1. Setup IAMs - // Create an IAM younger than 6 months - final OSTestInAppMessageInternal iam1 = InAppMessagingHelpers.buildTestMessage(null); - iam1.setRedisplayStats(1, currentTimeInSeconds - SIX_MONTHS_TIME_SECONDS + 10); - String clickId1 = "iam1_click_id_1"; - iam1.addClickId(clickId1); - TestHelpers.saveIAM(iam1, dbHelper); - - // Create an IAM older than 6 months - final OSTestInAppMessageInternal iam2 = InAppMessagingHelpers.buildTestMessage(null); - iam2.setRedisplayStats(1, currentTimeInSeconds - SIX_MONTHS_TIME_SECONDS - 10); - String clickId2 = "iam2_click_id_1"; - iam2.addClickId(clickId2); - TestHelpers.saveIAM(iam2, dbHelper); - - // 2. Cache IAMs as dismissed, impressioned, and clicked - Set messageIds = new HashSet() {{ - add(iam1.getMessageId()); - add(iam2.getMessageId()); - }}; - TestOneSignalPrefs.saveStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_DISMISSED_IAMS, - messageIds); - - TestOneSignalPrefs.saveStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_IMPRESSIONED_IAMS, - messageIds); - - Set clickedClickIds = new HashSet() {{ - addAll(iam1.getClickedClickIds()); - addAll(iam2.getClickedClickIds()); - }}; - TestOneSignalPrefs.saveStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_CLICKED_CLICK_IDS_IAMS, - clickedClickIds); - - // 3. Init OneSignal so it attempts to clean IAM cache - OneSignalInit(); - threadAndTaskWait(); - - // 4. Validate all data associated with the 6 month old IAM has been deleted - Set testDismissedMessages = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_DISMISSED_IAMS, - null); - assertEquals(1, testDismissedMessages.size()); - assertTrue(testDismissedMessages.contains(iam1.getMessageId())); - - Set testImpressionedMessages = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_IMPRESSIONED_IAMS, - null); - assertEquals(1, testImpressionedMessages.size()); - assertTrue(testImpressionedMessages.contains(iam1.getMessageId())); - - Set testClickedClickIds = TestOneSignalPrefs.getStringSet( - TestOneSignalPrefs.PREFS_ONESIGNAL, - TestOneSignalPrefs.PREFS_OS_CLICKED_CLICK_IDS_IAMS, - null); - assertEquals(1, testClickedClickIds.size()); - assertTrue(testClickedClickIds.contains(clickId1)); - - // 5. Make sure only IAM left is the IAM younger than 6 months - List savedInAppMessagesAfterInit = TestHelpers.getAllInAppMessages(dbHelper); - assertEquals(1, savedInAppMessagesAfterInit.size()); - assertEquals(iam1.getMessageId(), savedInAppMessagesAfterInit.get(0).getMessageId()); - } - - @Test - public void testInAppMessageRedisplayCacheCleaning() throws Exception { - final long currentTimeInSeconds = System.currentTimeMillis() / 1000; - - final OSTestInAppMessageInternal inAppMessage = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_saved", OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - String firstID = inAppMessage.getMessageId() + "_test"; - inAppMessage.setMessageId(firstID); - inAppMessage.getRedisplayStats().setLastDisplayTime(currentTimeInSeconds - SIX_MONTHS_TIME_SECONDS + 1); - TestHelpers.saveIAM(inAppMessage, dbHelper); - - inAppMessage.getRedisplayStats().setLastDisplayTime(currentTimeInSeconds - SIX_MONTHS_TIME_SECONDS - 1); - inAppMessage.setMessageId(inAppMessage.getMessageId() + "1"); - TestHelpers.saveIAM(inAppMessage, dbHelper); - - List savedInAppMessages = TestHelpers.getAllInAppMessages(dbHelper); - - assertEquals(2, savedInAppMessages.size()); - - final OSTestInAppMessageInternal message1 = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - final OSTestInAppMessageInternal message2 = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_2", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message1); - add(message2); - }}); - - // Init OneSignal with IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - List savedInAppMessagesAfterInit = TestHelpers.getAllInAppMessages(dbHelper); - // Message with old display time should be removed - assertEquals(1, savedInAppMessagesAfterInit.size()); - assertEquals(firstID, savedInAppMessagesAfterInit.get(0).getMessageId()); - } - - @Test - @Config(sdk = 18) - public void testMessageNotShownForAndroidApi18Lower() throws Exception { - initializeSdkWithMultiplePendingMessages(); - - // Send a new IAM - OneSignal.addTriggers(new HashMap() {{ - put("test_1", 3); - }}); - threadAndTaskWait(); - - // Check no messages exist - assertEquals(0, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - } - - @Test - public void testInAppMessageIdTracked() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // For mocking behaviour - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - // Init OneSignal IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Check no influence id saved - JSONArray lastReceivedIds = trackerFactory.getIAMChannelTracker().getLastReceivedIds(); - assertEquals(0, lastReceivedIds.length()); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - - // Check influence id saved - lastReceivedIds = trackerFactory.getIAMChannelTracker().getLastReceivedIds(); - assertEquals(1, lastReceivedIds.length()); - } - - @Test - public void testLiquidIAMDisplayWaitsForGetTags() throws Exception { - final OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndLiquid( - OSTriggerKind.CUSTOM, "test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2); - - setMockRegistrationResponseWithMessages(new ArrayList() {{ - add(message); - }}); - - // Init OneSignal IAM with redisplay - OneSignalInit(); - threadAndTaskWait(); - - // Add trigger to make IAM display - OneSignal.addTrigger("test_1", 2); - assertEquals(1, OneSignalPackagePrivateHelper.getInAppMessageDisplayQueue().size()); - // Wait for both getTags and get IAM HTML to be called - Awaitility.await() - .atMost(new Duration(150, TimeUnit.MILLISECONDS)) - .pollInterval(new Duration(10, TimeUnit.MILLISECONDS)) - .until(() -> ShadowOneSignalRestClient.requests.size() == 4); - int requestSize = ShadowOneSignalRestClient.requests.size(); - ShadowOneSignalRestClient.Request getTagsRequest = ShadowOneSignalRestClient.requests.get(requestSize - 1); - assertEquals("players/" + "df8f05be55ba-b2f7f966-d8cc-11e4-bed1" + "?app_id=" + "b2f7f966-d8cc-11e4-bed1-df8f05be55ba", getTagsRequest.url); - // Runnable for get tags is run - threadAndTaskWait(); - // Runnable for webView is run from background thread to main thread - threadAndTaskWait(); - ShadowOneSignalRestClient.Request lastRequest = ShadowOneSignalRestClient.requests.get(ShadowOneSignalRestClient.requests.size() - 1); - while (!lastRequest.url.equals("in_app_messages/" + message.getMessageId() + "/impression")) { - // Check impression request by waiting until animationEnd - threadAndTaskWait(); - lastRequest = ShadowOneSignalRestClient.requests.get(ShadowOneSignalRestClient.requests.size() - 1); - } - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", lastRequest.url); - } - - // Test toJSONObject() method currently only checks JSON for "messageId" - @Test - public void testInAppMessageInternalToJSONObject_messageId() throws Exception { - // 1. Create a basic test IAM - OSTestInAppMessageInternal iam = InAppMessagingHelpers.buildTestMessage(null); - - // 2. Set a message ID for the IAM - String messageId = new String(new char[64]).replace('\0', '0'); - iam.setMessageId(messageId); - - // 3. Init - OneSignalInit(); - threadAndTaskWait(); - - // 4. call toJSONObject() on IAM - JSONObject testJsonObj = iam.toJSONObject(); - - // 5. Check "messageId" in JSON Object - assertEquals(messageId, testJsonObj.optString("messageId")); - } - - private void setMockRegistrationResponseWithMessages(ArrayList messages) throws JSONException { - final JSONArray jsonMessages = new JSONArray(); - - for (OSTestInAppMessageInternal message : messages) - jsonMessages.put(InAppMessagingHelpers.convertIAMtoJSONObject(message)); - - ShadowOneSignalRestClient.setNextSuccessfulRegistrationResponse(new JSONObject() {{ - put("id", "df8f05be55ba-b2f7f966-d8cc-11e4-bed1"); - put("success", 1); - put(OneSignalPackagePrivateHelper.IN_APP_MESSAGES_JSON_KEY, jsonMessages); - }}); - } - - private void OneSignalInit() { - OneSignal_setTime(time); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.DEBUG, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - blankActivityController.resume(); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessagingUnitTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessagingUnitTests.java deleted file mode 100644 index 187766eec..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessagingUnitTests.java +++ /dev/null @@ -1,689 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; - -import androidx.annotation.Nullable; - -import com.onesignal.InAppMessagingHelpers; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.OSInAppMessageLifecycleHandler; -import com.onesignal.OSInAppMessage; -import com.onesignal.OSInAppMessageAction; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestInAppMessageInternal; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestInAppMessageAction; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowDynamicTimer; -import com.onesignal.ShadowJobService; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerKind; -import static com.onesignal.OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerOperator; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.test.onesignal.TestHelpers.assertMainThread; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowPushRegistratorFCM.class, - ShadowOSUtils.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowNotificationManagerCompat.class, - ShadowJobService.class, - ShadowDynamicTimer.class, - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class InAppMessagingUnitTests { - - private static final String IAM_CLICK_ID = "button_id_123"; - private static final double REQUIRED_TIMER_ACCURACY = 1.25; - private static final int LIMIT = 5; - private static final long DELAY = 60; - - private static OSTestInAppMessageInternal message; - - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - - @BeforeClass - public static void setupClass() throws Exception { - ShadowLog.stream = System.out; - - message = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO.toString(), - 3 - ); - - TestHelpers.beforeTestSuite(); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - lastAction = null; - lastMessage = null; - iamLifecycleCounter = 0; - - TestHelpers.beforeTestInitAndCleanup(); - - OneSignalInit(); - } - - @After - public void afterEachTest() throws Exception { - // reset back to the default - ShadowDynamicTimer.shouldScheduleTimers = true; - ShadowDynamicTimer.hasScheduledTimer = false; - TestHelpers.afterTestCleanup(); - - InAppMessagingHelpers.clearTestState(); - } - - private static void setLocalTriggerValue(String key, Object localValue) { - if (localValue != null) - OneSignal.addTrigger(key, localValue); - else - OneSignal.removeTriggerForKey(key); - } - - /** - * Convenience function that saves a local trigger (localValue) for the property name "test_property" - * then creates an in-app message with a trigger (triggerValue) for the same property name. It - * then evaluates the message for the given trigger conditions and returns the boolean, which - * indicates whether or not the message should be shown. - * - * For example, we can set up a test where the app has a property value of 3 and we want to - * test to make sure that if a message has a trigger value of 2 and an operator > that it - * returns true when evaluated, because 3 > 2 - */ - private static boolean comparativeOperatorTest(OSTriggerOperator operator, Object triggerValue, Object localValue) throws JSONException { - setLocalTriggerValue("test_property", localValue); - OSTestInAppMessageInternal testMessage = InAppMessagingHelpers.buildTestMessageWithSingleTrigger(OSTriggerKind.CUSTOM, "test_property", operator.toString(), triggerValue); - return InAppMessagingHelpers.evaluateMessage(testMessage); - } - - @Test - public void testBuiltMessage() { - UUID.fromString(message.getMessageId()); // Throws if invalid - assertNotNull(message.variants); - } - - @Test - public void testBuiltMessageVariants() { - assertEquals(message.variants.get("android").get("es"), InAppMessagingHelpers.TEST_SPANISH_ANDROID_VARIANT_ID); - assertEquals(message.variants.get("android").get("en"), InAppMessagingHelpers.TEST_ENGLISH_ANDROID_VARIANT_ID); - } - - @Test - public void testBuiltMessageReDisplay() throws JSONException { - OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWitRedisplay( - LIMIT, - DELAY - ); - assertTrue(message.getRedisplayStats().isRedisplayEnabled()); - assertEquals(LIMIT, message.getRedisplayStats().getDisplayLimit()); - assertEquals(DELAY, message.getRedisplayStats().getDisplayDelay()); - assertEquals(-1, message.getRedisplayStats().getLastDisplayTime()); - assertEquals(0, message.getRedisplayStats().getDisplayQuantity()); - - OSTestInAppMessageInternal messageWithoutDisplay = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO.toString(), - 3 - ); - assertFalse(messageWithoutDisplay.getRedisplayStats().isRedisplayEnabled()); - assertEquals(1, messageWithoutDisplay.getRedisplayStats().getDisplayLimit()); - assertEquals(0, messageWithoutDisplay.getRedisplayStats().getDisplayDelay()); - assertEquals(-1, messageWithoutDisplay.getRedisplayStats().getLastDisplayTime()); - assertEquals(0, messageWithoutDisplay.getRedisplayStats().getDisplayQuantity()); - } - - @Test - public void testBuiltMessageRedisplayLimit() throws JSONException { - OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWitRedisplay( - LIMIT, - DELAY - ); - - for (int i = 0; i < LIMIT; i++) { - assertTrue(message.getRedisplayStats().shouldDisplayAgain()); - message.getRedisplayStats().incrementDisplayQuantity(); - } - - message.getRedisplayStats().incrementDisplayQuantity(); - assertFalse(message.getRedisplayStats().shouldDisplayAgain()); - } - - @Test - public void testBuiltMessageRedisplayDelay() throws JSONException { - MockOSTimeImpl time = new MockOSTimeImpl(); - OneSignal_setTime(time); - OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWitRedisplay( - LIMIT, - DELAY - ); - - assertTrue(message.getRedisplayStats().isDelayTimeSatisfied()); - - message.getRedisplayStats().setLastDisplayTimeToCurrent(time); - time.advanceSystemTimeBy(DELAY); - assertTrue(message.getRedisplayStats().isDelayTimeSatisfied()); - - message.getRedisplayStats().setLastDisplayTimeToCurrent(time); - time.advanceSystemTimeBy(DELAY - 1); - assertFalse(message.getRedisplayStats().isDelayTimeSatisfied()); - } - - @Test - public void testBuiltMessageRedisplayCLickId() throws JSONException { - OSTestInAppMessageInternal message = InAppMessagingHelpers.buildTestMessageWitRedisplay( - LIMIT, - DELAY - ); - - assertTrue(message.getClickedClickIds().isEmpty()); - assertTrue(message.isClickAvailable(IAM_CLICK_ID)); - - message.addClickId(IAM_CLICK_ID); - message.clearClickIds(); - - assertTrue(message.getClickedClickIds().isEmpty()); - - message.addClickId(IAM_CLICK_ID); - message.addClickId(IAM_CLICK_ID); - assertEquals(1, message.getClickedClickIds().size()); - - assertFalse(message.isClickAvailable(IAM_CLICK_ID)); - - OSTestInAppMessageInternal messageWithoutDisplay = InAppMessagingHelpers.buildTestMessageWithSingleTrigger( - OSTriggerKind.SESSION_TIME, - null, - OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO.toString(), - 3 - ); - - messageWithoutDisplay.addClickId(IAM_CLICK_ID); - assertFalse(messageWithoutDisplay.isClickAvailable(IAM_CLICK_ID)); - } - - @Test - public void testBuiltMessageTrigger() { - OSTestTrigger trigger = (OSTestTrigger)message.triggers.get(0).get(0); - - assertEquals(trigger.kind, OSTriggerKind.SESSION_TIME); - assertEquals(trigger.operatorType, OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO); - assertNull(trigger.property); - assertEquals(trigger.value, 3); - } - - @Test - public void testParsesMessageActions() throws JSONException { - OSTestInAppMessageAction action = new OSTestInAppMessageAction(InAppMessagingHelpers.buildTestActionJson()); - - assertEquals(action.getClickId(), InAppMessagingHelpers.IAM_CLICK_ID); - assertEquals(action.getClickName(), "click_name"); - assertEquals(action.getClickUrl(), "https://www.onesignal.com"); - assertTrue(action.closes()); - assertEquals(action.getUrlTarget(), OSInAppMessageAction.OSInAppMessageActionUrlType.IN_APP_WEBVIEW); - } - - @Test - public void testSaveMultipleTriggerValuesGetTrigger() throws Exception { - HashMap testTriggers = new HashMap<>(); - testTriggers.put("test1", "value1"); - testTriggers.put("test2", "value2"); - - OneSignal.addTriggers(testTriggers); - - Map triggers = OneSignal.getTriggers(); - assertEquals(2, triggers.entrySet().size()); - - for (Map.Entry entry : triggers.entrySet()) { - assertEquals(testTriggers.get(entry.getKey()), entry.getValue()); - } - } - - @Test - public void testSaveMultipleTriggerValues() { - HashMap testTriggers = new HashMap<>(); - testTriggers.put("test1", "value1"); - testTriggers.put("test2", "value2"); - - OneSignal.addTriggers(testTriggers); - - assertEquals(OneSignal.getTriggerValueForKey("test1"), "value1"); - assertEquals(OneSignal.getTriggerValueForKey("test2"), "value2"); - } - - @Test - public void testAddTriggersFromJsonString_StringsTest() throws Exception { - JSONObject jsonObject = new JSONObject() {{ - put("key1", "value1"); - put("key2", "value2"); - }}; - - addTriggersFromJsonString(jsonObject.toString()); - - assertEquals(OneSignal.getTriggerValueForKey("key1"), "value1"); - assertEquals(OneSignal.getTriggerValueForKey("key2"), "value2"); - } - - @Test - public void testAddTriggersFromJsonString_NullValue() throws Exception { - JSONObject jsonObject = new JSONObject() {{ - put("key", null); - }}; - - addTriggersFromJsonString(jsonObject.toString()); - - assertNull(OneSignal.getTriggerValueForKey("key")); - } - - @Test - public void testAddTriggersFromJsonString_IntTest() throws Exception { - JSONObject jsonObject = new JSONObject() {{ - put("key", 1); - }}; - - addTriggersFromJsonString(jsonObject.toString()); - - assertEquals(1, OneSignal.getTriggerValueForKey("key")); - } - - @Test - public void testAddTriggersFromJsonString_NestedJSONArray() throws Exception { - JSONObject jsonObject = new JSONObject() {{ - put("key", new JSONArray() {{ - put("value"); - }}); - }}; - - addTriggersFromJsonString(jsonObject.toString()); - - assertEquals( - new ArrayList() {{ - add("value"); - }}, - OneSignal.getTriggerValueForKey("key") - ); - } - - @Test - public void testAddTriggersFromJsonString_NestedJSONObject() throws Exception { - JSONObject jsonObject = new JSONObject() {{ - put("key", new JSONObject() {{ - put("nestedKey", "value"); - }}); - }}; - - addTriggersFromJsonString(jsonObject.toString()); - - assertEquals( - new HashMap() {{ - put("nestedKey", "value"); - }}, - OneSignal.getTriggerValueForKey("key") - ); - } - - public static void addTriggersFromJsonString(String triggersJsonString) throws JSONException { - JSONObject jsonObject = new JSONObject(triggersJsonString); - OneSignal.addTriggers(OneSignalPackagePrivateHelper.JSONUtils.jsonObjectToMap(jsonObject)); - } - - @Test - public void testDeleteSavedTriggerValueGetTriggers() { - OneSignal.addTrigger("test1", "value1"); - assertEquals(OneSignal.getTriggerValueForKey("test1"), "value1"); - - OneSignal.removeTriggerForKey("test1"); - assertNull(OneSignal.getTriggers().get("test1")); - } - - @Test - public void testDeleteSavedTriggerValue() { - OneSignal.addTrigger("test1", "value1"); - assertEquals(OneSignal.getTriggerValueForKey("test1"), "value1"); - - OneSignal.removeTriggerForKey("test1"); - assertNull(OneSignal.getTriggerValueForKey("test1")); - } - - @Test - public void testRemoveTriggersForKeysFromArray_SingleKey() { - OneSignal.addTrigger("key", "value"); - - List triggersToRemove = new ArrayList<>(); - triggersToRemove.add("key"); - OneSignal.removeTriggersForKeys(triggersToRemove); - - assertNull(OneSignal.getTriggerValueForKey("key")); - } - - @Test - public void testGreaterThanOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.GREATER_THAN, 1, 2)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.GREATER_THAN, 5, 3)); - } - - @Test - public void testGreaterThanOperatorWithString() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.GREATER_THAN, 1, "2")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.GREATER_THAN, 5, "3")); - } - - @Test - public void testGreaterThanOrEqualToOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO, 2, 2.9)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO, 4, 3)); - } - - @Test - public void testLessThanOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 32, 2)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, 3)); - } - - @Test - public void testLessThanOperatorWithInvalidStrings() throws JSONException { - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, "")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, "a1")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, "a")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, "0x01")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, null)); - } - - @Test - public void testLessThanOperatorWithString() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 32, "2")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN, 2, "3")); - } - - @Test - public void testLessThanOrEqualToOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.LESS_THAN_OR_EQUAL_TO, 5, 4)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.LESS_THAN_OR_EQUAL_TO, 3, 4)); - } - - @Test - public void testEqualityOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, 0.1, 0.1)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, 0.0, 2)); - // Test mixed Number types (Integer & Double) - assertTrue(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, 1, 1.0)); - assertTrue(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, 1.0, 1)); - } - - @Test - public void testEqualityOperatorWithStrings() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, "a", "a")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, "a", "b")); - } - - @Test - public void testEqualityOperatorWithTriggerStringAndValueNumber() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, "1", 1)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.EQUAL_TO, "2", 1)); - } - - @Test - public void testNotEqualOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.NOT_EQUAL_TO, 3, 3.01)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.NOT_EQUAL_TO, 3.1, 3.1)); - } - - @Test - public void testContainsOperator() throws JSONException { - ArrayList localValue = new ArrayList() {{ - add("test string 1"); - }}; - - assertTrue(comparativeOperatorTest(OSTriggerOperator.CONTAINS, "test string 1", localValue)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.CONTAINS, "test string 2", localValue)); - } - - @Test - public void testExistsOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.EXISTS, null, "test")); - assertFalse(comparativeOperatorTest(OSTriggerOperator.EXISTS, null, null)); - } - - @Test - public void testNotExistsOperator() throws JSONException { - assertTrue(comparativeOperatorTest(OSTriggerOperator.NOT_EXISTS, null, null)); - assertFalse(comparativeOperatorTest(OSTriggerOperator.NOT_EXISTS, null, "test")); - } - - @Test - public void testMessageSchedulesSessionDurationTimer() throws JSONException { - OSTestTrigger trigger = InAppMessagingHelpers.buildTrigger(OSTriggerKind.SESSION_TIME, null, OSTriggerOperator.EQUAL_TO.toString(), 10); - - InAppMessagingHelpers.resetSessionLaunchTime(); - - // this evaluates the message and should schedule a timer for 10 seconds into the session - assertFalse(InAppMessagingHelpers.dynamicTriggerShouldFire(trigger)); - // verify that the timer was scheduled ~10 seconds - assertTrue(roughlyEqualTimerValues(10.0, ShadowDynamicTimer.mostRecentTimerDelaySeconds())); - } - - // This test makes sure that time-based triggers are considered once all non-time-based - // triggers evaluate to true and will set up a timer if needed - @Test - public void testMixedTriggersScheduleTimer() throws JSONException { - final OSTestTrigger timeBasedTrigger = InAppMessagingHelpers.buildTrigger(OSTriggerKind.SESSION_TIME, null, OSTriggerOperator.GREATER_THAN.toString(), 5.0); - final OSTestTrigger normalTrigger = InAppMessagingHelpers.buildTrigger(OSTriggerKind.CUSTOM, "prop1", OSTriggerOperator.LESS_THAN_OR_EQUAL_TO.toString(), 3); - - // the time based trigger will be false (but should schedule a timer) - // while the normal trigger should evaluate to true - setLocalTriggerValue("prop1", 3); - - ArrayList> triggers = new ArrayList>() {{ - add(new ArrayList() {{ - add(timeBasedTrigger); - add(normalTrigger); - }}); - }}; - - OSTestInAppMessageInternal testMessage = InAppMessagingHelpers.buildTestMessageWithMultipleTriggers(triggers); - assertFalse(InAppMessagingHelpers.evaluateMessage(testMessage)); - assertTrue(ShadowDynamicTimer.hasScheduledTimer); - assertTrue(roughlyEqualTimerValues(5.0, ShadowDynamicTimer.mostRecentTimerDelaySeconds())); - } - - @Test - public void testShouldTriggerWhen1OutOf3OrsAreMeet() throws JSONException { - setLocalTriggerValue("prop1", 3); - - ArrayList> triggers = new ArrayList>() {{ - add(new ArrayList() {{ - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.CUSTOM,"prop1", OSTriggerOperator.EQUAL_TO.toString(), 1)); - }}); - add(new ArrayList() {{ - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.CUSTOM,"prop1", OSTriggerOperator.EQUAL_TO.toString(), 2)); - }}); - add(new ArrayList() {{ - add(InAppMessagingHelpers.buildTrigger(OSTriggerKind.CUSTOM,"prop1", OSTriggerOperator.EQUAL_TO.toString(), 3)); - }}); - }}; - - OSTestInAppMessageInternal testMessage = InAppMessagingHelpers.buildTestMessageWithMultipleTriggers(triggers); - assertTrue(InAppMessagingHelpers.evaluateMessage(testMessage)); - } - - private boolean roughlyEqualTimerValues(double desired, double actual) { - return Math.abs(desired - actual) < REQUIRED_TIMER_ACCURACY; - } - - private void OneSignalInit() { - setRemoteParamsGetHtmlResponse(); - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - OneSignal.setAppId(InAppMessagingHelpers.ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - blankActivityController.resume(); - } - - private static @Nullable OSInAppMessageAction lastAction; - @Test - public void testOnMessageActionOccurredOnMessage() throws Exception { - OneSignal.setInAppMessageClickHandler(new OneSignal.OSInAppMessageClickHandler() { - @Override - public void inAppMessageClicked(OSInAppMessageAction result) { - lastAction = result; - // Ensure we are on the main thread when running the callback, since the app developer - // will most likely need to update UI. - assertMainThread(); - } - }); - threadAndTaskWait(); - - OneSignalPackagePrivateHelper.onMessageActionOccurredOnMessage(message, - new JSONObject() {{ - put("id", "button_id_123"); - put("name", "my_click_name"); - }} - ); - - // Ensure we make REST call to OneSignal to report click. - ShadowOneSignalRestClient.Request iamClickRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals("in_app_messages/" + message.getMessageId() + "/click", iamClickRequest.url); - assertEquals(InAppMessagingHelpers.ONESIGNAL_APP_ID, iamClickRequest.payload.get("app_id")); - assertEquals(1, iamClickRequest.payload.get("device_type")); - assertEquals(message.variants.get("android").get("en"), iamClickRequest.payload.get("variant_id")); - assertEquals(ShadowOneSignalRestClient.pushUserId, iamClickRequest.payload.get("player_id")); - assertEquals(true, iamClickRequest.payload.get("first_click")); - assertEquals("button_id_123", iamClickRequest.payload.get("click_id")); - - // Ensure we fire public callback that In-App was clicked. - assertEquals(lastAction.getClickName(), "my_click_name"); - } - - @Test - public void testOnMessageWasShown() throws Exception { - threadAndTaskWait(); - - OneSignalPackagePrivateHelper.onMessageWasShown(message); - - ShadowOneSignalRestClient.Request iamImpressionRequest = ShadowOneSignalRestClient.requests.get(2); - - assertEquals("in_app_messages/" + message.getMessageId() + "/impression", iamImpressionRequest.url); - assertEquals(InAppMessagingHelpers.ONESIGNAL_APP_ID, iamImpressionRequest.payload.get("app_id")); - assertEquals(ShadowOneSignalRestClient.pushUserId, iamImpressionRequest.payload.get("player_id")); - assertEquals(1, iamImpressionRequest.payload.get("device_type")); - assertEquals(true, iamImpressionRequest.payload.get("first_impression")); - } - - @Test - public void testOnPageChanged() throws Exception { - threadAndTaskWait(); - - OneSignalPackagePrivateHelper.onPageChanged(message, InAppMessagingHelpers.buildTestPageJson()); - - ShadowOneSignalRestClient.Request iamPageImpressionRequest = ShadowOneSignalRestClient.requests.get(2); - - assertEquals("in_app_messages/" + message.getMessageId() + "/pageImpression", iamPageImpressionRequest.url); - assertEquals(InAppMessagingHelpers.ONESIGNAL_APP_ID, iamPageImpressionRequest.payload.get("app_id")); - assertEquals(ShadowOneSignalRestClient.pushUserId, iamPageImpressionRequest.payload.get("player_id")); - assertEquals(1, iamPageImpressionRequest.payload.get("device_type")); - assertEquals(InAppMessagingHelpers.IAM_PAGE_ID, iamPageImpressionRequest.payload.get("page_id")); - } - - /* Tests for IAM Lifecycle */ - - private static @Nullable OSInAppMessage lastMessage; - private static int iamLifecycleCounter; - @Test - public void testIAMLifecycleEventsFlow() throws Exception { - OneSignal.setInAppMessageLifecycleHandler(new OSInAppMessageLifecycleHandler() { - @Override - public void onWillDisplayInAppMessage(OSInAppMessage message) { - lastMessage = message; - iamLifecycleCounter++; - } - - @Override - public void onDidDisplayInAppMessage(OSInAppMessage message) { - lastMessage = message; - iamLifecycleCounter++; - } - - @Override - public void onWillDismissInAppMessage(OSInAppMessage message) { - lastMessage = message; - iamLifecycleCounter++; - } - - @Override - public void onDidDismissInAppMessage(OSInAppMessage message) { - lastMessage = message; - iamLifecycleCounter++; - } - }); - threadAndTaskWait(); - - assertEquals(0, iamLifecycleCounter); - // maybe need threadAndTaskWait - OneSignalPackagePrivateHelper.onMessageWillDisplay(message); - assertEquals(1, iamLifecycleCounter); - - OneSignalPackagePrivateHelper.onMessageDidDisplay(message); - assertEquals(2,iamLifecycleCounter); - - OneSignalPackagePrivateHelper.onMessageWillDismiss(message); - assertEquals(3,iamLifecycleCounter); - - OneSignalPackagePrivateHelper.onMessageDidDismiss(message); - assertEquals(4,iamLifecycleCounter); - - assertNotNull(lastMessage); - assertEquals(lastMessage.getMessageId(), message.getMessageId()); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/JsonAsserts.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/JsonAsserts.java deleted file mode 100644 index eccecf054..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/JsonAsserts.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.test.onesignal; - -import androidx.annotation.NonNull; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Iterator; -import java.util.List; - -import static com.onesignal.OneSignalPackagePrivateHelper.JSONUtils.normalizeType; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -class JsonAsserts { - - static void doesNotContainKeys(@NonNull JSONObject subject, @NonNull List keys) { - for(String key : keys) - assertFalse(subject.has(key)); - } - - // Assert that the "subject" has all the keys with the same values from the "contains". - static void containsSubset(@NonNull JSONObject subject, @NonNull JSONObject contains) throws JSONException { - Iterator iterator = contains.keys(); - while (iterator.hasNext()) { - String key = iterator.next(); - if (contains.get(key) instanceof JSONObject && subject.get(key) instanceof JSONObject) - equals(contains.getJSONObject(key), subject.getJSONObject(key)); - else - assertEquals( - normalizeType(contains.get(key)), - normalizeType(subject.get(key)) - ); - } - } - - static void equals(@NonNull JSONObject expected, @NonNull JSONObject actual) throws JSONException { - assertEquals(expected.length(), actual.length()); - containsSubset(actual, expected); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/LocationIntegrationTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/LocationIntegrationTests.java deleted file mode 100644 index c108cae4f..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/LocationIntegrationTests.java +++ /dev/null @@ -1,604 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.AlarmManager; -import android.content.Context; -import android.content.Intent; -import android.location.Location; - -import androidx.test.core.app.ApplicationProvider; - -import com.huawei.hms.location.HWLocation; -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockSessionManager; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowFocusHandler; -import com.onesignal.ShadowFusedLocationApiWrapper; -import com.onesignal.ShadowGMSLocationController; -import com.onesignal.ShadowGMSLocationUpdateListener; -import com.onesignal.ShadowGoogleApiClientBuilder; -import com.onesignal.ShadowGoogleApiClientCompatProxy; -import com.onesignal.ShadowHMSFusedLocationProviderClient; -import com.onesignal.ShadowHMSLocationUpdateListener; -import com.onesignal.ShadowHmsInstanceId; -import com.onesignal.ShadowHuaweiTask; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignal; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.StaticResetHelper; -import com.onesignal.SyncJobService; -import com.onesignal.SyncService; -import com.onesignal.example.BlankActivity; -import com.onesignal.influence.data.OSTrackerFactory; - -import org.json.JSONObject; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import java.lang.reflect.Method; - -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.TestHelpers.afterTestCleanup; -import static com.test.onesignal.TestHelpers.fastColdRestartApp; -import static com.test.onesignal.TestHelpers.restartAppAndElapseTimeToNextSession; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNull; -import static org.robolectric.Shadows.shadowOf; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowPushRegistratorFCM.class, - ShadowOSUtils.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowHmsInstanceId.class, - ShadowFocusHandler.class - }, - sdk = 21 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class LocationIntegrationTests { - - private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba"; - - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - - private MockOSTimeImpl time; - private OSTrackerFactory trackerFactory; - private MockSessionManager sessionManager; - private MockOneSignalDBHelper dbHelper; - - private static void cleanUp() throws Exception { - ShadowGMSLocationController.reset(); - - TestHelpers.beforeTestInitAndCleanup(); - - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - } - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - -// Field OneSignal_CurrentSubscription = OneSignal.class.getDeclaredField("subscribableStatus"); -// OneSignal_CurrentSubscription.setAccessible(true); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - - time = new MockOSTimeImpl(); - trackerFactory = new OSTrackerFactory(new MockOSSharedPreferences(), new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - - TestHelpers.setupTestWorkManager(blankActivity); - - cleanUp(); - - OneSignal_setTime(time); - } - - @After - public void afterEachTest() throws Exception { - afterTestCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - cleanUp(); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void shouldUpdateAllLocationFieldsWhenTimeStampChanges() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - OneSignalInit(); - threadAndTaskWait(); - assertEquals(1.0, ShadowOneSignalRestClient.lastPost.getDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long")); - assertEquals(3.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc")); - assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type")); - - ShadowOneSignalRestClient.lastPost = null; - ShadowFusedLocationApiWrapper.lat = 30d; - ShadowFusedLocationApiWrapper.log = 2.0d; - ShadowFusedLocationApiWrapper.accuracy = 5.0f; - ShadowFusedLocationApiWrapper.time = 2L; - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(30.0, ShadowOneSignalRestClient.lastPost.getDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long")); - assertEquals(5.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc")); - assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type")); - } - - @Test - @Config(shadows = {ShadowOneSignal.class}) - @SuppressWarnings("unchecked") // getDeclaredMethod - public void testLocationTimeout() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - Class klass = Class.forName("com.onesignal.GMSLocationController"); - Method method = klass.getDeclaredMethod("startFallBackThread"); - method.setAccessible(true); - method.invoke(null); - method = klass.getDeclaredMethod("fireFailedComplete"); - method.setAccessible(true); - method.invoke(null); - threadAndTaskWait(); - - assertFalse(ShadowOneSignal.messages.contains("GoogleApiClient timeout")); - } - - @Test - @Config(shadows = { - ShadowGoogleApiClientBuilder.class, - ShadowGoogleApiClientCompatProxy.class, - ShadowFusedLocationApiWrapper.class }, - sdk = 19) - public void testLocationSchedule() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_FINE_LOCATION"); - ShadowFusedLocationApiWrapper.lat = 1.0d; - ShadowFusedLocationApiWrapper.log = 2.0d; - ShadowFusedLocationApiWrapper.accuracy = 3.0f; - ShadowFusedLocationApiWrapper.time = 12345L; - - // location if we have permission - OneSignalInit(); - threadAndTaskWait(); - assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc")); - assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type")); - - // Checking make sure an update is scheduled. - AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size()); - Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent(); - assertEquals(SyncService.class, shadowOf(intent).getIntentClass()); - - // Setting up a new point and testing it is sent - Location fakeLocation = new Location("UnitTest"); - fakeLocation.setLatitude(1.1d); - fakeLocation.setLongitude(2.2d); - fakeLocation.setAccuracy(3.3f); - fakeLocation.setTime(12346L); - ShadowGMSLocationUpdateListener.provideFakeLocation(fakeLocation); - - Robolectric.buildService(SyncService.class, intent).startCommand(0, 0); - threadAndTaskWait(); - assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc")); - - assertEquals(false, ShadowOneSignalRestClient.lastPost.opt("loc_bg")); - - // Testing loc_bg - blankActivityController.pause(); - threadAndTaskWait(); - fakeLocation.setTime(12347L); - ShadowGMSLocationUpdateListener.provideFakeLocation(fakeLocation); - Robolectric.buildService(SyncService.class, intent).startCommand(0, 0); - threadAndTaskWait(); - assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc")); - assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg")); - assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type")); - } - - @Test - @Config(shadows = { - ShadowGoogleApiClientBuilder.class, - ShadowGoogleApiClientCompatProxy.class, - ShadowFusedLocationApiWrapper.class }, - sdk = 19) - public void testLocationFromSyncAlarm() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - ShadowFusedLocationApiWrapper.lat = 1.1d; - ShadowFusedLocationApiWrapper.log = 2.1d; - ShadowFusedLocationApiWrapper.accuracy = 3.1f; - ShadowFusedLocationApiWrapper.time = 12346L; - - OneSignalInit(); - threadAndTaskWait(); - - fastColdRestartApp(); - AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - shadowOf(alarmManager).getScheduledAlarms().clear(); - ShadowOneSignalRestClient.lastPost = null; - - ShadowFusedLocationApiWrapper.lat = 1.0; - ShadowFusedLocationApiWrapper.log = 2.0d; - ShadowFusedLocationApiWrapper.accuracy = 3.0f; - ShadowFusedLocationApiWrapper.time = 12345L; - - blankActivityController.pause(); - threadAndTaskWait(); - - Robolectric.buildService(SyncService.class, new Intent()).startCommand(0, 0); - threadAndTaskWait(); - - assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc")); - assertEquals(0, ShadowOneSignalRestClient.lastPost.optInt("loc_type")); - assertEquals(12345L, ShadowOneSignalRestClient.lastPost.optInt("loc_time_stamp")); - assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg")); - - // Checking make sure an update is scheduled. - alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size()); - Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent(); - assertEquals(SyncService.class, shadowOf(intent).getIntentClass()); - shadowOf(alarmManager).getScheduledAlarms().clear(); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void shouldSendLocationToEmailRecord() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(11, postEmailPayload.getInt("device_type")); - assertEquals(1.0, postEmailPayload.getDouble("lat")); - assertEquals(2.0, postEmailPayload.getDouble("long")); - assertEquals(3.0, postEmailPayload.getDouble("loc_acc")); - assertEquals(0.0, postEmailPayload.getDouble("loc_type")); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void shouldSendLocationToSMSRecord() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - OneSignalInit(); - OneSignal.setSMSNumber("123456789"); - threadAndTaskWait(); - - JSONObject postSMSPayload = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, postSMSPayload.getInt("device_type")); - assertEquals(1.0, postSMSPayload.getDouble("lat")); - assertEquals(2.0, postSMSPayload.getDouble("long")); - assertEquals(3.0, postSMSPayload.getDouble("loc_acc")); - assertEquals(0.0, postSMSPayload.getDouble("loc_type")); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void shouldRegisterWhenPromptingAfterInit() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - ShadowGoogleApiClientCompatProxy.skipOnConnected = true; - - // Test promptLocation right after init race condition - OneSignalInit(); - OneSignal.promptLocation(); - - ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(1); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method); - assertEquals(1, request.payload.get("device_type")); - assertEquals(ShadowPushRegistratorFCM.regId, request.payload.get("identifier")); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void shouldCallOnSessionEvenIfSyncJobStarted() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - OneSignalInit(); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - ShadowGoogleApiClientCompatProxy.skipOnConnected = true; - OneSignalInit(); - - SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get(); - syncJobService.onStartJob(null); - TestHelpers.getThreadByName("OS_SYNCSRV_BG_SYNC").join(); - OneSignalPackagePrivateHelper.runAllNetworkRunnables(); - ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_session", request.url); - } - - // ####### Unit Test Huawei Location ######## - - @Test - @Config(shadows = {ShadowHMSFusedLocationProviderClient.class}) - public void shouldUpdateAllLocationFieldsWhenTimeStampChanges_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - OneSignalInit(); - threadAndTaskWait(); - assertEquals(1.0, ShadowOneSignalRestClient.lastPost.getDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long")); - assertEquals(3.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc")); - assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type")); - - ShadowOneSignalRestClient.lastPost = null; - ShadowHMSFusedLocationProviderClient.resetStatics(); - ShadowHMSFusedLocationProviderClient.lat = 30d; - ShadowHMSFusedLocationProviderClient.log = 2.0d; - ShadowHMSFusedLocationProviderClient.accuracy = 5.0f; - ShadowHMSFusedLocationProviderClient.time = 2L; - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(30.0, ShadowOneSignalRestClient.lastPost.getDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long")); - assertEquals(5.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc")); - assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type")); - } - - @Test - @Config(shadows = { - ShadowHMSFusedLocationProviderClient.class - }, sdk = 19) - public void testLocationSchedule_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_FINE_LOCATION"); - ShadowHMSFusedLocationProviderClient.lat = 1.0d; - ShadowHMSFusedLocationProviderClient.log = 2.0d; - ShadowHMSFusedLocationProviderClient.accuracy = 3.0f; - ShadowHMSFusedLocationProviderClient.time = 12345L; - - // location if we have permission - OneSignalInit(); - threadAndTaskWait(); - assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc")); - assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type")); - - // Checking make sure an update is scheduled. - AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size()); - Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent(); - assertEquals(SyncService.class, shadowOf(intent).getIntentClass()); - - // Setting up a new point and testing it is sent - HWLocation fakeLocation = new HWLocation(); - fakeLocation.setLatitude(1.1d); - fakeLocation.setLongitude(2.2d); - fakeLocation.setAccuracy(3.3f); - fakeLocation.setTime(12346L); - ShadowHMSLocationUpdateListener.provideFakeLocation_Huawei(fakeLocation); - - Robolectric.buildService(SyncService.class, intent).startCommand(0, 0); - threadAndTaskWait(); - assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc")); - - assertEquals(false, ShadowOneSignalRestClient.lastPost.opt("loc_bg")); - - // Testing loc_bg - blankActivityController.pause(); - threadAndTaskWait(); - - fakeLocation.setTime(12347L); - ShadowHMSLocationUpdateListener.provideFakeLocation_Huawei(fakeLocation); - Robolectric.buildService(SyncService.class, intent).startCommand(0, 0); - threadAndTaskWait(); - assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc")); - assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg")); - assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type")); - } - - @Test - @Config(shadows = { - ShadowHMSFusedLocationProviderClient.class, - ShadowHuaweiTask.class - }, sdk = 19) - public void testLocationFromSyncAlarm_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - ShadowHMSFusedLocationProviderClient.lat = 1.1d; - ShadowHMSFusedLocationProviderClient.log = 2.1d; - ShadowHMSFusedLocationProviderClient.accuracy = 3.1f; - ShadowHMSFusedLocationProviderClient.time = 12346L; - - OneSignalInit(); - threadAndTaskWait(); - - fastColdRestartApp(); - AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - shadowOf(alarmManager).getScheduledAlarms().clear(); - - ShadowOneSignalRestClient.lastPost = null; - ShadowHMSFusedLocationProviderClient.resetStatics(); - ShadowHMSFusedLocationProviderClient.lat = 1.0; - ShadowHMSFusedLocationProviderClient.log = 2.0d; - ShadowHMSFusedLocationProviderClient.accuracy = 3.0f; - ShadowHMSFusedLocationProviderClient.time = 12345L; - ShadowHMSFusedLocationProviderClient.shadowTask = true; - ShadowHuaweiTask.result = ShadowHMSFusedLocationProviderClient.getLocation(); - - Robolectric.buildService(SyncService.class, new Intent()).startCommand(0, 0); - threadAndTaskWait(); - - assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat")); - assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long")); - assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc")); - assertEquals(0, ShadowOneSignalRestClient.lastPost.optInt("loc_type")); - assertEquals(12345L, ShadowOneSignalRestClient.lastPost.optInt("loc_time_stamp")); - assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg")); - - // Checking make sure an update is scheduled. - alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size()); - Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent(); - assertEquals(SyncService.class, shadowOf(intent).getIntentClass()); - shadowOf(alarmManager).getScheduledAlarms().clear(); - } - - @Test - @Config(shadows = {ShadowHMSFusedLocationProviderClient.class}) - public void shouldSendLocationToEmailRecord_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(11, postEmailPayload.getInt("device_type")); - assertEquals(1.0, postEmailPayload.getDouble("lat")); - assertEquals(2.0, postEmailPayload.getDouble("long")); - assertEquals(3.0, postEmailPayload.getDouble("loc_acc")); - assertEquals(0.0, postEmailPayload.getDouble("loc_type")); - } - - @Test - @Config(shadows = {ShadowHMSFusedLocationProviderClient.class}) - public void shouldSendLocationToSMSRecord_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - OneSignalInit(); - OneSignal.setSMSNumber("123456789"); - threadAndTaskWait(); - - JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, postEmailPayload.getInt("device_type")); - assertEquals(1.0, postEmailPayload.getDouble("lat")); - assertEquals(2.0, postEmailPayload.getDouble("long")); - assertEquals(3.0, postEmailPayload.getDouble("loc_acc")); - assertEquals(0.0, postEmailPayload.getDouble("loc_type")); - } - - @Test - @Config(shadows = {ShadowHMSFusedLocationProviderClient.class, ShadowHuaweiTask.class}) - public void shouldRegisterWhenPromptingAfterInit_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - ShadowHMSFusedLocationProviderClient.skipOnGetLocation = true; - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - // Test promptLocation right after init race condition - OneSignalInit(); - OneSignal.promptLocation(); - - ShadowHuaweiTask.callSuccessListener(ShadowHMSFusedLocationProviderClient.getLocation()); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(1); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_HUAWEI, request.payload.get("device_type")); - assertEquals(ShadowHmsInstanceId.token, request.payload.get("identifier")); - } - - @Test - @Config(shadows = {ShadowHMSFusedLocationProviderClient.class, ShadowHuaweiTask.class}) - public void shouldCallOnSessionEvenIfSyncJobStarted_Huawei() throws Exception { - ShadowOSUtils.supportsHMS(true); - ShadowHMSFusedLocationProviderClient.shadowTask = true; - ShadowHuaweiTask.result = ShadowHMSFusedLocationProviderClient.getLocation(); - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_COARSE_LOCATION"); - - OneSignalInit(); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - ShadowHMSFusedLocationProviderClient.skipOnGetLocation = true; - OneSignalInit(); - - SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get(); - syncJobService.onStartJob(null); - TestHelpers.getThreadByName("OS_SYNCSRV_BG_SYNC").join(); - OneSignalPackagePrivateHelper.runAllNetworkRunnables(); - ShadowHuaweiTask.callSuccessListener(ShadowHMSFusedLocationProviderClient.getLocation()); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_session", request.url); - } - - private void OneSignalInit() { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - OneSignal_setTime(time); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - blankActivityController.resume(); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java deleted file mode 100644 index f84c9434b..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java +++ /dev/null @@ -1,4217 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2018 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.AlarmManager; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ActivityInfo; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.net.ConnectivityManager; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockSessionManager; -import com.onesignal.OSDeviceState; -import com.onesignal.OSEmailSubscriptionObserver; -import com.onesignal.OSEmailSubscriptionStateChanges; -import com.onesignal.OSNotification; -import com.onesignal.OSNotificationAction; -import com.onesignal.OSNotificationOpenedResult; -import com.onesignal.OSNotificationReceivedEvent; -import com.onesignal.OSPermissionObserver; -import com.onesignal.OSPermissionStateChanges; -import com.onesignal.OSSMSSubscriptionObserver; -import com.onesignal.OSSMSSubscriptionStateChanges; -import com.onesignal.OSSubscriptionObserver; -import com.onesignal.OSSubscriptionStateChanges; -import com.onesignal.OneSignal; -import com.onesignal.OneSignal.ChangeTagsUpdateHandler; -import com.onesignal.OneSignal.OSSetLanguageCompletionHandler; -import com.onesignal.OneSignal.OSLanguageError; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalShadowPackageManager; -import com.onesignal.PermissionsActivity; -import com.onesignal.ShadowBadgeCountUpdater; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowFirebaseAnalytics; -import com.onesignal.ShadowFocusHandler; -import com.onesignal.ShadowFusedLocationApiWrapper; -import com.onesignal.ShadowGMSLocationController; -import com.onesignal.ShadowGenerateNotification; -import com.onesignal.ShadowGoogleApiClientBuilder; -import com.onesignal.ShadowGoogleApiClientCompatProxy; -import com.onesignal.ShadowHmsInstanceId; -import com.onesignal.ShadowJobService; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignal; -import com.onesignal.ShadowOneSignalNotificationManager; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorADM; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.ShadowReceiveReceiptController; -import com.onesignal.ShadowRoboNotificationManager; -import com.onesignal.StaticResetHelper; -import com.onesignal.SyncJobService; -import com.onesignal.SyncService; -import com.onesignal.example.BlankActivity; -import com.onesignal.example.MainActivity; -import com.onesignal.influence.data.OSTrackerFactory; - -import org.awaitility.Awaitility; -import org.awaitility.Duration; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowAlarmManager; -import org.robolectric.shadows.ShadowConnectivityManager; -import org.robolectric.shadows.ShadowLog; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Pattern; - -import static com.onesignal.OneSignalPackagePrivateHelper.FCMBroadcastReceiver_processBundle; -import static com.onesignal.OneSignalPackagePrivateHelper.NotificationBundleProcessor_Process; -import static com.onesignal.OneSignalPackagePrivateHelper.NotificationOpenedProcessor_processFromContext; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_handleNotificationOpen; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_isInForeground; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_taskQueueWaitingForInit; -import static com.onesignal.OneSignalPackagePrivateHelper.OSObservable; -import static com.onesignal.OneSignalPackagePrivateHelper.toUnescapedEUIDString; -import static com.onesignal.ShadowOneSignalRestClient.EMAIL_USER_ID; -import static com.onesignal.ShadowOneSignalRestClient.PUSH_USER_ID; -import static com.onesignal.ShadowOneSignalRestClient.REST_METHOD; -import static com.onesignal.ShadowOneSignalRestClient.SMS_USER_ID; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.GenerateNotificationRunner.getBaseNotifBundle; -import static com.test.onesignal.RestClientAsserts.assertAmazonPlayerCreateAtIndex; -import static com.test.onesignal.RestClientAsserts.assertAndroidPlayerCreateAtIndex; -import static com.test.onesignal.RestClientAsserts.assertHuaweiPlayerCreateAtIndex; -import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndex; -import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndexDoesNotHaveKeys; -import static com.test.onesignal.RestClientAsserts.assertOnSessionAtIndex; -import static com.test.onesignal.RestClientAsserts.assertPlayerCreatePushAtIndex; -import static com.test.onesignal.RestClientAsserts.assertRemoteParamsAtIndex; -import static com.test.onesignal.RestClientAsserts.assertRestCalls; -import static com.test.onesignal.TestHelpers.afterTestCleanup; -import static com.test.onesignal.TestHelpers.assertAndRunSyncService; -import static com.test.onesignal.TestHelpers.assertNextJob; -import static com.test.onesignal.TestHelpers.assertNumberOfServicesAvailable; -import static com.test.onesignal.TestHelpers.fastColdRestartApp; -import static com.test.onesignal.TestHelpers.flushBufferedSharedPrefs; -import static com.test.onesignal.TestHelpers.getNextJob; -import static com.test.onesignal.TestHelpers.pauseActivity; -import static com.test.onesignal.TestHelpers.restartAppAndElapseTimeToNextSession; -import static com.test.onesignal.TestHelpers.startRemoteNotificationReceivedHandlerService; -import static com.test.onesignal.TestHelpers.stopActivity; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertThat; -import static org.robolectric.Shadows.shadowOf; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowPushRegistratorADM.class, - ShadowPushRegistratorFCM.class, - ShadowOSUtils.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowNotificationManagerCompat.class, - ShadowJobService.class, - ShadowHmsInstanceId.class, - ShadowFocusHandler.class, - OneSignalShadowPackageManager.class - }, - sdk = 21 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -// Enable to ensure test order to consistency debug flaky test. -// @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class MainOneSignalClassRunner { - - private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba"; - private static final String ONESIGNAL_NOTIFICATION_ID = "97d8e764-81c2-49b0-a644-713d052ae7d5"; - private static final String ONESIGNAL_SMS_NUMBER = "123456789"; - private static final String TIMEZONE_ID = "Europe/London"; - - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - private MockOSTimeImpl time; - private OSTrackerFactory trackerFactory; - private MockSessionManager sessionManager; - private MockOneSignalDBHelper dbHelper; - - private static String lastNotificationOpenedBody; - private static OSNotificationReceivedEvent lastServiceNotificationReceivedEvent; - - private static OneSignal.OSNotificationOpenedHandler getNotificationOpenedHandler() { - return openedResult -> { - - // TODO: Double check if we should use this or not - lastNotificationOpenedBody = openedResult.getNotification().getBody(); - }; - } - - private static JSONObject lastGetTags; - private static void getGetTagsHandler() { - OneSignal.getTags(tags -> lastGetTags = tags); - } - - private static OSEmailSubscriptionStateChanges lastEmailSubscriptionStateChanges; - private static OSSMSSubscriptionStateChanges lastSMSSubscriptionStateChanges; - - private static void cleanUp() throws Exception { - lastServiceNotificationReceivedEvent = null; - lastNotificationOpenedBody = null; - lastGetTags = null; - lastEmailSubscriptionStateChanges = null; - lastSMSSubscriptionStateChanges = null; - - ShadowGMSLocationController.reset(); - - TestHelpers.beforeTestInitAndCleanup(); - - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - } - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - - Field OneSignal_CurrentSubscription = OneSignal.class.getDeclaredField("subscribableStatus"); - OneSignal_CurrentSubscription.setAccessible(true); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - time = new MockOSTimeImpl(); - trackerFactory = new OSTrackerFactory(new MockOSSharedPreferences(), new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - - TestHelpers.setupTestWorkManager(blankActivity); - - cleanUp(); - - OneSignal_setTime(time); - } - - @After - public void afterEachTest() throws Exception { - afterTestCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - cleanUp(); - } - - @Test - public void testInitFromApplicationContext() throws Exception { - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - threadAndTaskWait(); - // Testing we still register the user in the background if this is the first time. (Note Context is application) - assertNotNull(ShadowOneSignalRestClient.lastPost); - - ShadowOneSignalRestClient.lastPost = null; - restartAppAndElapseTimeToNextSession(time); - - OneSignal_setTime(time); - // Restart app, should not send onSession automatically - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - threadAndTaskWait(); - assertNull(ShadowOneSignalRestClient.lastPost); - - // Starting of first Activity should trigger onSession - blankActivityController.resume(); - threadAndTaskWait(); - assertNotNull(ShadowOneSignalRestClient.lastPost); - } - - @Test - public void testDeviceTypeIsAndroid_forPlayerCreate() throws Exception { - // 1. Init OneSignal so the app id is cached - OneSignalInit(); - threadAndTaskWait(); - - // 2. Make sure device_type is Android (1) in player create - assertAndroidPlayerCreateAtIndex(1); - } - - @Test - public void testDeviceTypeIsAmazon_forPlayerCreate() throws Exception { - // 1. Mock Amazon device type for this test - ShadowOSUtils.supportsADM = true; - - // 2. Init OneSignal so the app id is cached - OneSignalInit(); - threadAndTaskWait(); - - // 3. Make sure device_type is Amazon (2) in player create - assertAmazonPlayerCreateAtIndex(1); - } - - @Test - public void testDeviceTypeIsHuawei_forPlayerCreate() throws Exception { - // 1. Mock Amazon device type for this test - ShadowOSUtils.supportsHMS(true); - - // 2. Init OneSignal so the app id is cached - OneSignalInit(); - threadAndTaskWait(); - - // 3. Make sure device_type is Huawei (13) in player create - assertHuaweiPlayerCreateAtIndex(1); - } - - @Test - public void testDeviceTypeIsAndroid_withoutOneSignalInit() throws Exception { - // 1. Init OneSignal so the app id is cached - OneSignalInit(); - threadAndTaskWait(); - - // 2. Background app - pauseActivity(blankActivityController); - - // 3. Restart OneSignal and clear the ShadowPushRegistratorADM statics - restartAppAndElapseTimeToNextSession(time); - threadAndTaskWait(); - - // 4. Set OneSignal.appId and context simulating a background sync doing so - OneSignal_setTime(time); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - - // 5. Foreground app and trigger new session - blankActivityController.resume(); - threadAndTaskWait(); - - // 6. Make sure device_type is Android (1) in player create and on_session - assertAndroidPlayerCreateAtIndex(1); - assertOnSessionAtIndex(3); - } - - @Test - public void testDeviceTypeIsAmazon_withoutOneSignalInit() throws Exception { - // 1. Mock Amazon device type for this test - ShadowOSUtils.supportsADM = true; - - // 2. Init OneSignal so the app id is cached - OneSignalInit(); - threadAndTaskWait(); - - // 3. Background the app - pauseActivity(blankActivityController); - - // 4. Restart the entire OneSignal and clear the ShadowPushRegistratorADM statics - restartAppAndElapseTimeToNextSession(time); - threadAndTaskWait(); - - // 5. Set OneSignal.appId and context simulating a background sync doing so - OneSignal_setTime(time); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - - // 6. Foreground app and trigger new session - blankActivityController.resume(); - threadAndTaskWait(); - - // 7. Make sure device_type is Android (1) in player create and on_session - assertAmazonPlayerCreateAtIndex(1); - assertOnSessionAtIndex(3); - } - - /** - * 1. User opens app to MainActivity - * 2. Comparison of MainActivity to dummy PermissionsActivity (1st Test Case) - * 3. User gives privacy consent and LocationGMS prompt is shown with PermissionsActivity - * 4. Comparison of PermissionsActivity to dummy PermissionsActivity (2nd Test Case) - */ - @Test - @Config(sdk = 26) - public void testLocationPermissionPromptWithPrivacyConsent() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignal.promptLocation(); - OneSignalInit(); - threadAndTaskWait(); - - // Create a dummy PermissionsActivity to compare in the test cases - Intent expectedActivity = new Intent(ApplicationProvider.getApplicationContext(), PermissionsActivity.class); - - /* Without showing the LocationGMS prompt we check to see that the current - * activity is not equal to PermissionsActivity since it is not showing yet */ - Intent actualActivity = shadowOf(blankActivity).getNextStartedActivity(); - // Assert false that the current activity is equal to the dummy PermissionsActivity - assertFalse(actualActivity.filterEquals(expectedActivity)); - - // Now we trigger the LocationGMS but providing consent to OneSignal SDK - OneSignal.provideUserConsent(true); - threadAndTaskWait(); - - // Now the PermissionsActivity should be the next on the stack - actualActivity = shadowOf(blankActivity).getNextStartedActivity(); - // Assert true that the current activity is equal to the dummy PermissionsActivity - assertTrue(actualActivity.filterEquals(expectedActivity)); - } - - @Test - public void testAppFocusWithPrivacyConsent() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignalInit(); - threadAndTaskWait(); - - // Make sure onAppFocus does not move past privacy consent check and on_session is not called - pauseActivity(blankActivityController); - - time.advanceSystemTimeBy(31); - - blankActivityController.resume(); - threadAndTaskWait(); - - // Only remote param request should be made at this point since privacy consent has not been given - int requestsCount = ShadowOneSignalRestClient.requests.size(); - assertEquals(1, requestsCount); - assertRemoteParamsAtIndex(0); - - // Give privacy consent - OneSignal.provideUserConsent(true); - - // Pause app and wait enough time to trigger on_session - pauseActivity(blankActivityController); - - time.advanceSystemTimeBy(31); - - // Call onAppFocus and check that the last url is a on_session request - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - } - - @Test - public void testAppOnFocusAfterOnSessionCall() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(60); - - time.advanceSystemAndElapsedTimeBy(0); - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - - time.advanceSystemAndElapsedTimeBy(61); - - pauseActivity(blankActivityController); - - assertAndRunSyncService(); - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_focus")); - assertEquals(61, ShadowOneSignalRestClient.lastPost.getInt("active_time")); - } - - @Test - public void testAppOnFocusAfterOnSessionCallFail() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(60); - - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - ShadowOneSignalRestClient.lastUrl = null; - - time.advanceSystemTimeBy(59); - - pauseActivity(blankActivityController); - assertNull(ShadowOneSignalRestClient.lastUrl); - } - - @Test - public void testAppOnFocusNeededAfterOnSessionCall() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(31); - - sessionManager.onNotificationReceived("notification_id"); - time.advanceSystemAndElapsedTimeBy(0); - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - - time.advanceSystemAndElapsedTimeBy(61); - - OneSignalPackagePrivateHelper.RemoteOutcomeParams params = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(); - trackerFactory.saveInfluenceParams(params); - - pauseActivity(blankActivityController); - - assertAndRunSyncService(); - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - assertOnFocusAtIndex(3, new JSONObject() {{ - put("active_time", 61); - put("direct", false); - put("notification_ids", new JSONArray().put("notification_id")); - }}); - } - - @Test - public void testAppOnFocus_containsOutcomeData_withOutcomeEventFlagsEnabled() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Disable all outcome flags - OneSignalPackagePrivateHelper.RemoteOutcomeParams params = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(); - trackerFactory.saveInfluenceParams(params); - - // Background app for 31 seconds - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(31); - - // Click notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), "notification_id"); - threadAndTaskWait(); - - // Foreground app - time.advanceSystemAndElapsedTimeBy(0); - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure on_session is called - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - - time.advanceSystemAndElapsedTimeBy(61); - - // Background app - pauseActivity(blankActivityController); - - // A sync job should have been schedule, lets run it to ensure on_focus is called. - assertRestCalls(4); - assertAndRunSyncService(); - - assertOnFocusAtIndex(4, new JSONObject() {{ - put("active_time", 61); - put("direct", true); - put("notification_ids", new JSONArray().put("notification_id")); - }}); - } - - @Test - public void testAppOnFocus_wontContainOutcomeData_withOutcomeEventFlagsDisabled() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Disable all outcome flags - OneSignalPackagePrivateHelper.RemoteOutcomeParams params = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false); - trackerFactory.saveInfluenceParams(params); - - // Background app for 31 seconds - pauseActivity(blankActivityController); - // Non on_focus call scheduled - assertNumberOfServicesAvailable(0); - time.advanceSystemTimeBy(31); - - // Click notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID + "1"); - threadAndTaskWait(); - - // Foreground app - time.advanceSystemAndElapsedTimeBy(0); - blankActivityController.resume(); - threadAndTaskWait(); - // Make sure on_session is called - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - - // Wait 60 seconds - time.advanceSystemAndElapsedTimeBy(60); - - // Background app - pauseActivity(blankActivityController); - assertAndRunSyncService(); - assertNumberOfServicesAvailable(1); - - // Make sure no direct flag or notifications are added into the on_focus - assertOnFocusAtIndexDoesNotHaveKeys(4, Arrays.asList("notification_ids", "direct")); - assertOnFocusAtIndex(4, new JSONObject().put("active_time", 60)); - } - - @Test - public void testAppOnFocusNeededAfterOnSessionCallFail() throws Exception { - time.advanceSystemTimeBy(60); - OneSignalInit(); - threadAndTaskWait(); - - blankActivityController.resume(); - threadAndTaskWait(); - - sessionManager.onDirectInfluenceFromNotificationOpen("notification_id"); - - OneSignalPackagePrivateHelper.RemoteOutcomeParams params = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(); - - trackerFactory.saveInfluenceParams(params); - time.advanceSystemTimeBy(10); - - ShadowOneSignalRestClient.lastUrl = null; - pauseActivity(blankActivityController); - - assertNull(ShadowOneSignalRestClient.lastUrl); - } - - @Test - public void testAppTwiceOnFocusNeededAfterOnSessionCallFail() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(31); - - final String notificationId = "notification_id"; - sessionManager.onNotificationReceived(notificationId); - sessionManager.onDirectInfluenceFromNotificationOpen(notificationId); - time.advanceSystemAndElapsedTimeBy(0); - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - - OneSignalPackagePrivateHelper.RemoteOutcomeParams params = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(); - trackerFactory.saveInfluenceParams(params); - - time.advanceSystemAndElapsedTimeBy(61); - - pauseActivity(blankActivityController); - - // on_focus should not run yet as we need to wait until the job kicks off due to needing - // to wait until the session is ended for outcome session counts to be correct - assertRestCalls(3); - assertAndRunSyncService(); - assertRestCalls(4); - assertOnFocusAtIndex(3, new JSONObject() {{ - put("active_time", 61); - put("direct", false); - put("notification_ids", new JSONArray().put(notificationId)); - }}); - - // Doing a quick 1 second focus should NOT trigger another network call - blankActivityController.resume(); - threadAndTaskWait(); - time.advanceSystemTimeBy(1); - pauseActivity(blankActivityController); - - assertRestCalls(4); - } - - @Test - public void testAppStartFocus() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players")); - - stopActivity(blankActivityController); - assertTrue(ShadowFocusHandler.Companion.getHasStopped()); - - blankActivityController.resume(); - assertFalse(ShadowFocusHandler.Companion.getHasStopped()); - } - - private void setOneSignalContextOpenAppThenBackgroundAndResume() throws Exception { - // 1. Context could be set by the app like this; Or on it's own when a push or other event happens - OneSignal.initWithContext(blankActivity.getApplication()); - - // 2. App is opened by user - blankActivityController.resume(); - threadAndTaskWait(); - - // 3. User backgrounds app - pauseActivity(blankActivityController); - - // 4. User goes back to app again - blankActivityController.resume(); - threadAndTaskWait(); - } - - @Test - public void testAppDoesNotCrashIfContextIsSetupViaEventButInitWasNotCalled() throws Exception { - setOneSignalContextOpenAppThenBackgroundAndResume(); - assertRestCalls(0); - } - - @Test - public void testStillRegistersIfInitCalledAfterIgnoredFocusEvents() throws Exception { - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - - setOneSignalContextOpenAppThenBackgroundAndResume(); - - OneSignalInit(); - threadAndTaskWait(); - - // Assert network calls are still made after SDK is initialized. - assertRemoteParamsAtIndex(0); - assertPlayerCreatePushAtIndex(1); - assertRestCalls(2); - } - - @Test - public void testInitWithContext_Activity() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - - OneSignal.initWithContext(blankActivity); - OneSignal.setAppId(ONESIGNAL_APP_ID); - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(OneSignal_isInForeground()); - } - - @Test - public void testInitWithContext_ActivityResumedBeforeInit() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - - blankActivityController.resume(); - OneSignal.initWithContext(blankActivity); - OneSignal.setAppId(ONESIGNAL_APP_ID); - threadAndTaskWait(); - - assertTrue(OneSignal_isInForeground()); - } - - @Test - public void testInitWithContextAppIdSet_ActivityResumedBeforeInit() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - - blankActivityController.resume(); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - - threadAndTaskWait(); - - assertTrue(OneSignal_isInForeground()); - } - - @Test - public void testInitWithContext_Application() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.DEBUG, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - - OneSignal.initWithContext(blankActivity.getApplicationContext()); - OneSignal.setAppId(ONESIGNAL_APP_ID); - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(OneSignal_isInForeground()); - } - - @Test - public void testOnSessionCalledOnlyOncePer30Sec() throws Exception { - // Will call create - time.advanceSystemTimeBy(2 * 60); - OneSignalInit(); - threadAndTaskWait(); - blankActivityController.resume(); - assertEquals("players", ShadowOneSignalRestClient.lastUrl); - - // Shouldn't call on_session if just resuming app with a short delay - pauseActivity(blankActivityController); - ShadowOneSignalRestClient.lastUrl = null; - blankActivityController.resume(); - threadAndTaskWait(); - assertNull(ShadowOneSignalRestClient.lastUrl); - - // Or when restarting the app quickly. - ShadowOneSignalRestClient.lastPost = null; - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - blankActivityController.resume(); - threadAndTaskWait(); - assertTrue(ShadowOneSignalRestClient.lastUrl.matches(".*android_params.js.*")); - - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(2 * 60); - ShadowOneSignalRestClient.lastUrl = null; - blankActivityController.resume(); - threadAndTaskWait(); - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - assertEquals("{\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"}", ShadowOneSignalRestClient.lastPost.toString()); - } - - @Test - public void testRequestMadeWithCorrectTimeZoneID() throws Exception { - //Sets Default timezone and initalizes onesignal - TimeZone.setDefault(TimeZone.getTimeZone(TIMEZONE_ID)); - OneSignalInit(); - threadAndTaskWait(); - assertEquals(TIMEZONE_ID, ShadowOneSignalRestClient.lastPost.get("timezone_id")); - } - - @Test - public void testAlwaysUseRemoteProjectNumberOverLocal() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - assertEquals("87654321", ShadowPushRegistratorFCM.lastProjectNumber); - - // A 2nd init call - OneSignalInit(); - - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(31); - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure when we try to register again before our on_session call it is with the remote - // project number instead of the local one. - assertEquals("87654321", ShadowPushRegistratorFCM.lastProjectNumber); - } - - @Test - public void testPutStillCalledOnChanges() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - blankActivityController.resume(); - assertEquals("players", ShadowOneSignalRestClient.lastUrl); - - // Shouldn't call on_session if just resuming app with a short delay - pauseActivity(blankActivityController); - ShadowOneSignalRestClient.lastUrl = null; - blankActivityController.resume(); - threadAndTaskWait(); - assertNull(ShadowOneSignalRestClient.lastUrl); - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - - ShadowOSUtils.carrierName = "test2"; - - // Should make PUT call with changes on app restart - ShadowOneSignalRestClient.lastPost = null; - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - blankActivityController.resume(); - threadAndTaskWait(); - - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - assertEquals("players/" + OneSignal.getDeviceState().getUserId(), ShadowOneSignalRestClient.lastUrl); - assertEquals("{\"carrier\":\"test2\",\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"}", ShadowOneSignalRestClient.lastPost.toString()); - } - - @Test - public void testCreatesEvenIfAppIsQuicklyForceKilledOnFirstLaunch() throws Exception { - // 1. App cold restarted before the device has a chance to create a player - OneSignalInit(); - fastColdRestartApp(); - - // 2. 2nd cold start of the app. - OneSignalInit(); - threadAndTaskWait(); - - // 3. Ensure we made 3 network calls. (2 to android_params and 1 create player call) - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - assertEquals("players", ShadowOneSignalRestClient.lastUrl); - assertEquals(REST_METHOD.POST, ShadowOneSignalRestClient.requests.get(2).method); - } - - @Test - public void testOnSessionEvenIfQuickAppRestart() throws Exception { - // 1. Do app first start and register the device for a player id - OneSignalInit(); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - - // 2. App is restarted before it can make it's on_session call - OneSignalInit(); - fastColdRestartApp(); - - // 3. 3rd start of the app, we should make an on_session call since the last one did not go through - OneSignalInit(); - threadAndTaskWait(); - - // 4. Ensure we made 4 network calls. (2 to android_params and 1 create player call) - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - assertEquals("players/" + OneSignal.getDeviceState().getUserId() + "/on_session", ShadowOneSignalRestClient.lastUrl); - assertEquals(REST_METHOD.POST, ShadowOneSignalRestClient.requests.get(4).method); - } - - @Test - public void testOnSessionFlagIsClearedAfterSuccessfullySynced() throws Exception { - // 1. App cold restarted before the device has a chance to create a player - OneSignalInit(); - fastColdRestartApp(); - - // 2. 2nd cold start of the app, waiting to make sure device gets registered - OneSignalInit(); - threadAndTaskWait(); - - // 3. Restart the app without wating. - fastColdRestartApp(); - - // 4. 3rd cold start of the app. - OneSignalInit(); - threadAndTaskWait(); - - // 4. Ensure we made 4 network calls. (3 to android_params and 1 create player call) - // We are making sure we are only making on create call and NO on_session calls - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - assertEquals("players", ShadowOneSignalRestClient.requests.get(2).url); - assertEquals(REST_METHOD.POST, ShadowOneSignalRestClient.requests.get(2).method); - } - - @Test - public void testPutCallsMadeWhenUserStateChangesOnAppResume() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - blankActivityController.resume(); - assertEquals("players", ShadowOneSignalRestClient.lastUrl); - } - - @Test - public void testAndroidParamsProjectNumberOverridesLocal() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - assertThat(ShadowPushRegistratorFCM.lastProjectNumber, not("123456789")); - } - - @Test - @Config(shadows = {ShadowOneSignal.class}) - public void testOpenFromNotificationWhenAppIsDead() throws Exception { - OneSignal.initWithContext(blankActivity); - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Robo test message\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - - threadAndTaskWait(); - - assertEquals("Robo test message", lastNotificationOpenedBody); - } - - @Test - public void testNullProjectNumberSetsErrorType() throws Exception { - // Get call will not return a Google project number if it hasn't been entered on the OneSignal dashboard. - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject() {{ - put("awl_list", new JSONObject()); - put("android_sender_id", ""); - }}); - - // Don't fire the mock callback, it will be done from the real class. - ShadowPushRegistratorFCM.skipComplete = true; - - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - assertEquals(-6, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - } - - @Test - @Config(shadows = {ShadowRoboNotificationManager.class}, sdk = 26) - public void testNotificationChannelListPayload() throws Exception { - NotificationChannelManagerRunner testHelper = new NotificationChannelManagerRunner().setContext(blankActivity); - - JSONObject androidParams = testHelper.createBasicChannelListPayload(); - androidParams.put("awl_list", new JSONObject()); - // Get call will not return a Google project number if it hasn't been entered on the OneSignal dashboard. - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(androidParams.toString()); - - // Don't fire the mock callback, it will be done from the real class. - ShadowPushRegistratorFCM.skipComplete = true; - - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - testHelper.assertChannelsForBasicChannelList(); - } - - @Test - public void shouldCorrectlyRemoveOpenedHandlerAndFireMissedOnesWhenAddedBack() throws Exception { - OneSignalInit(); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - threadAndTaskWait(); - - OneSignal.setNotificationOpenedHandler(null); - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Robo test message\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - assertNull(lastNotificationOpenedBody); - - OneSignalInit(); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - assertEquals("Robo test message", lastNotificationOpenedBody); - } - - @Test - public void shouldNotFireNotificationOpenAgainAfterAppRestart() throws Exception { - OneSignalInit(); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - - threadAndTaskWait(); - - Bundle bundle = getBaseNotifBundle(); - OneSignalPackagePrivateHelper.NotificationBundleProcessor_ProcessFromFCMIntentService(blankActivity, bundle); - - threadAndTaskWait(); - - lastNotificationOpenedBody = null; - - // Restart app - Should omit notification_types - StaticResetHelper.restSetStaticFields(); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - - threadAndTaskWait(); - - assertEquals(null, lastNotificationOpenedBody); - } - - @Test - public void testOpeningLauncherActivity() throws Exception { - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignalInit(); - fastColdRestartApp(); - - AddLauncherIntentFilter(); - // From app launching normally - assertNotNull(shadowOf(blankActivity).getNextStartedActivity()); - // Will get appId saved - OneSignal.initWithContext(blankActivity.getApplicationContext()); - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - - assertNotNull(shadowOf(blankActivity).getNextStartedActivity()); - assertNull(shadowOf(blankActivity).getNextStartedActivity()); - } - - @Test - public void testOpeningLauncherActivityWhenOffline() throws Exception { - ShadowOneSignalRestClient.failGetParams = true; - AddLauncherIntentFilter(); - - OneSignalInit(); - // This removes Activity from the unit test's state - assertNotNull(shadowOf(blankActivity).getNextStartedActivity()); - - // Background the app - blankActivityController.pause(); - - // Open a notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - - // Ensure the app is foregrounded - assertNotNull(shadowOf(blankActivity).getNextStartedActivity()); - } - - @Test - public void testOpeningLaunchUrl() throws Exception { - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignalInit(); - fastColdRestartApp(); - OneSignal.initWithContext(blankActivity); - // Removes app launch - shadowOf(blankActivity).getNextStartedActivity(); - - // No OneSignal init here to test case where it is located in an Activity. - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\", \"u\": \"http://google.com\" } }]"), ONESIGNAL_NOTIFICATION_ID); - Intent intent = shadowOf(blankActivity).getNextStartedActivity(); - assertEquals("android.intent.action.VIEW", intent.getAction()); - assertEquals("http://google.com", intent.getData().toString()); - assertNull(shadowOf(blankActivity).getNextStartedActivity()); - } - - @Test - public void testOpeningLaunchUrlWithDisableDefault() throws Exception { - // Add the 'com.onesignal.NotificationOpened.DEFAULT' as 'DISABLE' meta-data tag - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - - // Removes app launch - shadowOf(blankActivity).getNextStartedActivity(); - - // No OneSignal init here to test case where it is located in an Activity. - - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\", \"u\": \"http://google.com\" } }]"), ONESIGNAL_NOTIFICATION_ID); - assertNull(shadowOf(blankActivity).getNextStartedActivity()); - } - - @Test - public void testDisableOpeningLauncherActivityOnNotificationOpen() throws Exception { - // Add the 'com.onesignal.NotificationOpened.DEFAULT' as 'DISABLE' meta-data tag - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - - // From app launching normally - assertNotNull(shadowOf(blankActivity).getNextStartedActivity()); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - assertNull(lastNotificationOpenedBody); - - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - - assertNull(shadowOf(blankActivity).getNextStartedActivity()); - assertEquals("Test Msg", lastNotificationOpenedBody); - } - - @Test - public void testLaunchUrlSuppressTrue() throws Exception { - // Add the 'com.onesignal.suppressLaunchURLs' as 'true' meta-data tag - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignalInit(); - fastColdRestartApp(); - - // Add the 'com.onesignal.suppressLaunchURLs' as 'true' meta-data tag - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.suppressLaunchURLs", true); - - // Removes app launch - shadowOf(blankActivity).getNextStartedActivity(); - - // Init with context since this is call before calling OneSignal_handleNotificationOpen internally - OneSignal.initWithContext(blankActivity); - - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\", \"u\": \"http://google.com\" } }]"), ONESIGNAL_NOTIFICATION_ID); - threadAndTaskWait(); - - assertOpenMainActivityIntent(shadowOf(blankActivity).getNextStartedActivity()); - } - - private void assertOpenMainActivityIntent(@NonNull Intent intent) { - assertEquals(Intent.ACTION_MAIN, intent.getAction()); - assertTrue(intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)); - } - - @Test - public void testLaunchUrlSuppressFalse() throws Exception { - // Add the 'com.onesignal.suppressLaunchURLs' as 'true' meta-data tag - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignalInit(); - fastColdRestartApp(); - - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.suppressLaunchURLs", false); - OneSignal.initWithContext(blankActivity); - - // Removes app launch - shadowOf(blankActivity).getNextStartedActivity(); - - // Init with context since this is call before calling OneSignal_handleNotificationOpen internally - OneSignal.initWithContext(blankActivity); - - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\", \"u\": \"http://google.com\" } }]"), ONESIGNAL_NOTIFICATION_ID); - threadAndTaskWait(); - - Intent intent = shadowOf(blankActivity).getNextStartedActivity(); - assertEquals("android.intent.action.VIEW", intent.getAction()); - assertEquals("http://google.com", intent.getData().toString()); - assertNull(shadowOf(blankActivity).getNextStartedActivity()); - } - - private static String notificationReceivedBody; - private static int androidNotificationId; - - @Test - @Config (shadows = { ShadowGenerateNotification.class }) - public void testNotificationReceivedWhenAppInFocus() throws Exception { - // 1. Init OneSignal - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationWillShowInForegroundHandler(notificationReceivedEvent -> { - androidNotificationId = notificationReceivedEvent.getNotification().getAndroidNotificationId(); - notificationReceivedBody = notificationReceivedEvent.getNotification().getBody(); - - notificationReceivedEvent.complete(notificationReceivedEvent.getNotification()); - }); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - - // 2. Foreground the app - blankActivityController.resume(); - threadAndTaskWait(); - - Bundle bundle = getBaseNotifBundle(); - - final boolean[] callbackEnded = {false}; - OneSignalPackagePrivateHelper.ProcessBundleReceiverCallback processBundleReceiverCallback = new OneSignalPackagePrivateHelper.ProcessBundleReceiverCallback() { - public void onBundleProcessed(OneSignalPackagePrivateHelper.ProcessedBundleResult processedResult) { - assertNotNull(processedResult); - assertTrue(processedResult.isProcessed()); - callbackEnded[0] = true; - } - }; - - FCMBroadcastReceiver_processBundle(blankActivity, bundle, processBundleReceiverCallback); - Awaitility.await() - .atMost(new Duration(3, TimeUnit.SECONDS)) - .pollInterval(new Duration(100, TimeUnit.MILLISECONDS)) - .untilAsserted(() -> { - assertTrue(callbackEnded[0]); - }); - assertNull(lastNotificationOpenedBody); - - assertEquals("Robo test message", notificationReceivedBody); - assertNotEquals(0, androidNotificationId); - - // Don't fire for duplicates - lastNotificationOpenedBody = null; - notificationReceivedBody = null; - - FCMBroadcastReceiver_processBundle(blankActivity, bundle); - threadAndTaskWait(); - - assertNull(lastNotificationOpenedBody); - assertNull(notificationReceivedBody); - - lastNotificationOpenedBody = null; - notificationReceivedBody = null; - - // Test that only NotificationReceivedHandler fires - bundle = getBaseNotifBundle("UUID2"); - FCMBroadcastReceiver_processBundle(blankActivity, bundle); - threadAndTaskWait(); - - assertNull(lastNotificationOpenedBody); - assertEquals("Robo test message", notificationReceivedBody); - } - - // Start Received Request tests (report_received) - - @Test - @Config(shadows = { ShadowGenerateNotification.class, ShadowReceiveReceiptController.class }) - public void testNotificationReceivedSendReceivedRequest_WhenAppInBackground() throws Exception { - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - fastColdRestartApp(); - - ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true); - // 1. initWithContext is called when startProcessing notification - OneSignal.initWithContext(blankActivity.getApplicationContext()); - // 2. Receive a notification in background - FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle()); - threadAndTaskWait(); - - // 3. Check that report_received where sent - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - assertEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class, ShadowReceiveReceiptController.class }) - public void testNotificationReceivedSendReceivedRequest_WhenAppInForeground() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true); - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - // 1. Receive a notification in background - FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle()); - threadAndTaskWait(); - - // 2. Check that report_received where sent - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - assertEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class, ShadowReceiveReceiptController.class }) - public void testNotificationReceivedNoSendReceivedRequest_WhenDisabled() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(false); - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - // 1. Receive a notification in background - FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle()); - threadAndTaskWait(); - - // 2. Check that report_received where sent - assertEquals(2, ShadowOneSignalRestClient.requests.size()); - assertNotEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class, ShadowReceiveReceiptController.class }) - public void testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed() throws Exception { - // 1. Setup correct notification extension service class - startRemoteNotificationReceivedHandlerService("com.test.onesignal.MainOneSignalClassRunner$" + - "RemoteNotificationReceivedHandler_NoDisplay"); - - ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true); - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - // 2. Receive a notification in background - FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle()); - threadAndTaskWait(); - - // 3. Make sure service was called - assertNotNull(lastServiceNotificationReceivedEvent); - - // 4. Check that report_received where sent - assertEquals(2, ShadowOneSignalRestClient.requests.size()); - assertNotEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl); - } - - @Test - @Config(sdk = 26, shadows = { ShadowGenerateNotification.class, ShadowOneSignalNotificationManager.class, ShadowReceiveReceiptController.class }) - public void testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed_DisabledByChannel() throws Exception { - // 1. Setup correct notification extension service class - startRemoteNotificationReceivedHandlerService("com.test.onesignal.MainOneSignalClassRunner$" + - "RemoteNotificationReceivedHandler"); - - ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true); - ShadowOneSignalNotificationManager.setNotificationChannelEnabled(false); - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - // 2. Receive a notification in background - FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle()); - threadAndTaskWait(); - - // 3. Make sure service was called - assertNotNull(lastServiceNotificationReceivedEvent); - - // 4. Check that report_received where sent - assertEquals(2, ShadowOneSignalRestClient.requests.size()); - assertNotEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl); - } - - /** - * @see #testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed - */ - public static class RemoteNotificationReceivedHandler_NoDisplay implements OneSignal.OSRemoteNotificationReceivedHandler { - - @Override - public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent receivedEvent) { - lastServiceNotificationReceivedEvent = receivedEvent; - - receivedEvent.complete(null); - } - } - - /** - * @see #testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed_DisabledByChannel - */ - public static class RemoteNotificationReceivedHandler implements OneSignal.OSRemoteNotificationReceivedHandler { - - @Override - public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent receivedEvent) { - lastServiceNotificationReceivedEvent = receivedEvent; - - receivedEvent.complete(receivedEvent.getNotification()); - } - } - - // End Received Request tests (report_received) - - @Test - @Config(shadows = {ShadowBadgeCountUpdater.class}) - public void testBadgeClearOnFirstStart() throws Exception { - ShadowBadgeCountUpdater.lastCount = -1; - - // First run should set badge to 0 - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - threadAndTaskWait(); - assertEquals(0, ShadowBadgeCountUpdater.lastCount); - - // Resume should have effect on badges. Notifications will be restored - ShadowBadgeCountUpdater.lastCount = -1; - blankActivityController.resume(); - threadAndTaskWait(); - assertEquals(-1, ShadowBadgeCountUpdater.lastCount); - - StaticResetHelper.restSetStaticFields(); - // Restart should have no effect on badges - ShadowBadgeCountUpdater.lastCount = -1; - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - threadAndTaskWait(); - assertEquals(-1, ShadowBadgeCountUpdater.lastCount); - } - - @Test - public void testUnsubscribeStatusShouldBeSetIfFCMErrored() throws Exception { - ShadowPushRegistratorFCM.fail = true; - OneSignalInit(); - threadAndTaskWait(); - assertEquals(-7, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - } - - @Test - public void testInvalidGoogleProjectNumberWithSuccessfulRegisterResponse() throws Exception { - // A more real test would be "missing support library" but bad project number is an easier setup - // and is testing the same logic. - ShadowPushRegistratorFCM.fail = true; -// OneSignalInitWithBadProjectNum(); - OneSignalInit(); - threadAndTaskWait(); - Robolectric.getForegroundThreadScheduler().runOneTask(); - - assertEquals(-7, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - // Test that idsAvailable still fires - assertEquals(ShadowOneSignalRestClient.pushUserId, OneSignal.getDeviceState().getUserId()); - assertNull(OneSignal.getDeviceState().getPushToken()); // Since FCM registration failed, this should be null - - // We now get a push token after the device registers with Onesignal, - // the idsAvailable callback should fire a 2nd time with a registrationId automatically - ShadowPushRegistratorFCM.manualFireRegisterForPush(); - threadAndTaskWait(); - assertEquals(ShadowPushRegistratorFCM.regId, OneSignal.getDeviceState().getPushToken()); - } - - @Test - public void testGMSErrorsAfterSuccessfulSubscribeDoNotUnsubscribeTheDevice() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - - ShadowOneSignalRestClient.lastPost = null; - restartAppAndElapseTimeToNextSession(time); - - ShadowPushRegistratorFCM.fail = true; - OneSignalInit(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - } - - @Test - public void testInvalidGoogleProjectNumberWithFailedRegisterResponse() throws Exception { - // Ensures lower number notification_types do not over right higher numbered ones. - ShadowPushRegistratorFCM.fail = true; -// OneSignalInitWithBadProjectNum(); - OneSignalInit(); - threadAndTaskWait(); - Robolectric.getForegroundThreadScheduler().runOneTask(); - assertEquals(-7, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - - // Test that idsAvailable still fires - assertEquals(ShadowOneSignalRestClient.pushUserId, OneSignal.getDeviceState().getUserId()); - } - - @Test - public void testSetSubscriptionShouldNotOverrideSubscribeError() throws Exception { -// OneSignalInitWithBadProjectNum(); - OneSignalInit(); - blankActivityController.resume(); - threadAndTaskWait(); - - // Should not try to update server - ShadowOneSignalRestClient.lastPost = null; - OneSignal.disablePush(false); - assertNull(ShadowOneSignalRestClient.lastPost); - - // Restart app - Should omit notification_types - restartAppAndElapseTimeToNextSession(time); - OneSignal_setTime(time); -// OneSignalInitWithBadProjectNum(); - OneSignalInit(); - blankActivityController.resume(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - } - - @Test - public void shouldNotResetSubscriptionOnSession() throws Exception { - OneSignalInit(); - OneSignal.disablePush(true); - threadAndTaskWait(); - assertEquals(-2, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - - restartAppAndElapseTimeToNextSession(time); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - } - - @Test - public void shouldSetSubscriptionCorrectlyEvenAfterFirstOneSignalRestInitFail() throws Exception { - // Failed to register with OneSignal but SetSubscription was called with false - ShadowOneSignalRestClient.failAll = true; - OneSignalInit(); - OneSignal.disablePush(true); - threadAndTaskWait(); - ShadowOneSignalRestClient.failAll = false; - - - // Restart app - Should send unsubscribe with create player call. - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - assertEquals(-2, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - - // Restart app again - Value synced last time so don't send again. - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - } - - @Test - public void shouldUpdateNotificationTypesCorrectlyEvenWhenSetSubscriptionIsCalledInAnErrorState() throws Exception { - ShadowPushRegistratorFCM.fail = true; - OneSignalInit(); - threadAndTaskWait(); - OneSignal.disablePush(false); - - // Restart app - Should send subscribe with on_session call. - fastColdRestartApp(); - ShadowPushRegistratorFCM.fail = false; - OneSignalInit(); - threadAndTaskWait(); - assertEquals(1, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - } - - @Test - public void shouldAllowMultipleSetSubscription() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.disablePush(true); - threadAndTaskWait(); - - assertEquals(-2, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - - // Should not resend same value - ShadowOneSignalRestClient.lastPost = null; - OneSignal.disablePush(true); - assertNull(ShadowOneSignalRestClient.lastPost); - - OneSignal.disablePush(false); - threadAndTaskWait(); - assertEquals(1, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - - // Should not resend same value - ShadowOneSignalRestClient.lastPost = null; - OneSignal.disablePush(false); - threadAndTaskWait(); - assertNull(ShadowOneSignalRestClient.lastPost); - } - - @Test - public void testFCMTimeOutThenSuccessesLater() throws Exception { - // Init with a bad connection to Google. - ShadowPushRegistratorFCM.fail = true; - OneSignalInit(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("identifier")); - - // Registers for FCM after a retry - ShadowPushRegistratorFCM.fail = false; - ShadowPushRegistratorFCM.manualFireRegisterForPush(); - threadAndTaskWait(); - assertEquals(ShadowPushRegistratorFCM.regId, ShadowOneSignalRestClient.lastPost.getString("identifier")); - - // Cold restart app, should not send the same identifier again. - ShadowOneSignalRestClient.lastPost = null; - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(ShadowOneSignalRestClient.lastPost.has("identifier")); - } - - @Test - public void testChangeAppId_fromColdStart() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - int normalCreateFieldCount = ShadowOneSignalRestClient.lastPost.length(); - fastColdRestartApp(); - OneSignal.setAppId("99f7f966-d8cc-11e4-bed1-df8f05be55b2"); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - assertEquals(normalCreateFieldCount, ShadowOneSignalRestClient.lastPost.length()); - } - - /** - * Similar to testChangeAppId_fromColdStart test - */ - @Test - public void testChangeAppId_duringRuntime() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - int normalCreateFieldCount = ShadowOneSignalRestClient.lastPost.length(); - OneSignal.setAppId("99f7f966-d8cc-11e4-bed1-df8f05be55b2"); - threadAndTaskWait(); - - assertEquals(normalCreateFieldCount, ShadowOneSignalRestClient.lastPost.length()); - } - - @Test - public void testUserDeletedFromServer() throws Exception { - // 1. Open app and register for the first time. - OneSignalInit(); - threadAndTaskWait(); - - int normalCreateFieldCount = ShadowOneSignalRestClient.lastPost.length(); - ShadowOneSignalRestClient.lastPost = null; - - // 2. Developer deletes user and cold restarts the app - restartAppAndElapseTimeToNextSession(time); - ShadowOneSignalRestClient.failNext = true; - ShadowOneSignalRestClient.setNextFailureJSONResponse(new JSONObject() {{ - put("errors", new JSONArray() {{ - put("Device type is not a valid device_type. Valid options are: 0 = iOS, 1 = Android, 2 = Amazon, 3 = WindowsPhone(MPNS), 4 = ChromeApp, 5 = ChromeWebsite, 6 = WindowsPhone(WNS), 7 = Safari(APNS), 8 = Firefox"); - }}); - }}); - OneSignalInit(); - threadAndTaskWait(); - - // 3. Assert the SDK handles the error above and make a new create call. - assertPlayerCreatePushAtIndex(4); - // Checking that the number of fields matches exactly to the original create call. - assertEquals(normalCreateFieldCount, ShadowOneSignalRestClient.lastPost.length()); - - // 4. Developer deletes users again from dashboard while app is running. - ShadowOneSignalRestClient.failNext = true; - ShadowOneSignalRestClient.setNextFailureJSONResponse(new JSONObject() {{ - put("errors", new JSONArray().put("No user with this id found")); - }}); - // 5. Make some call the will attempt a player update - OneSignal.sendTag("key1", "value1"); - threadAndTaskWait(); - - // 6. Assert the SDK handles the error above and make a new create call. - assertPlayerCreatePushAtIndex(6); - // Checking that the number of fields matches original create call, +1 for tags - assertEquals(normalCreateFieldCount + 1, ShadowOneSignalRestClient.lastPost.length()); - } - - @Test - public void testOfflineCrashes() throws Exception { - ConnectivityManager connectivityManager = (ConnectivityManager)ApplicationProvider.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); - ShadowConnectivityManager shadowConnectivityManager = shadowOf(connectivityManager); - shadowConnectivityManager.setActiveNetworkInfo(null); - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.sendTag("key", "value"); - threadAndTaskWait(); - - OneSignal.disablePush(true); - threadAndTaskWait(); - } - - // ####### SendTags Tests ######## - - @Test - public void shouldSendTags() throws Exception { - OneSignalInit(); - OneSignal.sendTags(new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}")); - threadAndTaskWait(); - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - assertEquals(ONESIGNAL_APP_ID, ShadowOneSignalRestClient.lastPost.getString("app_id")); - assertEquals("value1", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").getString("test1")); - assertEquals("value2", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").getString("test2")); - - // Should omit sending repeated tags - ShadowOneSignalRestClient.lastPost = null; - OneSignal.sendTags(new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}")); - threadAndTaskWait(); - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - assertNull(ShadowOneSignalRestClient.lastPost); - - // Should only send changed and new tags - OneSignal.sendTags(new JSONObject("{\"test1\": \"value1.5\", \"test2\": \"value2\", \"test3\": \"value3\"}")); - threadAndTaskWait(); - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - JSONObject sentTags = ShadowOneSignalRestClient.lastPost.getJSONObject("tags"); - assertEquals("value1.5", sentTags.getString("test1")); - assertFalse(sentTags.has(("test2"))); - assertEquals("value3", sentTags.getString("test3")); - - // Test empty JSONObject - OneSignal.sendTags(new JSONObject()); - OneSignal.sendTags(new JSONObject(), null); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void shouldSendTagsFromBackgroundOnAppKilled() throws Exception { - // 1. Setup correct notification extension service class - startRemoteNotificationReceivedHandlerService("com.test.onesignal.MainOneSignalClassRunner$" + - "RemoteNotificationReceivedHandler_callSendTags"); - - // First init run for appId to be saved - // At least OneSignal was init once for user to be subscribed - // If this doesn't' happen, notifications will not arrive - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - fastColdRestartApp(); - - // 2. initWithContext is called when startProcessing notification - OneSignal.initWithContext(blankActivity.getApplicationContext()); - // 3. Receive a notification in background - FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle()); - threadAndTaskWait(); - - // 4. Make sure service was called - assertNotNull(lastServiceNotificationReceivedEvent); - - // 5. Check that tags where sent - assertEquals(4, ShadowOneSignalRestClient.requests.size()); - ShadowOneSignalRestClient.Request playersRequest = ShadowOneSignalRestClient.requests.get(3); - JSONObject sentTags = playersRequest.payload.getJSONObject("tags"); - assertEquals("test_value", sentTags.getString("test_key")); - } - - /** - * @see #shouldSendTagsFromBackgroundOnAppKilled - */ - public static class RemoteNotificationReceivedHandler_callSendTags implements OneSignal.OSRemoteNotificationReceivedHandler { - - @Override - public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent receivedEvent) { - lastServiceNotificationReceivedEvent = receivedEvent; - - OneSignal.sendTag("test_key", "test_value"); - receivedEvent.complete(receivedEvent.getNotification()); - } - } - - @Test - public void shouldNotSendTagOnRepeats() throws Exception { - OneSignalInit(); - OneSignal.sendTag("test1", "value1"); - threadAndTaskWait(); - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - assertEquals(ONESIGNAL_APP_ID, ShadowOneSignalRestClient.lastPost.getString("app_id")); - assertEquals("value1", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").getString("test1")); - - // Should only send new tag - ShadowOneSignalRestClient.lastPost = null; - OneSignal.sendTag("test2", "value2"); - threadAndTaskWait(); - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - assertEquals("value2", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").getString("test2")); - - // Should not resend first tags - ShadowOneSignalRestClient.lastPost = null; - OneSignal.sendTag("test1", "value1"); - threadAndTaskWait(); - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - assertNull(ShadowOneSignalRestClient.lastPost); - } - - @Test - public void shouldSendTagsWithRequestBatching() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - OneSignal.sendTags(new JSONObject("{\"test1\": \"value1\"}")); - OneSignal.sendTags(new JSONObject("{\"test2\": \"value2\"}")); - - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals("value1", lastGetTags.getString("test1")); - assertEquals("value2", lastGetTags.getString("test2")); - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - } - - @Test - public void shouldNotAttemptToSendTagsBeforeGettingPlayerId() throws Exception { - ShadowPushRegistratorFCM.skipComplete = true; - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(1, ShadowOneSignalRestClient.networkCallCount); - - // Should not attempt to make a network call yet as we don't have a player_id - OneSignal.sendTags(new JSONObject("{\"test1\": \"value1\"}")); - threadAndTaskWait(); - - assertEquals(1, ShadowOneSignalRestClient.networkCallCount); - - ShadowPushRegistratorFCM.fireLastCallback(); - threadAndTaskWait(); - - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - assertNotNull(OneSignal.getDeviceState().getUserId()); - } - - private static class TestChangeTagsUpdateHandler implements ChangeTagsUpdateHandler { - private AtomicBoolean succeeded = new AtomicBoolean(false); - private AtomicBoolean failed = new AtomicBoolean(false); - - @Override - public void onSuccess(JSONObject tags) { - succeeded.set(true); - } - - @Override - public void onFailure(OneSignal.SendTagsError error) { - failed.set(true); - } - - boolean getSucceeded() { - return succeeded.get(); - } - - boolean getFailed() { - return failed.get(); - } - } - - // Tests to make sure the onSuccess handler works - @Test - public void shouldSendNewTagsWithResponse() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - TestChangeTagsUpdateHandler handler = new TestChangeTagsUpdateHandler(); - - OneSignal.sendTags(new JSONObject("{\"test\" : \"value\"}"), handler); - - threadAndTaskWait(); - - assertTrue(handler.getSucceeded()); - - // now test to make sure the handler still fires for a call to - // sendTags() that doesn't modify existing tags (no JSON delta) - - handler = new TestChangeTagsUpdateHandler(); - - OneSignal.sendTags(new JSONObject("{\"test\" : \"value\"}"), handler); - - threadAndTaskWait(); - - assertTrue(handler.getSucceeded()); - } - - // Tests to make sure that the onFailure callback works - @Test - public void shouldFailToSendTagsWithResponse() throws Exception { - TestChangeTagsUpdateHandler handler = new TestChangeTagsUpdateHandler(); - - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.failMethod = "players"; - ShadowOneSignalRestClient.failHttpCode = 403; - ShadowOneSignalRestClient.setNextFailureJSONResponse(new JSONObject() {{ - put("tags", "error"); - }}); - - // Should fail because players call failed with tags - OneSignal.sendTags(new JSONObject("{\"test\" : \"value\"}"), handler); - threadAndTaskWait(); - - assertTrue(handler.getFailed()); - } - - // Tests to make sure that the SDK will call both handlers - @Test - public void shouldCallMultipleHandlers() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - TestChangeTagsUpdateHandler firstHandler = new TestChangeTagsUpdateHandler(); - TestChangeTagsUpdateHandler secondHandler = new TestChangeTagsUpdateHandler(); - - OneSignal.sendTags(new JSONObject("{\"test1\" : \"value1\"}"), firstHandler); - OneSignal.sendTags(new JSONObject("{\"test2\" : \"value2\"}"), secondHandler); - - threadAndTaskWait(); - - assertTrue(firstHandler.getSucceeded()); - assertTrue(secondHandler.getSucceeded()); - } - - @Test - public void testNestedSendTagsOnSuccess() throws Exception { - final JSONObject tags = new JSONObject().put("key", "value"); - - OneSignalInit(); - OneSignal.sendTags(tags); - threadAndTaskWait(); - - // Sending same tags a 2nd time creates the issue, as it take a different code path - OneSignal.sendTags( - tags, - new ChangeTagsUpdateHandler() { - @Override - public void onSuccess(JSONObject values) { - OneSignal.sendTags(tags, new TestChangeTagsUpdateHandler()); - } - @Override - public void onFailure(OneSignal.SendTagsError error) {} - } - ); - threadAndTaskWait(); - } - - @Test - public void shouldCreatePlayerAfterDelayedTokenFromApplicationOnCreate() throws Exception { - ShadowPushRegistratorFCM.skipComplete = true; - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - blankActivityController.resume(); - threadAndTaskWait(); - - ShadowPushRegistratorFCM.fireLastCallback(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request createPlayer = ShadowOneSignalRestClient.requests.get(1); - assertEquals(2, ShadowOneSignalRestClient.requests.size()); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, createPlayer.method); - assertEquals("players", createPlayer.url); - assertEquals("b4f7f966-d8cc-11e4-bed1-df8f05be55ba", createPlayer.payload.get("app_id")); - assertEquals(1, createPlayer.payload.get("device_type")); - } - - @Test - public void testOldIntValues() throws Exception { - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", "{\"tags\": {\"int\": 123}}"); - editor.putString("ONESIGNAL_USERSTATE_SYNCVALYES_TOSYNC_STATE", "{\"tags\": {\"int\": 123}}"); - editor.apply(); - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.deleteTag("int"); - threadAndTaskWait(); - - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals("{}", lastGetTags.toString()); - } - - @Test - public void testSendTagNonStringValues() throws Exception { - OneSignalInit(); - OneSignal.sendTags("{\"int\": 122, \"bool\": true, \"null\": null, \"array\": [123], \"object\": {}}"); - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals(String.class, lastGetTags.get("int").getClass()); - assertEquals("122", lastGetTags.get("int")); - assertEquals(String.class, lastGetTags.get("bool").getClass()); - assertEquals("true", lastGetTags.get("bool")); - - // null should be the same as a blank string. - assertFalse(lastGetTags.has("null")); - - assertFalse(lastGetTags.has("array")); - assertFalse(lastGetTags.has("object")); - } - - @Test - public void testOneSignalMethodsBeforeDuringInitMultipleThreads() throws Exception { - // Avoid logging to much - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.ERROR, OneSignal.LOG_LEVEL.NONE); - for (int a = 0; a < 10; a++) { - List threadList = new ArrayList<>(30); - for (int i = 0; i < 30; i++) { - Thread lastThread = newSendTagTestThread(Thread.currentThread(), i); - lastThread.start(); - threadList.add(lastThread); - assertFalse(failedCurModTest); - } - - for (Thread thread : threadList) - thread.join(); - assertFalse(failedCurModTest); - } - - assertEquals(30000, OneSignal_taskQueueWaitingForInit().size()); - OneSignalInit(); - - for (int a = 0; a < 10; a++) { - List threadList = new ArrayList<>(30); - for (int i = 0; i < 30; i++) { - Thread lastThread = newSendTagSetZeroThread(Thread.currentThread(), i); - lastThread.start(); - threadList.add(lastThread); - assertFalse(failedCurModTest); - } - - for (Thread thread : threadList) - thread.join(); - assertFalse(failedCurModTest); - } - - threadAndTaskWait(); - - JSONObject tags = ShadowOneSignalRestClient.lastPost.getJSONObject("tags"); - //assert the tags...which should all be 0 - for (int a = 0; a < 10; a++) { - for (int i = 0; i < 30; i++) { - assertEquals("0", tags.getString("key" + i)); - } - } - } - - private static Thread newSendTagSetZeroThread(final Thread mainThread, final int id) { - //sets all keys to "0" - return new Thread(new Runnable() { - @Override - public void run() { - try { - OneSignal.sendTags("{\"key" + id + "\": " + 0 + "}"); - } catch (Throwable t) { - // Ignore the flaky Robolectric null error. - if (t.getStackTrace()[0].getClassName().equals("org.robolectric.shadows.ShadowMessageQueue")) - return; - failedCurModTest = true; - mainThread.interrupt(); - throw t; - } - } - }); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void testOneSignalMethodsBeforeInit() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_FINE_LOCATION"); - ShadowFusedLocationApiWrapper.lat = 1.0d; - ShadowFusedLocationApiWrapper.log = 2.0d; - ShadowFusedLocationApiWrapper.accuracy = 3.0f; - ShadowFusedLocationApiWrapper.time = 12345L; - - //queue up a bunch of actions and check that the queue gains size before init - // ----- START QUEUE ------ - - for(int a = 0; a < 500; a++) { - OneSignal.sendTag("a" + a, String.valueOf(a)); - } - - OneSignal.getTags(new OneSignal.OSGetTagsHandler() { - @Override - public void tagsAvailable(JSONObject tags) { - //assert that the first 10 tags sent were available - try { - for(int a = 0; a < 10; a++) { - assertEquals(String.valueOf(a), tags.get("a" + a)); - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - }); - threadAndTaskWait(); - - // ----- END QUEUE ------ - - // There should be 501 pending operations in the queue - assertEquals(501, OneSignal_taskQueueWaitingForInit().size()); - - OneSignalInit(); //starts the pending tasks executor - - // ---- EXECUTOR STILL RUNNING ----- - //these operations should be sent straight to the executor which is still running... - OneSignal.sendTag("a499","5"); - OneSignal.sendTag("a498","4"); - OneSignal.sendTag("a497","3"); - OneSignal.sendTag("a496","2"); - OneSignal.sendTag("a495","1"); - - OneSignal.getTags(new OneSignal.OSGetTagsHandler() { - @Override - public void tagsAvailable(JSONObject tags) { - try { - //assert that the first 10 tags sent were available - for(int a = 0; a < 10; a++) { - assertEquals(String.valueOf(a),tags.get("a"+a)); - } - //these tags should be returned with new values - getTags should be the - //last operation with new tag values - assertEquals("5",tags.getString("a499")); - assertEquals("4",tags.getString("a498")); - assertEquals("3",tags.getString("a497")); - assertEquals("2",tags.getString("a496")); - assertEquals("1",tags.getString("a495")); - } - catch (Exception e) { - e.printStackTrace(); - } - } - }); - - //after init, the queue should be empty... - assertEquals(0, OneSignal_taskQueueWaitingForInit().size()); - - threadAndTaskWait(); - - //Assert that the queued up operations ran in correct order - // and that the correct user state was POSTed and synced - - assertNotNull(ShadowOneSignalRestClient.lastPost.getJSONObject("tags")); - - JSONObject tags = ShadowOneSignalRestClient.lastPost.getJSONObject("tags"); - assertEquals("0",tags.getString("a0")); - assertEquals("1",tags.getString("a1")); - assertEquals("2",tags.getString("a2")); - assertEquals("3",tags.getString("a3")); - assertEquals("4",tags.getString("a4")); - - //we changed these tags while the executor was running... - assertEquals("5",tags.getString("a499")); - assertEquals("4",tags.getString("a498")); - assertEquals("3",tags.getString("a497")); - assertEquals("2",tags.getString("a496")); - assertEquals("1",tags.getString("a495")); - } - - @Test - @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class}) - public void testOneSignalEmptyPendingTaskQueue() throws Exception { - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_FINE_LOCATION"); - ShadowFusedLocationApiWrapper.lat = 1.0d; - ShadowFusedLocationApiWrapper.log = 2.0d; - ShadowFusedLocationApiWrapper.accuracy = 3.0f; - ShadowFusedLocationApiWrapper.time = 12345L; - - OneSignalInit(); //starts the pending tasks executor - - for(int a = 0; a < 5; a++) - OneSignal.sendTag("a" + a, String.valueOf(a)); - - //the queue should be empty since we already initialized the SDK - assertEquals(0, OneSignal_taskQueueWaitingForInit().size()); - - threadAndTaskWait(); - - //Assert that the queued up operations ran in correct order - // and that the correct user state was POSTed and synced - - assertNotNull(ShadowOneSignalRestClient.lastPost.getJSONObject("tags")); - - JSONObject tags = ShadowOneSignalRestClient.lastPost.getJSONObject("tags"); - assertEquals("0", tags.getString("a0")); - assertEquals("1", tags.getString("a1")); - assertEquals("2", tags.getString("a2")); - assertEquals("3", tags.getString("a3")); - assertEquals("4", tags.getString("a4")); - } - - private static boolean failedCurModTest; - @Test - @Config(sdk = 26) - public void testSendTagsConcurrentModificationException() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - final int TOTAL_RUNS = 75, CONCURRENT_THREADS = 15; - for(int a = 0; a < TOTAL_RUNS; a++) { - List threadList = new ArrayList<>(CONCURRENT_THREADS); - for (int i = 0; i < CONCURRENT_THREADS; i++) { - Thread lastThread = newSendTagTestThread(Thread.currentThread(), a * i); - lastThread.start(); - threadList.add(lastThread); - assertFalse(failedCurModTest); - } - - OneSignalPackagePrivateHelper.runAllNetworkRunnables(); - - for(Thread thread : threadList) - thread.join(); - - assertFalse(failedCurModTest); - System.out.println("Pass " + a + " out of " + TOTAL_RUNS); - } - } - - @Test - @Config(sdk = 26) - public void testFocusConcurrentModificationException() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - final int TOTAL_RUNS = 75, CONCURRENT_THREADS = 15; - for(int a = 0; a < TOTAL_RUNS; a++) { - List threadList = new ArrayList<>(CONCURRENT_THREADS); - for (int i = 0; i < CONCURRENT_THREADS; i++) { - OneSignalPackagePrivateHelper.OneSignal_onAppLostFocus(); - Thread lastThread = newSendTagTestThread(Thread.currentThread(), a * i); - lastThread.start(); - threadList.add(lastThread); - assertFalse(failedCurModTest); - } - - OneSignalPackagePrivateHelper.runAllNetworkRunnables(); - - for(Thread thread : threadList) - thread.join(); - - assertFalse(failedCurModTest); - System.out.println("Pass " + a + " out of " + TOTAL_RUNS); - } - } - - private static Thread newSendTagTestThread(final Thread mainThread, final int id) { - return new Thread(() -> { - try { - for (int i = 0; i < 100; i++) { - if (failedCurModTest) - break; - OneSignal.sendTags("{\"key" + id + "\": " + i + "}"); - } - } catch (Throwable t) { - // Ignore the flaky Robolectric null error. - if (t.getStackTrace()[0].getClassName().equals("org.robolectric.shadows.ShadowMessageQueue")) - return; - t.printStackTrace(); - failedCurModTest = true; - mainThread.interrupt(); - throw t; - } - }); - } - - @Test - public void shouldSaveToSyncIfKilledAndSyncOnNextAppStart() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.sendTag("key", "value"); - // Pause Activity - blankActivityController.pause(); - - // Network call for android params and player create should have been made. - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - - // App closed and re-opened. - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - - // Un-synced tag should now sync. - assertEquals("value", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").getString("key")); - } - - @Test - @Config(sdk = 19) - public void shouldSyncPendingChangesFromSyncService() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.sendTag("key", "value"); - - // App is swiped away - blankActivityController.pause(); - - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - fastColdRestartApp(); - threadAndTaskWait(); - - // Tags did not get synced so SyncService should be scheduled - AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE); - ShadowAlarmManager shadowAlarmManager = shadowOf(alarmManager); - assertEquals(1, shadowAlarmManager.getScheduledAlarms().size()); - assertEquals(SyncService.class, shadowOf(shadowOf(shadowAlarmManager.getNextScheduledAlarm().operation).getSavedIntent()).getIntentClass()); - shadowAlarmManager.getScheduledAlarms().clear(); - - // Test running the service - Robolectric.buildService(SyncService.class).startCommand(0, 0); - threadAndTaskWait(); - assertEquals("value", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").getString("key")); - // Remote params are called before players call due to initWithContext call inside SyncService - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - - // Test starting app - OneSignalInit(); - threadAndTaskWait(); - - // No new changes, don't schedule another restart. - // App is swiped away - blankActivityController.pause(); - threadAndTaskWait(); - - // No Focus service should be scheduled - assertEquals(0, shadowOf(alarmManager).getScheduledAlarms().size()); - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - } - - @Test - public void shouldNotCrashIfSyncServiceIsRunBeforeInitIsDone() throws Exception { - Robolectric.buildService(SyncService.class).create().startCommand(0,0); - Robolectric.buildService(SyncJobService.class).create().get().onStartJob(null); - threadAndTaskWait(); - } - - // Only fails if you run on it's own when running locally. - // Untested on travis CI - @Test - public void syncServiceRunnableShouldWorkConcurrently() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - for(int a = 0; a < 10; a++) { - List threadList = new ArrayList<>(30); - for (int i = 0; i < 30; i++) { - Thread lastThread = newSendTagTestThread(Thread.currentThread(), i); - lastThread.start(); - threadList.add(lastThread); - Runnable syncRunable = new OneSignalPackagePrivateHelper.OneSignalSyncServiceUtils_SyncRunnable(); - new Thread(syncRunable).start(); - } - - for(Thread thread : threadList) - thread.join(); - assertFalse(failedCurModTest); - } - - threadAndTaskWait(); - } - - private void sendTagsAndImmediatelyBackgroundApp() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Set tags and background app before a network call can be made - OneSignal.sendTag("test", "value"); - blankActivityController.pause(); - } - - @Test - public void ensureSchedulingOfSyncJobServiceOnActivityPause() throws Exception { - sendTagsAndImmediatelyBackgroundApp(); - - // There should be a SyncJobService service scheduled - assertNumberOfServicesAvailable(1); - assertAndRunSyncService(); - } - - @Test - public void ensureSyncJobIsCanceledOnAppResume() throws Exception { - sendTagsAndImmediatelyBackgroundApp(); - blankActivityController.resume(); - - // Jobs should no longer be not be scheduled - assertNull(getNextJob()); - } - - @Test - public void ensureSyncIsRunOnAppResume() throws Exception { - sendTagsAndImmediatelyBackgroundApp(); - blankActivityController.resume(); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - ShadowOneSignalRestClient.Request lastRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(REST_METHOD.PUT, lastRequest.method); - assertEquals("value", lastRequest.payload.getJSONObject("tags").get("test")); - } - - @Test - @Config(sdk = 26) - public void ensureNoConcurrentUpdateCallsWithSameData() throws Exception { - sendTagsAndImmediatelyBackgroundApp(); - - // Simulate a hung network connection when SyncJobService starts. - ShadowOneSignalRestClient.freezeResponses = true; - SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get(); - syncJobService.onStartJob(null); - threadAndTaskWait(); // Kicks off the Job service's background thread. - - // App is resumed, the SyncJobService is still waiting on a network response at this point. - blankActivityController.resume(); - threadAndTaskWait(); - - // Should only be 3 requests if there are no duplicates - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - } - - @Test - @Config(sdk = 26, shadows = { ShadowGoogleApiClientCompatProxy.class, ShadowGMSLocationController.class }) - public void ensureSyncJobServiceRescheduleOnApiTimeout() throws Exception { - ShadowGMSLocationController.apiFallbackTime = 0; - shadowOf(RuntimeEnvironment.application).grantPermissions("android.permission.ACCESS_FINE_LOCATION"); - ShadowGoogleApiClientCompatProxy.skipOnConnected = true; - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals("com.onesignal.SyncJobService", getNextJob().getService().getClassName()); - } - - private void useAppFor2minThenBackground() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - // 1. Start app - OneSignalInit(); - threadAndTaskWait(); - - // 2. Wait 2 minutes - time.advanceSystemAndElapsedTimeBy(2 * 60); - - // 3. Put app in background - pauseActivity(blankActivityController); - - // 4. A SyncService should have been scheduled - assertAndRunSyncService(); - } - - @Test - @Config(sdk = 26) - public void ensureSchedulingOfSyncJobServiceOnActivityPause_forPendingActiveTime() throws Exception { - useAppFor2minThenBackground(); - - // There should be a SyncJobService service scheduled - assertNumberOfServicesAvailable(1); - // A future job should be scheduled to finish the sync in case the process is killed - // for the on_focus call can be made. - assertNextJob(SyncJobService.class, 0); - - // FIXME: Cleanup for upcoming unit test - // This is a one off scenario where a unit test fails after this one is run - blankActivityController.resume(); - threadAndTaskWait(); - } - - @Test - public void ensureSyncIsRunOnAppResume_forPendingActiveTime() throws Exception { - useAppFor2minThenBackground(); - - blankActivityController.resume(); - threadAndTaskWait(); - - assertRestCalls(3); - assertOnFocusAtIndex(2, 120); - } - - @Test - @Config(sdk = 26) - public void ensureFailureOnPauseIsSentFromSyncService_forPendingActiveTime() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - // 1. Start app - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - threadAndTaskWait(); - - // 2. Wait 2 minutes - time.advanceSystemAndElapsedTimeBy(2 * 60); - - // 3. Put app in background, simulating network issue. - ShadowOneSignalRestClient.failAll = true; - pauseActivity(blankActivityController); - - assertAndRunSyncService(); - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - - // Simulate a hung network connection when SyncJobService starts. - ShadowOneSignalRestClient.failAll = false; - SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get(); - syncJobService.onStartJob(null); - threadAndTaskWait(); // Kicks off the Job service's background thread. - - assertRestCalls(4); - assertOnFocusAtIndex(3, 120); - -// // FIXME: Cleanup for upcoming unit test -// // This is a one off scenario where a unit test fails after this one is run -// blankActivityController.resume(); -// threadAndTaskWait(); - } - - @Test - public void ensureNoRetriesForAndroidParamsOn403() throws Exception { - ShadowOneSignalRestClient.failGetParams = true; - ShadowOneSignalRestClient.failHttpCode = 403; - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(1, ShadowOneSignalRestClient.requests.size()); - } - - @Test - public void ensureNoRetriesForPlayerUpdatesOn403() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.failAll = true; - ShadowOneSignalRestClient.failHttpCode = 403; - OneSignal.sendTag("key", "value"); - threadAndTaskWait(); - - // 1. Android Param success. 2. player create success. 3. On call to update which fails without retrying. - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - } - - @Test - @Config(sdk = 26) - public void ensureNoConcurrentUpdateCallsWithSameData_forPendingActiveTime() throws Exception { - // useAppFor2minThenBackground(); - time.advanceSystemAndElapsedTimeBy(0); - // 1. Start app - OneSignalInit(); - threadAndTaskWait(); - - // 2. Wait 2 minutes - time.advanceSystemAndElapsedTimeBy(2 * 60); - - // 3. Put app in background - ShadowOneSignalRestClient.freezeResponses = true; - pauseActivity(blankActivityController); - - // 4. Simulate a hung network connection when SyncJobService starts. - SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get(); - syncJobService.onStartJob(null); - threadAndTaskWait(); // Kicks off the Job service's background thread. - - // 5. App is resumed, the SyncJobService is still waiting on a network response at this point. - blankActivityController.resume(); - threadAndTaskWait(); - - // 6. Network connection now responding - ShadowOneSignalRestClient.unFreezeResponses(); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.requests.size()); - } - - @Test - public void testMethodCalls_withSetAppIdCalledBeforeMethodCalls() throws Exception { - OneSignal.setAppId(ONESIGNAL_APP_ID); - - getGetTagsHandler(); - OneSignal.sendTag("key", "value"); - OneSignal.sendTags("{\"key\": \"value\"}"); - OneSignal.deleteTag("key"); - OneSignal.deleteTags("[\"key1\", \"key2\"]"); - OneSignal.disablePush(false); - OneSignal.promptLocation(); - OneSignal.postNotification("{}", new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) {} - @Override - public void onFailure(JSONObject response) {} - }); - OneSignal.setNotificationOpenedHandler(null); - OneSignal.setNotificationWillShowInForegroundHandler(null); - threadAndTaskWait(); - - // Permission subscription wont return until OneSignal init is done - assertNull(OneSignal.getDeviceState()); - - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - assertTrue(OneSignal.getDeviceState().isSubscribed()); - } - - @Test - public void testMethodCalls_withInitWithContextCalledBeforeMethodCalls() throws Exception { - OneSignal.initWithContext(blankActivity); - - getGetTagsHandler(); - OneSignal.sendTag("key", "value"); - OneSignal.sendTags("{\"key\": \"value\"}"); - OneSignal.deleteTag("key"); - OneSignal.deleteTags("[\"key1\", \"key2\"]"); - OneSignal.disablePush(false); - OneSignal.promptLocation(); - OneSignal.postNotification("{}", new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) {} - @Override - public void onFailure(JSONObject response) {} - }); - OneSignal.setNotificationOpenedHandler(null); - OneSignal.setNotificationWillShowInForegroundHandler(null); - threadAndTaskWait(); - - // TODO change to assertNull(OneSignal.getPermissionSubscriptionState()); when privacy consent public set is removed - assertFalse(OneSignal.getDeviceState().isSubscribed()); - - OneSignal.setAppId(ONESIGNAL_APP_ID); - threadAndTaskWait(); - - assertTrue(OneSignal.getDeviceState().isSubscribed()); - } - - @Test - public void testMethodCalls_withInitWithContextAndSetAppId() throws Exception { - getGetTagsHandler(); - OneSignal.sendTag("key", "value"); - OneSignal.sendTags("{\"key\": \"value\"}"); - OneSignal.deleteTag("key"); - OneSignal.deleteTags("[\"key1\", \"key2\"]"); - OneSignal.disablePush(false); - OneSignal.promptLocation(); - OneSignal.postNotification("{}", new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) {} - @Override - public void onFailure(JSONObject response) {} - }); - OneSignal.setNotificationOpenedHandler(null); - OneSignal.setNotificationWillShowInForegroundHandler(null); - threadAndTaskWait(); - - assertNull(OneSignal.getDeviceState()); - - OneSignal.initWithContext(blankActivity); - OneSignal.setAppId(ONESIGNAL_APP_ID); - threadAndTaskWait(); - - assertTrue(OneSignal.getDeviceState().isSubscribed()); - } - - @Test - public void testMethodCalls_withSetAppIdAndInitWithContext() throws Exception { - getGetTagsHandler(); - OneSignal.sendTag("key", "value"); - OneSignal.sendTags("{\"key\": \"value\"}"); - OneSignal.deleteTag("key"); - OneSignal.deleteTags("[\"key1\", \"key2\"]"); - OneSignal.disablePush(false); - OneSignal.promptLocation(); - OneSignal.postNotification("{}", new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) {} - @Override - public void onFailure(JSONObject response) {} - }); - OneSignal.setNotificationOpenedHandler(null); - OneSignal.setNotificationWillShowInForegroundHandler(null); - threadAndTaskWait(); - - assertNull(OneSignal.getDeviceState()); - - OneSignal.initWithContext(blankActivity); - OneSignal.setAppId(ONESIGNAL_APP_ID); - threadAndTaskWait(); - - assertTrue(OneSignal.getDeviceState().isSubscribed()); - } - - // ####### DeleteTags Tests ###### - @Test - public void testDeleteTagWithNonexistingKey() { - OneSignalInit(); - OneSignal.deleteTag("int"); - } - - @Test - public void testDeleteTags() throws Exception { - OneSignalInit(); - OneSignal.sendTags("{\"str\": \"str1\", \"int\": 122, \"bool\": true}"); - OneSignal.deleteTag("int"); - getGetTagsHandler(); - threadAndTaskWait(); - - assertFalse(lastGetTags.has("int")); - lastGetTags = null; - - // Should only send the tag we added back. - OneSignal.sendTags("{\"str\": \"str1\", \"int\": 122, \"bool\": true}"); - threadAndTaskWait(); - assertEquals("{\"int\":\"122\"}", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").toString()); - - // Make sure a single delete works. - OneSignal.deleteTag("int"); - getGetTagsHandler(); - threadAndTaskWait(); - assertFalse(lastGetTags.has("int")); - - // Delete all other tags, the 'tags' key should not exists in local storage. - OneSignal.deleteTags(Arrays.asList("bool", "str")); - threadAndTaskWait(); - - flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - String syncValues = prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null); - assertFalse(new JSONObject(syncValues).has("tags")); - } - - - @Test - public void testDeleteTagsAfterSync() throws Exception { - OneSignalInit(); - OneSignal.sendTags("{\"foo\": \"bar\", \"fuz\": \"baz\"}"); - threadAndTaskWait(); - assertEquals("bar", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").get("foo")); - assertEquals("baz", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").get("fuz")); - - OneSignal.deleteTags("[\"foo\", \"fuz\"]"); - threadAndTaskWait(); - assertEquals("", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").get("foo")); - assertEquals("", ShadowOneSignalRestClient.lastPost.getJSONObject("tags").get("fuz")); - - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals("{}", lastGetTags.toString()); - - flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - JSONObject syncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - assertFalse(syncValues.has("tags")); - } - - @Test - public void testOmitDeletesOfNonExistingKeys() throws Exception { - OneSignalInit(); - OneSignal.deleteTag("this_key_does_not_exist"); - threadAndTaskWait(); - - assertFalse(ShadowOneSignalRestClient.lastPost.has("tags")); - } - - // ####### End DeleteTags Tests ###### - // ####### GetTags Tests ######## - - @Test - public void testGetTagsWithNoTagsShouldBeNull() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - getGetTagsHandler(); - threadAndTaskWait(); - - assertNull(lastGetTags); - String lastUrl = ShadowOneSignalRestClient.lastUrl; - assertEquals("?app_id=" + ONESIGNAL_APP_ID, lastUrl.substring(lastUrl.lastIndexOf("?"))); - } - - @Test - public void testGetTagNullCheck() throws Exception { - OneSignalInit(); - OneSignal.getTags(null); - } - - @Test - public void shouldGetTags() throws Exception { - OneSignalInit(); - OneSignal.sendTags(new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}")); - threadAndTaskWait(); - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals("value1", lastGetTags.getString("test1")); - assertEquals("value2", lastGetTags.getString("test2")); - } - - @Test - public void shouldGetTagsFromServerOnFirstCallAndMergeLocalAndRemote() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.setNextSuccessfulGETJSONResponse(new JSONObject() {{ - put("tags", new JSONObject() {{ - put("test1", "value1"); - put("test2", "value2"); - }}); - }}); - - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - assertEquals("value1", lastGetTags.getString("test1")); - assertEquals("value2", lastGetTags.getString("test2")); - - // Makes sure a 2nd call to GetTags correctly uses existing tags and merges new local changes. - lastGetTags = null; - OneSignal.sendTag("test3", "value3"); - getGetTagsHandler(); - threadAndTaskWait(); - assertEquals("value1", lastGetTags.getString("test1")); - assertEquals("value2", lastGetTags.getString("test2")); - assertEquals("value3", lastGetTags.getString("test3")); - threadAndTaskWait(); - // Also ensure only 1 network call is made to just send the new tags only. - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - - // Test that local pending changes are still applied but new changes made server side a respected. - lastGetTags = null; - ShadowOneSignalRestClient.failNextPut = true; - OneSignal.deleteTag("test2"); - OneSignal.sendTag("test4", "value4"); - ShadowOneSignalRestClient.setNextSuccessfulGETJSONResponse(new JSONObject() {{ - put("tags", new JSONObject() {{ - put("test1", "value1"); - put("test2", "value2"); - put("test3", "ShouldOverride"); - put("test4", "RemoteShouldNotOverwriteLocalPending"); - }}); - }}); - getGetTagsHandler(); - threadAndTaskWait(); - assertEquals("value1", lastGetTags.getString("test1")); - System.out.println("lastGetTags: " + lastGetTags); - assertFalse(lastGetTags.has("test2")); - assertEquals("ShouldOverride", lastGetTags.getString("test3")); - assertEquals("value4", lastGetTags.getString("test4")); - assertEquals(8, ShadowOneSignalRestClient.networkCallCount); - - assertEquals("{\"test2\":\"\",\"test4\":\"value4\"}", - ShadowOneSignalRestClient.lastPost.optJSONObject("tags").toString()); - } - - @Test - public void getTagsDelayedAfterRegistering() throws Exception { - // Set players GET response - ShadowOneSignalRestClient.setNextSuccessfulGETJSONResponse(new JSONObject() {{ - put("tags", new JSONObject() {{ - put("test1", "value1"); - }}); - }}); - ShadowOneSignalRestClient.nextSuccessfulGETResponsePattern = Pattern.compile("players/.*"); - OneSignalInit(); - // need to wait for remote_params call -> privacy consent set to false - threadAndTaskWait(); - getGetTagsHandler(); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - assertEquals("value1", lastGetTags.getString("test1")); - assertTrue(ShadowOneSignalRestClient.lastUrl.contains(ShadowOneSignalRestClient.pushUserId)); - } - - // ####### End GetTags Tests ######## - - @Test - public void testSetLanguageOnPlayerCreate() throws Exception { - OneSignalInit(); - OneSignal.setLanguage("fr"); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request lastRequest = ShadowOneSignalRestClient.requests.get(1); - - assertEquals("fr", lastRequest.payload.getString("language")); - } - - @Test - public void testSetLanguagePUTRequest() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - OneSignal.setLanguage("fr"); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request lastRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals("fr", lastRequest.payload.getString("language")); - } - - @Test - public void testSetLanguageOnSession() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - - OneSignalInit(); - OneSignal.setLanguage("fr"); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request lastRequest = ShadowOneSignalRestClient.requests.get(3); - assertEquals("fr", lastRequest.payload.getString("language")); - } - - private static class TestSetLanguageHandler implements OSSetLanguageCompletionHandler { - private AtomicBoolean succeeded = new AtomicBoolean(false); - private AtomicBoolean failed = new AtomicBoolean(false); - - @Override - public void onSuccess(String results) { succeeded.set(true); } - - @Override - public void onFailure(OSLanguageError error) { failed.set(true); } - - boolean getSucceeded() { return succeeded.get(); } - - boolean getFailed() { return failed.get(); } - } - - // Tests to make sure the onSuccess handler works - @Test - public void shouldSetLanguageWithResponse() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - TestSetLanguageHandler handler = new TestSetLanguageHandler(); - - OneSignal.setLanguage("fr", handler); - - threadAndTaskWait(); - - assertTrue(handler.getSucceeded()); - - // now test to make sure the handler still fires for a call to - // setLanguage() that modifies existing language - - handler = new TestSetLanguageHandler(); - - OneSignal.setLanguage("es", handler); - - threadAndTaskWait(); - - assertTrue(handler.getSucceeded()); - } - - // Tests to make sure that the onFailure callback works - @Test - public void shouldFailToSetLanguageWithResponse() throws Exception { - TestSetLanguageHandler handler = new TestSetLanguageHandler(); - - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.failMethod = "players"; - ShadowOneSignalRestClient.failHttpCode = 403; - ShadowOneSignalRestClient.setNextFailureJSONResponse(new JSONObject() {{ - put("tags", "error"); - }}); - - // Should fail because players call failed with tags - OneSignal.setLanguage("fr", handler); - threadAndTaskWait(); - - assertTrue(handler.getFailed()); - } - - /** - * Similar workflow to testLocationPermissionPromptWithPrivacyConsent() - * We want to provide consent but make sure that session time tracking works properly - */ - @Test - @Config(sdk = 26) - public void testSessionTimeTrackingOnPrivacyConsent() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - threadAndTaskWait(); - - // Provide consent to OneSignal SDK amd forward time 2 minutes - OneSignal.provideUserConsent(true); - // TODO: This passed without a resume here, why? - blankActivityController.resume(); - - time.advanceSystemAndElapsedTimeBy(2 * 60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - // Check that time is tracked successfully by validating the "on_focus" endpoint - assertRestCalls(3); - assertOnFocusAtIndex(2, 120); - } - - @Test - public void gdprUserConsent() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - assertTrue(OneSignalPackagePrivateHelper.OneSignal_requiresUserPrivacyConsent()); - - //privacy consent state should still be set to true (user consent required) - OneSignalInit(); - threadAndTaskWait(); - - //the delayed params should now be set - assertNotNull(OneSignalPackagePrivateHelper.OneSignal_delayedInitParams()); - assertNull(OneSignalPackagePrivateHelper.OneSignal_appId()); - - //test to make sure methods, such as PostNotification, don't execute without user consent - OneSignal.PostNotificationResponseHandler handler = new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) { - postNotificationSuccess = response; - } - - @Override - public void onFailure(JSONObject response) { - postNotificationFailure = response; - } - }; - - OneSignal.postNotification("{}", handler); - threadAndTaskWait(); - assertNull(postNotificationSuccess); - assertNull(postNotificationFailure); - postNotificationSuccess = postNotificationFailure = null; - - OneSignal.provideUserConsent(true); - - assertNull(OneSignalPackagePrivateHelper.OneSignal_delayedInitParams()); - assertNotNull(OneSignalPackagePrivateHelper.OneSignal_appId()); - - // Not testing input here, just that HTTP 200 fires a success. - OneSignal.postNotification("{}", handler); - threadAndTaskWait(); - assertNotNull(postNotificationSuccess); - assertNull(postNotificationFailure); - postNotificationSuccess = postNotificationFailure = null; - } - - @Test - public void gdprRevokeUserConsent() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - - //privacy consent state should still be set to true (user consent required) - OneSignalInit(); - - OneSignal.provideUserConsent(true); - - threadAndTaskWait(); - - OneSignal.provideUserConsent(false); - - threadAndTaskWait(); - - //test to make sure methods, such as PostNotification, don't execute without user consent - OneSignal.PostNotificationResponseHandler handler = new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) { - postNotificationSuccess = response; - } - - @Override - public void onFailure(JSONObject response) { - postNotificationFailure = response; - } - }; - - OneSignal.postNotification("{}", handler); - threadAndTaskWait(); - assertNull(postNotificationSuccess); - assertNull(postNotificationFailure); - postNotificationSuccess = postNotificationFailure = null; - } - - @Test - public void shouldReturnCorrectConsentRequiredStatus() throws JSONException { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - - OneSignalInit(); - - assertTrue(OneSignal.requiresUserPrivacyConsent()); - - OneSignal.provideUserConsent(true); - - assertFalse(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void shouldReturnCorrectConsentRequiredStatusWhenSetBeforeInit() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignal.provideUserConsent(true); - OneSignalInit(); - threadAndTaskWait(); - - assertTrue(OneSignal.userProvidedPrivacyConsent()); - - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - - assertTrue(OneSignal.userProvidedPrivacyConsent()); - } - - // Functions to add observers (like addSubscriptionObserver) should continue - // to work even if privacy consent has not been granted. - @Test - public void shouldAddSubscriptionObserverIfConsentNotGranted() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignalInit(); - threadAndTaskWait(); - - OSSubscriptionObserver subscriptionObserver = stateChanges -> { - lastSubscriptionStateChanges = stateChanges; - currentSubscription = stateChanges.getTo().isSubscribed(); - }; - OneSignal.addSubscriptionObserver(subscriptionObserver); - lastSubscriptionStateChanges = null; - // Make sure garbage collection doesn't nuke any observers. - Runtime.getRuntime().gc(); - - OneSignal.provideUserConsent(true); - threadAndTaskWait(); - - // make sure the subscription observer was fired - assertTrue(lastSubscriptionStateChanges.getTo().isSubscribed()); - assertFalse(lastSubscriptionStateChanges.getFrom().isSubscribed()); - } - - @Test - public void shouldAddPermissionObserverIfConsentNotGranted() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignalInit(); - threadAndTaskWait(); - - OSPermissionObserver permissionObserver = new OSPermissionObserver() { - @Override - public void onOSPermissionChanged(OSPermissionStateChanges stateChanges) { - lastPermissionStateChanges = stateChanges; - currentPermission = stateChanges.getTo().areNotificationsEnabled(); - } - }; - OneSignal.addPermissionObserver(permissionObserver); - - OneSignal.provideUserConsent(true); - threadAndTaskWait(); - - // make sure the permission observer was fired - assertFalse(lastPermissionStateChanges.getFrom().areNotificationsEnabled()); - assertTrue(lastPermissionStateChanges.getTo().areNotificationsEnabled()); - } - - @Test - public void shouldAddEmailSubscriptionObserverIfConsentNotGranted() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignalInit(); - OSEmailSubscriptionObserver subscriptionObserver = new OSEmailSubscriptionObserver() { - @Override - public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateChanges) { - lastEmailSubscriptionStateChanges = stateChanges; - } - }; - OneSignal.addEmailSubscriptionObserver(subscriptionObserver); - - OneSignal.provideUserConsent(true); - threadAndTaskWait(); - - String email = "josh@onesignal.com"; - OneSignal.setEmail(email); - threadAndTaskWait(); - - // make sure the email subscription observer was fired - assertEquals(email, lastEmailSubscriptionStateChanges.getFrom().getEmailAddress()); - assertNull(lastEmailSubscriptionStateChanges.getFrom().getEmailUserId()); - assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", lastEmailSubscriptionStateChanges.getTo().getEmailUserId()); - assertEquals(email, lastEmailSubscriptionStateChanges.getTo().getEmailAddress()); - assertTrue(lastEmailSubscriptionStateChanges.getTo().isSubscribed()); - } - - @Test - public void shouldAddSMSSubscriptionObserverIfConsentNotGranted() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignalInit(); - threadAndTaskWait(); - - OSSMSSubscriptionObserver subscriptionObserver = stateChanges -> lastSMSSubscriptionStateChanges = stateChanges; - OneSignal.addSMSSubscriptionObserver(subscriptionObserver); - - OneSignal.provideUserConsent(true); - threadAndTaskWait(); - - assertNull(lastSMSSubscriptionStateChanges); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // make sure the sms subscription observer was fired - assertEquals(ONESIGNAL_SMS_NUMBER, lastSMSSubscriptionStateChanges.getFrom().getSMSNumber()); - assertNull(lastSMSSubscriptionStateChanges.getFrom().getSmsUserId()); - assertFalse(lastSMSSubscriptionStateChanges.getFrom().isSubscribed()); - assertEquals(ShadowOneSignalRestClient.smsUserId, lastSMSSubscriptionStateChanges.getTo().getSmsUserId()); - assertEquals(ONESIGNAL_SMS_NUMBER, lastSMSSubscriptionStateChanges.getTo().getSMSNumber()); - assertTrue(lastSMSSubscriptionStateChanges.getTo().isSubscribed()); - } - - /* - // Can't get test to work from a app flow due to the main thread being locked one way or another in a robolectric env. - // Running ActivityLifecycleListener.focusHandlerThread...advanceToNextPostedRunnable waits on the main thread. - // If it is put in its own thread then synchronized that is run when messages a runnable is added / removed hangs the main thread here too. - @Test - public void shouldNotDoubleCountFocusTime() throws Exception { - System.out.println("TEST IS RUNNING ONE THREAD: " + Thread.currentThread()); - - // Start app normally - OneSignalInit(); - threadAndTaskWait(); - - // Press home button after 30 sec - blankActivityController.resume(); - advanceSystemTimeBy(30 * 1_000L); - blankActivityController.pause(); - threadAndTaskWait(); - - // Press home button after 30 more sec, with a network hang - blankActivityController.resume(); - advanceSystemTimeBy(60 * 1_000L); - ShadowOneSignalRestClient.interruptibleDelayNext = true; - blankActivityController.pause(); - System.out.println("HERE1"); - threadAndTaskWait(); - System.out.println("HERE2" + Thread.currentThread()); - - // Open app and press home button again right away. - blankActivityController.resume(); - System.out.println("HERE3: " + Thread.currentThread()); - blankActivityController.pause(); - System.out.println("HERE4"); - threadAndTaskWait(); - System.out.println("HERE5"); - - ShadowOneSignalRestClient.interruptHTTPDelay(); - System.out.println("HERE6"); - - threadWait(); - System.out.println("ShadowOneSignalRestClient.lastPost: " + ShadowOneSignalRestClient.lastPost); - System.out.println("ShadowOneSignalRestClient.networkCallCount: " + ShadowOneSignalRestClient.networkCallCount); - - assertEquals(60, ShadowOneSignalRestClient.lastPost.getInt("active_time")); - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - } - */ - - // ####### Unit test postNotification ##### - - private static JSONObject postNotificationSuccess = null, postNotificationFailure = null; - - @Test - public void testPostNotification() throws Exception { - OneSignalInit(); - - OneSignal.PostNotificationResponseHandler handler = new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) { - postNotificationSuccess = response; - } - - @Override - public void onFailure(JSONObject response) { - postNotificationFailure = response; - } - }; - - // Not testing input here, just that HTTP 200 fires a success. - OneSignal.postNotification("{}", handler); - threadAndTaskWait(); - assertNotNull(postNotificationSuccess); - assertNull(postNotificationFailure); - postNotificationSuccess = postNotificationFailure = null; - - ShadowOneSignalRestClient.setNextSuccessfulJSONResponse(new JSONObject() {{ - put("id", ""); - put("recipients", 0); - put("errors", new JSONArray() {{ - put("All included players are not subscribed"); - }}); - }}); - - OneSignal.postNotification("{}", handler); - assertNull(postNotificationSuccess); - assertNotNull(postNotificationFailure); - } - - @Test - @Config(shadows = { ShadowRoboNotificationManager.class, ShadowBadgeCountUpdater.class, ShadowGenerateNotification.class }) - public void shouldCancelAndClearNotifications() throws Exception { - ShadowRoboNotificationManager.notifications.clear(); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - threadAndTaskWait(); - - // Create 2 notifications - Bundle bundle = getBaseNotifBundle(); - OneSignalPackagePrivateHelper.NotificationBundleProcessor_ProcessFromFCMIntentService(blankActivity, bundle); - bundle = getBaseNotifBundle("UUID2"); - OneSignalPackagePrivateHelper.NotificationBundleProcessor_ProcessFromFCMIntentService(blankActivity, bundle); - threadAndTaskWait(); - - // Test canceling - Map postedNotifs = ShadowRoboNotificationManager.notifications; - Iterator> postedNotifsIterator = postedNotifs.entrySet().iterator(); - ShadowRoboNotificationManager.PostedNotification postedNotification = postedNotifsIterator.next().getValue(); - - OneSignal.removeNotification(postedNotification.id); - threadAndTaskWait(); - assertEquals(1, ShadowBadgeCountUpdater.lastCount); - assertEquals(1, ShadowRoboNotificationManager.notifications.size()); - - OneSignal.clearOneSignalNotifications(); - threadAndTaskWait(); - assertEquals(0, ShadowBadgeCountUpdater.lastCount); - assertEquals(0, ShadowRoboNotificationManager.notifications.size()); - - // Make sure they are marked dismissed. - Cursor cursor = dbHelper.query(OneSignalPackagePrivateHelper.NotificationTable.TABLE_NAME, new String[] { "created_time" }, - OneSignalPackagePrivateHelper.NotificationTable.COLUMN_NAME_DISMISSED + " = 1", null, null, null, null); - assertEquals(2, cursor.getCount()); - cursor.close(); - } - - // ####### Unit test toJSONObject methods - @Test - public void testOSNotificationToJSONObject() throws Exception { - OSNotification osNotification = createTestOSNotification(); - - JSONObject testJsonObj = osNotification.toJSONObject(); - - assertEquals("msg_body", testJsonObj.optString("body")); - JSONObject firstActionButton = (JSONObject)testJsonObj.optJSONArray("actionButtons").get(0); - assertEquals("text", firstActionButton.optString("text")); - - JSONObject additionalData = testJsonObj.optJSONObject("additionalData"); - assertEquals("bar", additionalData.optString("foo")); - } - - @Test - public void testOSNotificationOpenResultToJSONObject() throws Exception { - OSNotificationAction action = new OSNotificationAction(OSNotificationAction.ActionType.Opened, null); - OSNotificationOpenedResult osNotificationOpenedResult = new OSNotificationOpenedResult(createTestOSNotification(), action); - - JSONObject testJsonObj = osNotificationOpenedResult.toJSONObject(); - - JSONObject additionalData = testJsonObj.optJSONObject("notification").optJSONObject("additionalData"); - assertEquals("bar", additionalData.optString("foo")); - - JSONObject firstGroupedNotification = (JSONObject)testJsonObj.optJSONObject("notification").optJSONArray("groupedNotifications").get(0); - assertEquals("collapseId1", firstGroupedNotification.optString("collapseId")); - } - - // ####### Unit test JSONUtils methods - @Test - public void test_JSONUtils_toUnescapedEUIDString() throws Exception { - // 1. Test when EUID is first in the json, and has ($) and (/), and ($) elsewhere - - // Set up the JSONObject to test with - String jsonStringWithDollarAndSlash = "{" + - "\"external_user_id\":\"$1$/abc/de$f/\"," + - "\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"," + - "\"timezone\":\"$Europe/London\"" + - "}"; - JSONObject jsonWithDollarAndSlash = new JSONObject(jsonStringWithDollarAndSlash); - - // The expected string which escapes the "timezone" slash (/) only - String expected_jsonStringWithDollarAndSlash = "{" + - "\"external_user_id\":\"$1$/abc/de$f/\"," + - "\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"," + - "\"timezone\":\"$Europe\\/London\"" + - "}"; - - // The actual string result from calling JSONUtils.toUnescapedEUIDString() - String actual_jsonStringWithDollarAndSlash = toUnescapedEUIDString(jsonWithDollarAndSlash); - - // These two strings should be equal - assertEquals(expected_jsonStringWithDollarAndSlash, actual_jsonStringWithDollarAndSlash); - - // 2. Test when EUID is first in the json, and has no dollar nor slash - - String jsonStringWithEUID = "{" + - "\"external_user_id\":\"123abc\"," + - "\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"," + - "\"timezone\":\"$Europe/London\"" + - "}"; - JSONObject jsonWithEUID = new JSONObject(jsonStringWithEUID); - - String expected_jsonStringWithEUID = "{" + - "\"external_user_id\":\"123abc\"," + - "\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"," + - "\"timezone\":\"$Europe\\/London\"" + - "}"; - - String actual_jsonStringWithEUID = toUnescapedEUIDString(jsonWithEUID); - - assertEquals(expected_jsonStringWithEUID, actual_jsonStringWithEUID); - - // 3. Test when there is no EUID is in the json - - String jsonStringWithoutEUID = "{" + - "\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"," + - "\"timezone\":\"Europe/London\"" + - "}"; - JSONObject jsonWithoutEUID = new JSONObject(jsonStringWithoutEUID); - - String expected_jsonStringWithoutEUID = "{" + - "\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\"," + - "\"timezone\":\"Europe\\/London\"" + - "}"; - - String actual_jsonStringWithoutEUID = toUnescapedEUIDString(jsonWithoutEUID); - - assertEquals(expected_jsonStringWithoutEUID, actual_jsonStringWithoutEUID); - } - - @Test - public void testNotificationOpenedProcessorHandlesEmptyIntent() { - NotificationOpenedProcessor_processFromContext(blankActivity, new Intent()); - } - - @Test - public void shouldHandleChromeNullNewSession() throws Exception { - ShadowCustomTabsClient.nullNewSession = true; - OneSignalInit(); - threadAndTaskWait(); - } - - private OSPermissionStateChanges lastPermissionStateChanges; - private boolean currentPermission; - // Firing right away to match iOS behavior for wrapper SDKs. - @Test - public void shouldFirePermissionObserverOnFirstAdd() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OSPermissionObserver permissionObserver = new OSPermissionObserver() { - @Override - public void onOSPermissionChanged(OSPermissionStateChanges stateChanges) { - lastPermissionStateChanges = stateChanges; - currentPermission = stateChanges.getTo().areNotificationsEnabled(); - } - }; - OneSignal.addPermissionObserver(permissionObserver); - - assertFalse(lastPermissionStateChanges.getFrom().areNotificationsEnabled()); - assertTrue(lastPermissionStateChanges.getTo().areNotificationsEnabled()); - // Test to make sure object was correct at the time of firing. - assertTrue(currentPermission); - } - - @Test - public void shouldFirePermissionObserverWhenUserDisablesNotifications() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject() - .put("unsubscribe_on_notifications_disabled", false) - ); - OneSignalInit(); - threadAndTaskWait(); - - OSPermissionObserver permissionObserver = stateChanges -> { - lastPermissionStateChanges = stateChanges; - currentPermission = stateChanges.getTo().areNotificationsEnabled(); - }; - OneSignal.addPermissionObserver(permissionObserver); - lastPermissionStateChanges = null; - // Make sure garbage collection doesn't nuke any observers. - Runtime.getRuntime().gc(); - - stopActivity(blankActivityController); - ShadowNotificationManagerCompat.enabled = false; - blankActivityController.resume(); - - assertTrue(lastPermissionStateChanges.getFrom().areNotificationsEnabled()); - assertFalse(lastPermissionStateChanges.getTo().areNotificationsEnabled()); - // Test to make sure object was correct at the time of firing. - assertFalse(currentPermission); - // unsubscribeWhenNotificationsAreDisabled is not set so don't send notification_types. - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - } - - @Test - public void shouldSetNotificationTypesToZeroWhenUnsubscribeWhenNotificationsAreDisabledIsEnabled() throws Exception { - ShadowNotificationManagerCompat.enabled = false; - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject() - .put("unsubscribe_on_notifications_disabled", true) - ); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - assertEquals(0, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - - pauseActivity(blankActivityController); - ShadowNotificationManagerCompat.enabled = true; - blankActivityController.resume(); - threadAndTaskWait(); - assertEquals(1, ShadowOneSignalRestClient.lastPost.getInt("notification_types")); - } - - @Test - @Config(shadows = {ShadowBadgeCountUpdater.class}) - public void shouldClearBadgesWhenPermissionIsDisabled() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - ShadowBadgeCountUpdater.lastCount = 1; - - pauseActivity(blankActivityController); - ShadowNotificationManagerCompat.enabled = false; - blankActivityController.resume(); - threadAndTaskWait(); - - assertEquals(0, ShadowBadgeCountUpdater.lastCount); - } - - private OSSubscriptionStateChanges lastSubscriptionStateChanges; - private boolean currentSubscription; - @Test - public void shouldFireSubscriptionObserverOnFirstAdd() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OSSubscriptionObserver permissionObserver = new OSSubscriptionObserver() { - @Override - public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) { - lastSubscriptionStateChanges = stateChanges; - currentSubscription = stateChanges.getTo().isSubscribed(); - } - }; - OneSignal.addSubscriptionObserver(permissionObserver); - - assertFalse(lastSubscriptionStateChanges.getFrom().isSubscribed()); - assertTrue(lastSubscriptionStateChanges.getTo().isSubscribed()); - // Test to make sure object was correct at the time of firing. - assertTrue(currentSubscription); - } - - @Test - public void shouldFireSubscriptionObserverWhenUserDisablesNotifications() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject() - .put("unsubscribe_on_notifications_disabled", false) - ); - OneSignalInit(); - threadAndTaskWait(); - - OSSubscriptionObserver subscriptionObserver = new OSSubscriptionObserver() { - @Override - public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) { - lastSubscriptionStateChanges = stateChanges; - currentSubscription = stateChanges.getTo().isSubscribed(); - } - }; - OneSignal.addSubscriptionObserver(subscriptionObserver); - lastSubscriptionStateChanges = null; - // Make sure garbage collection doesn't nuke any observers. - Runtime.getRuntime().gc(); - - pauseActivity(blankActivityController); - ShadowNotificationManagerCompat.enabled = false; - blankActivityController.resume(); - threadAndTaskWait(); - - assertTrue(lastSubscriptionStateChanges.getFrom().isSubscribed()); - assertFalse(lastSubscriptionStateChanges.getTo().isSubscribed()); - // Test to make sure object was correct at the time of firing. - assertFalse(currentSubscription); - // unsubscribeWhenNotificationsAreDisabled is not set so don't send notification_types. - assertFalse(ShadowOneSignalRestClient.lastPost.has("notification_types")); - } - - @Test - public void shouldFireSubscriptionObserverWhenChangesHappen() throws Exception { - OneSignalInit(); - OSSubscriptionObserver permissionObserver = new OSSubscriptionObserver() { - @Override - public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) { - lastSubscriptionStateChanges = stateChanges; - currentSubscription = stateChanges.getTo().isSubscribed(); - } - }; - OneSignal.addSubscriptionObserver(permissionObserver); - threadAndTaskWait(); - - assertFalse(lastSubscriptionStateChanges.getFrom().isSubscribed()); - assertTrue(lastSubscriptionStateChanges.getTo().isSubscribed()); - // Test to make sure object was correct at the time of firing. - assertTrue(currentSubscription); - assertFalse(lastSubscriptionStateChanges.getTo().isPushDisabled()); - assertEquals(ShadowPushRegistratorFCM.regId, lastSubscriptionStateChanges.getTo().getPushToken()); - assertEquals(ShadowOneSignalRestClient.pushUserId, lastSubscriptionStateChanges.getTo().getUserId()); - } - - @Test - public void shouldNotFireSubscriptionObserverWhenChangesHappenIfRemoved() throws Exception { - OneSignalInit(); - OSSubscriptionObserver permissionObserver = new OSSubscriptionObserver() { - @Override - public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) { - lastSubscriptionStateChanges = stateChanges; - currentSubscription = stateChanges.getTo().isSubscribed(); - } - }; - OneSignal.addSubscriptionObserver(permissionObserver); - lastSubscriptionStateChanges = null; - OneSignal.removeSubscriptionObserver(permissionObserver); - threadAndTaskWait(); - - assertFalse(currentSubscription); - assertNull(lastSubscriptionStateChanges); - } - - @Test - public void shouldFireEmailSubscriptionObserverOnSetEmail() throws Exception { - OneSignalInit(); - OSEmailSubscriptionObserver subscriptionObserver = new OSEmailSubscriptionObserver() { - @Override - public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateChanges) { - lastEmailSubscriptionStateChanges = stateChanges; - } - }; - OneSignal.addEmailSubscriptionObserver(subscriptionObserver); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - assertNull(lastEmailSubscriptionStateChanges.getFrom().getEmailUserId()); - assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", lastEmailSubscriptionStateChanges.getTo().getEmailUserId()); - assertEquals("josh@onesignal.com", lastEmailSubscriptionStateChanges.getTo().getEmailAddress()); - assertTrue(lastEmailSubscriptionStateChanges.getTo().isSubscribed()); - } - - @Test - public void shouldFireSMSSubscriptionObserverOnSetSMS() throws Exception { - OneSignalInit(); - OSSMSSubscriptionObserver subscriptionObserver = stateChanges -> lastSMSSubscriptionStateChanges = stateChanges; - OneSignal.addSMSSubscriptionObserver(subscriptionObserver); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - assertNull(lastSMSSubscriptionStateChanges.getFrom().getSmsUserId()); - assertEquals(SMS_USER_ID, lastSMSSubscriptionStateChanges.getTo().getSmsUserId()); - assertEquals(ONESIGNAL_SMS_NUMBER, lastSMSSubscriptionStateChanges.getTo().getSMSNumber()); - assertTrue(lastSMSSubscriptionStateChanges.getTo().isSubscribed()); - } - - @Test - public void shouldFireEmailSubscriptionObserverOnLogoutEmail() throws Exception { - OneSignalInit(); - OSEmailSubscriptionObserver subscriptionObserver = new OSEmailSubscriptionObserver() { - @Override - public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateChanges) { - lastEmailSubscriptionStateChanges = stateChanges; - } - }; - OneSignal.addEmailSubscriptionObserver(subscriptionObserver); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - OneSignal.logoutEmail(); - threadAndTaskWait(); - - assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", lastEmailSubscriptionStateChanges.getFrom().getEmailUserId()); - assertEquals("josh@onesignal.com", lastEmailSubscriptionStateChanges.getFrom().getEmailAddress()); - - assertFalse(lastEmailSubscriptionStateChanges.getTo().isSubscribed()); - assertNull(lastEmailSubscriptionStateChanges.getTo().getEmailUserId()); - assertNull(lastEmailSubscriptionStateChanges.getTo().getEmailAddress()); - } - - @Test - public void shouldNotFireEmailSubscriptionObserverOnAppRestart() throws Exception { - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - OSEmailSubscriptionObserver subscriptionObserver = new OSEmailSubscriptionObserver() { - @Override - public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateChanges) { - lastEmailSubscriptionStateChanges = stateChanges; - } - }; - OneSignal.addEmailSubscriptionObserver(subscriptionObserver); - threadAndTaskWait(); - assertNotNull(lastEmailSubscriptionStateChanges); - - restartAppAndElapseTimeToNextSession(time); - - OneSignalInit(); - threadAndTaskWait(); - lastEmailSubscriptionStateChanges = null; - OneSignal.addEmailSubscriptionObserver(subscriptionObserver); - threadAndTaskWait(); - - assertNull(lastEmailSubscriptionStateChanges); - } - - @Test - public void shouldNotFireSMSSubscriptionObserverOnAppRestart() throws Exception { - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - OSSMSSubscriptionObserver subscriptionObserver = stateChanges -> lastSMSSubscriptionStateChanges = stateChanges; - OneSignal.addSMSSubscriptionObserver(subscriptionObserver); - threadAndTaskWait(); - assertNotNull(lastSMSSubscriptionStateChanges); - - restartAppAndElapseTimeToNextSession(time); - lastSMSSubscriptionStateChanges = null; - - OneSignalInit(); - threadAndTaskWait(); - OneSignal.addSMSSubscriptionObserver(subscriptionObserver); - threadAndTaskWait(); - - assertNull(lastSMSSubscriptionStateChanges); - } - - @Test - public void shouldNotThrowWhenRemovingWeakReferenceObservableThatHasBeenGarbageCollected() { - OSObservable observer = new OSObservable<>("", false); - WeakReference weakObject = new WeakReference<>(new Object()); - observer.addObserver(weakObject.get()); - Runtime.getRuntime().gc(); // Force cleaning up WeakReference above - observer.removeObserver(weakObject.get()); - } - - @Test - public void shouldGetCorrectCurrentEmailSubscriptionState() throws Exception { - OneSignalInit(); - OSDeviceState deviceState = OneSignal.getDeviceState(); - - assertNotNull(deviceState); - assertNull(deviceState.getEmailUserId()); - assertNull(deviceState.getEmailAddress()); - assertFalse(deviceState.isEmailSubscribed()); - - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - deviceState = OneSignal.getDeviceState(); - - assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", deviceState.getEmailUserId()); - assertEquals("josh@onesignal.com", deviceState.getEmailAddress()); - assertTrue(deviceState.isEmailSubscribed()); - } - - @Test - public void shouldGetCorrectCurrentSMSSubscriptionState() throws Exception { - OneSignalInit(); - OSDeviceState deviceState = OneSignal.getDeviceState(); - - assertNotNull(deviceState); - assertNull(deviceState.getSMSUserId()); - assertNull(deviceState.getSMSNumber()); - assertFalse(deviceState.isSMSSubscribed()); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - deviceState = OneSignal.getDeviceState(); - - assertEquals(SMS_USER_ID, deviceState.getSMSUserId()); - assertEquals(ONESIGNAL_SMS_NUMBER, deviceState.getSMSNumber()); - assertTrue(deviceState.isSMSSubscribed()); - } - - @Test - public void shouldGetEmailUserIdAfterAppRestart() throws Exception { - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - - OneSignalInit(); - OSDeviceState deviceState = OneSignal.getDeviceState(); - assertEquals("josh@onesignal.com", deviceState.getEmailAddress()); - assertNotNull(deviceState.getEmailUserId()); - } - - @Test - public void shouldGetSMSUserIdAfterAppRestart() throws Exception { - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - - OneSignalInit(); - OSDeviceState deviceState = OneSignal.getDeviceState(); - assertEquals(ONESIGNAL_SMS_NUMBER, deviceState.getSMSNumber()); - assertNotNull(deviceState.getSMSUserId()); - } - - @Test - public void shouldReturnCorrectGetPermissionSubscriptionState() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - OSDeviceState deviceState = OneSignal.getDeviceState(); - assertTrue(deviceState.areNotificationsEnabled()); - assertTrue(deviceState.isSubscribed()); - } - - @Test - public void testDeviceStateHasEmailAddress() throws Exception { - String testEmail = "test@onesignal.com"; - - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - OSDeviceState device = OneSignal.getDeviceState(); - assertNull(device.getEmailAddress()); - - OneSignal.setEmail(testEmail); - threadAndTaskWait(); - - // Device is a snapshot, last value should not change - assertNull(device.getEmailAddress()); - // Retrieve new user device - assertEquals(testEmail, OneSignal.getDeviceState().getEmailAddress()); - } - - @Test - public void testDeviceStateHasSMSAddress() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - OSDeviceState device = OneSignal.getDeviceState(); - assertNull(device.getSMSNumber()); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // Device is a snapshot, last value should not change - assertNull(device.getSMSNumber()); - // Retrieve new user device - assertEquals(ONESIGNAL_SMS_NUMBER, OneSignal.getDeviceState().getSMSNumber()); - } - - @Test - public void testDeviceStateHasEmailId() throws Exception { - String testEmail = "test@onesignal.com"; - - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - OSDeviceState device = OneSignal.getDeviceState(); - assertNull(device.getEmailUserId()); - - OneSignal.setEmail(testEmail); - threadAndTaskWait(); - - // Device is a snapshot, last value should not change - assertNull(device.getEmailUserId()); - // Retrieve new user device - assertNotNull(OneSignal.getDeviceState().getEmailUserId()); - } - - @Test - public void testDeviceStateHasSMSId() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - OSDeviceState device = OneSignal.getDeviceState(); - assertNull(device.getSMSUserId()); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // Device is a snapshot, last value should not change - assertNull(device.getSMSUserId()); - // Retrieve new user device - assertEquals(SMS_USER_ID, OneSignal.getDeviceState().getSMSUserId()); - } - - @Test - public void testDeviceStateHasUserId() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - assertNotNull(OneSignal.getDeviceState().getUserId()); - } - - @Test - public void testDeviceStateHasPushToken() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - assertNotNull(OneSignal.getDeviceState().getPushToken()); - } - - @Test - public void testDeviceStateAreNotificationsEnabled() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - OSDeviceState device = OneSignal.getDeviceState(); - assertTrue(device.areNotificationsEnabled()); - - fastColdRestartApp(); - - ShadowNotificationManagerCompat.enabled = false; - - OneSignalInit(); - threadAndTaskWait(); - - // Device is a snapshot, last value should not change - assertTrue(device.areNotificationsEnabled()); - // Retrieve new user device - assertFalse(OneSignal.getDeviceState().areNotificationsEnabled()); - } - - @Test - public void testDeviceStateIsPushDisabled() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - assertFalse(OneSignal.getDeviceState().isPushDisabled()); - } - - @Test - public void testDeviceStateIsSubscribed() throws Exception { - assertNull(OneSignal.getDeviceState()); - - OneSignalInit(); - threadAndTaskWait(); - - OSDeviceState device = OneSignal.getDeviceState(); - assertTrue(device.isSubscribed()); - - fastColdRestartApp(); - - ShadowNotificationManagerCompat.enabled = false; - - OneSignalInit(); - threadAndTaskWait(); - - // Device is a snapshot, last value should not change - assertTrue(device.isSubscribed()); - // Retrieve new user device - assertFalse(OneSignal.getDeviceState().isSubscribed()); - } - - @Test - public void shouldSendPurchases() throws Exception { - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - JSONObject purchase = new JSONObject(); - purchase.put("sku", "com.test.sku"); - JSONArray purchases = new JSONArray(); - purchases.put(purchase); - - OneSignalPackagePrivateHelper.OneSignal_sendPurchases(purchases, false, null); - threadAndTaskWait(); - - String expectedPayload = "{\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\",\"purchases\":[{\"sku\":\"com.test.sku\"}]}"; - ShadowOneSignalRestClient.Request pushPurchase = ShadowOneSignalRestClient.requests.get(5); - assertEquals("players/" + PUSH_USER_ID + "/on_purchase", pushPurchase.url); - assertEquals(expectedPayload, pushPurchase.payload.toString()); - - ShadowOneSignalRestClient.Request emailPurchase = ShadowOneSignalRestClient.requests.get(6); - assertEquals("players/" + EMAIL_USER_ID + "/on_purchase", emailPurchase.url); - assertEquals(expectedPayload, emailPurchase.payload.toString()); - - ShadowOneSignalRestClient.Request smsPurchase = ShadowOneSignalRestClient.requests.get(7); - assertEquals("players/" + SMS_USER_ID + "/on_purchase", smsPurchase.url); - assertEquals(expectedPayload, smsPurchase.payload.toString()); - } - - @Test - @Config(shadows = { ShadowFirebaseAnalytics.class }) - public void shouldSendFirebaseAnalyticsNotificationOpen() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("fba", true)); - OneSignalInit(); - threadAndTaskWait(); - - JSONObject openPayload = new JSONObject(); - openPayload.put("title", "Test title"); - openPayload.put("alert", "Test Msg"); - openPayload.put("custom", new JSONObject("{ \"i\": \"UUID\" }")); - OneSignal_handleNotificationOpen(blankActivity, new JSONArray().put(openPayload), ONESIGNAL_NOTIFICATION_ID); - - assertEquals("os_notification_opened", ShadowFirebaseAnalytics.lastEventString); - Bundle expectedBundle = new Bundle(); - expectedBundle.putString("notification_id", "UUID"); - expectedBundle.putString("medium", "notification"); - expectedBundle.putString("source", "OneSignal"); - expectedBundle.putString("campaign", "Test title"); - assertEquals(expectedBundle.toString(), ShadowFirebaseAnalytics.lastEventBundle.toString()); - - // Assert that another open isn't trigger later when the unprocessed opens are fired - ShadowFirebaseAnalytics.lastEventString = null; - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - assertNull(ShadowFirebaseAnalytics.lastEventString); - } - - @Test - @Config(shadows = { ShadowFirebaseAnalytics.class, ShadowGenerateNotification.class }) - public void shouldSendFirebaseAnalyticsNotificationReceived() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("fba", true)); - OneSignalInit(); - threadAndTaskWait(); - - JSONObject openPayload = new JSONObject(); - openPayload.put("title", "Test title"); - openPayload.put("alert", "Test Msg"); - openPayload.put("custom", new JSONObject("{ \"i\": \"UUID\" }")); - NotificationBundleProcessor_Process(blankActivity, false, openPayload); - - assertEquals("os_notification_received", ShadowFirebaseAnalytics.lastEventString); - Bundle expectedBundle = new Bundle(); - expectedBundle.putString("notification_id", "UUID"); - expectedBundle.putString("medium", "notification"); - expectedBundle.putString("source", "OneSignal"); - expectedBundle.putString("campaign", "Test title"); - assertEquals(expectedBundle.toString(), ShadowFirebaseAnalytics.lastEventBundle.toString()); - - // Assert that another receive isn't trigger later when the unprocessed receives are fired - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationWillShowInForegroundHandler(notificationReceivedEvent -> { - - }); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - threadAndTaskWait(); - - ShadowFirebaseAnalytics.lastEventString = null; - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - assertNull(ShadowFirebaseAnalytics.lastEventString); - } - - @Test - public void testGetTagsQueuesCallbacks() throws Exception { - final BlockingQueue queue = new ArrayBlockingQueue<>(2); - - // Allows us to validate that both handlers get executed independently - class DebugGetTagsHandler implements OneSignal.OSGetTagsHandler { - @Override - public void tagsAvailable(JSONObject tags) { - queue.offer(true); - } - } - - DebugGetTagsHandler first = new DebugGetTagsHandler(); - DebugGetTagsHandler second = new DebugGetTagsHandler(); - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.sendTag("test", "value"); - threadAndTaskWait(); - - OneSignal.getTags(first); - OneSignal.getTags(second); - threadAndTaskWait(); - - assertTrue(queue.take()); - assertTrue(queue.take()); - } - - @Test - public void testNestedGetTags() throws Exception { - final BlockingQueue queue = new ArrayBlockingQueue<>(2); - - // Validates that nested getTags calls won't throw a ConcurrentModificationException - class DebugGetTagsHandler implements OneSignal.OSGetTagsHandler { - @Override - public void tagsAvailable(JSONObject tags) { - OneSignal.getTags(new OneSignal.OSGetTagsHandler() { - @Override - public void tagsAvailable(JSONObject tags) { - queue.offer(true); - } - }); - } - } - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.sendTag("test", "value"); - threadAndTaskWait(); - - DebugGetTagsHandler first = new DebugGetTagsHandler(); - DebugGetTagsHandler second = new DebugGetTagsHandler(); - OneSignal.getTags(first); - OneSignal.getTags(second); - threadAndTaskWait(); - - assertTrue(queue.take()); - assertTrue(queue.take()); - } - - /** - * Created a AndroidManifest with 2 activities, 1 with the orientation config and 1 without - * Using this AndroidManifest setup to test that a config setting is detectable - */ - @Test - public void testAndroidManifestConfigChangeFlags_orientationFlag() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Set ActivityInfo.CONFIG_ORIENTATION configChanges flag - OneSignalShadowPackageManager.configChanges = ActivityInfo.CONFIG_ORIENTATION; - - // Verify BlankActivity has orientation flag - boolean blankHasFlag = OneSignalPackagePrivateHelper.hasConfigChangeFlag(blankActivity, ActivityInfo.CONFIG_ORIENTATION); - assertTrue(blankHasFlag); - - // Go to MainActivity - Intent mainIntent = new Intent(blankActivity, MainActivity.class); - Activity mainActivity = Robolectric.buildActivity(MainActivity.class).newIntent(mainIntent).create().get(); - - // Set no configChanges flags - OneSignalShadowPackageManager.configChanges = 0; - - // Verify MainActivity has no orientation flag - boolean mainHasFlag = OneSignalPackagePrivateHelper.hasConfigChangeFlag(mainActivity, ActivityInfo.CONFIG_ORIENTATION); - assertFalse(mainHasFlag); - } - - // ####### Unit test helper methods ######## - - private static OSNotification createTestOSNotification() throws Exception { - OSNotification.ActionButton actionButton = new OSNotification.ActionButton("id", "text", null); - List actionButtons = new ArrayList<>(); - actionButtons.add(actionButton); - - List groupedNotifications = new ArrayList<>(); - - OSNotification groupedNotification = new OneSignalPackagePrivateHelper.OSTestNotification.OSTestNotificationBuilder() - .setCollapseId("collapseId1") - .build(); - - groupedNotifications.add(groupedNotification); - - return new OneSignalPackagePrivateHelper.OSTestNotification.OSTestNotificationBuilder() - .setBody("msg_body") - .setAdditionalData(new JSONObject("{\"foo\": \"bar\"}")) - .setActionButtons(actionButtons) - .setGroupedNotifications(groupedNotifications) - .build(); - } - - private void OneSignalInit() { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - OneSignal_setTime(time); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - blankActivityController.resume(); - } - - // For some reason Roboelctric does not automatically add this when it reads the AndroidManifest.xml - // Also it seems it has to be done in the test itself instead of the setup process. - private static void AddLauncherIntentFilter() { - Intent launchIntent = new Intent(Intent.ACTION_MAIN); - launchIntent.setPackage("com.onesignal.example"); - launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); - ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.activityInfo = new ActivityInfo(); - resolveInfo.activityInfo.packageName = "com.onesignal.example"; - resolveInfo.activityInfo.name = "MainActivity"; - - shadowOf(blankActivity.getPackageManager()).addResolveInfoForIntent(launchIntent, resolveInfo); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/NotificationChannelManagerRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/NotificationChannelManagerRunner.java deleted file mode 100644 index e1898f9b6..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/NotificationChannelManagerRunner.java +++ /dev/null @@ -1,295 +0,0 @@ -package com.test.onesignal; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationChannelGroup; -import android.app.NotificationManager; -import android.content.Context; - -import com.onesignal.OneSignal; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignal; -import com.onesignal.ShadowRoboNotificationManager; -import com.onesignal.example.BlankActivity; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.math.BigInteger; - -import static com.onesignal.OneSignalPackagePrivateHelper.NotificationChannelManager_createNotificationChannel; -import static com.onesignal.OneSignalPackagePrivateHelper.NotificationChannelManager_processChannelList; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class, - ShadowRoboNotificationManager.class}, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -public class NotificationChannelManagerRunner { - - private Context mContext; - private BlankActivity blankActivity; - - NotificationChannelManagerRunner setContext(Context context) { - mContext = context; - return this; - } - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - } - - @Before - public void beforeEachTest() { - ActivityController blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - mContext = blankActivity; - } - - @Test - public void createNotificationChannelShouldReturnDefaultChannelWithEmptyPayload() { - JSONObject payload = new JSONObject(); - - String ret = NotificationChannelManager_createNotificationChannel(blankActivity, payload); - - assertEquals("fcm_fallback_notification_channel", ret); - NotificationChannel lastChannel = ShadowRoboNotificationManager.lastChannel; - assertEquals("fcm_fallback_notification_channel", lastChannel.getId()); - assertNotNull(lastChannel.getSound()); - assertTrue(lastChannel.shouldShowLights()); - assertTrue(lastChannel.shouldVibrate()); - } - - @Test - public void createNotificationChannelCreateBasicChannel() throws Exception { - JSONObject payload = new JSONObject(); - JSONObject chnl = new JSONObject(); - chnl.put("id", "test_id"); - payload.put("chnl", chnl.toString()); - - String ret = NotificationChannelManager_createNotificationChannel(blankActivity, payload); - - NotificationChannel channel = ShadowRoboNotificationManager.lastChannel; - assertEquals("test_id", ret); - assertEquals("test_id", ShadowRoboNotificationManager.lastChannel.getId()); - assertNotNull(channel.getSound()); - assertTrue(channel.shouldShowLights()); - assertTrue(channel.shouldVibrate()); - } - - @Test - public void createNotificationChannelWithALlOptions() throws Exception { - JSONObject payload = new JSONObject(); - JSONObject chnl = new JSONObject(); - - chnl.put("id", "test_id"); - chnl.put("nm", "Test Name"); - chnl.put("dscr", "Some description"); - chnl.put("grp_id", "grp_id"); - chnl.put("grp_nm", "Group Name"); - - payload.put("pri", 10); - payload.put("led", 0); - payload.put("ledc", "FFFF0000"); - payload.put("vib", 0); - payload.put("vib_pt", new JSONArray("[1,2,3,4]")); - payload.put("sound", "notification"); - payload.put("vis", Notification.VISIBILITY_SECRET); - payload.put("bdg", 1); - payload.put("bdnd", 1); - - payload.put("chnl", chnl.toString()); - - String ret = NotificationChannelManager_createNotificationChannel(blankActivity, payload); - - NotificationChannel channel = ShadowRoboNotificationManager.lastChannel; - assertEquals("test_id", ret); - assertEquals("test_id", ShadowRoboNotificationManager.lastChannel.getId()); - assertEquals("Test Name", channel.getName()); - assertEquals("Some description", channel.getDescription()); - assertEquals("grp_id", channel.getGroup()); - NotificationChannelGroup group = ShadowRoboNotificationManager.lastChannelGroup; - assertEquals("grp_id", group.getId()); - assertEquals("Group Name", group.getName()); - assertNotNull(channel.getSound()); - assertFalse(channel.shouldShowLights()); // Setting a led color should NOT override enableLights - assertEquals(-65536, channel.getLightColor()); - assertFalse(channel.shouldVibrate()); // Setting a pattern should NOT override enableVibration - assertArrayEquals(new long[]{1,2,3,4}, channel.getVibrationPattern()); - assertEquals(NotificationManager.IMPORTANCE_MAX, channel.getImportance()); - assertEquals("content://settings/system/notification_sound", channel.getSound().toString()); - assertEquals(Notification.VISIBILITY_SECRET, channel.getLockscreenVisibility()); - assertTrue(channel.canShowBadge()); - assertTrue(channel.canBypassDnd()); - } - - @Test - public void useOtherChannelWhenItIsAvailable() throws Exception { - JSONObject payload = new JSONObject(); - payload.put("oth_chnl", "existing_id"); - - JSONObject chnl = new JSONObject(); - chnl.put("id", "test_id"); - payload.put("chnl", chnl.toString()); - - String ret = NotificationChannelManager_createNotificationChannel(blankActivity, payload); - - // Should create and use the payload type as the "existing_id" didn't exist. - assertEquals("test_id", ret); - - // Create the missing channel and using the same payload we should use this existing_id now. - createChannel("existing_id"); - ret = NotificationChannelManager_createNotificationChannel(blankActivity, payload); - assertEquals("existing_id", ret); - } - - - // Start - Cold start sync tests - - @Test - public void processPayloadWithOutChannelList() { - createChannel("local_existing_id"); - createChannel("OS_existing_id"); - - NotificationChannelManager_processChannelList(blankActivity, null); - - assertNotNull(getChannel("local_existing_id")); - assertNotNull(getChannel("OS_existing_id")); - } - - @Test - public void processPayloadCreatingNewChannel() throws Exception { - createChannel("local_existing_id"); - - JSONArray channelList = new JSONArray(); - JSONObject channelItem = new JSONObject(); - JSONObject channelItemChnl = new JSONObject(); - - channelItemChnl.put("id", "OS_id1"); - channelItem.put("chnl", channelItemChnl); - - channelList.put(channelItem); - - NotificationChannelManager_processChannelList(blankActivity, channelList); - - assertNotNull(getChannel("local_existing_id")); - assertNotNull(getChannel("OS_id1")); - } - - @Test - public void processPayloadDeletingOldChannel() throws Exception { - NotificationChannelManager_processChannelList(blankActivity, createBasicChannelListPayload().optJSONArray("chnl_lst")); - assertChannelsForBasicChannelList(); - } - - // Test that specific "en" defined keys name and descriptions are used when - // the device language is English. - // Top level keys under no language key are considered the default language. - @Test - public void processChannelListWithMultiLanguage() throws Exception { - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - - JSONObject payload = createBasicChannelListPayload(); - - JSONObject channelItem = (JSONObject)payload.optJSONArray("chnl_lst").get(0); - JSONObject channelProperties = channelItem.optJSONObject("chnl"); - - // Add "langs" key with a "en" sub key. - JSONObject langs = new JSONObject(); - JSONObject en = new JSONObject(); - en.put("nm", "en_nm"); - en.put("dscr", "en_dscr"); - en.put("grp_nm", "en_grp_nm"); - langs.put("en", en); - channelProperties.put("langs", langs); - - channelProperties.put("grp_id", "grp_id1"); - - NotificationChannelManager_processChannelList(blankActivity, payload.optJSONArray("chnl_lst")); - - NotificationChannel channel = getChannel("OS_id1"); - assertEquals("en_nm", channel.getName()); - assertEquals("en_dscr", channel.getDescription()); - assertEquals("en_grp_nm", ShadowRoboNotificationManager.lastChannelGroup.getName()); - } - - @Test - @Config(shadows = {ShadowOneSignal.class}) - public void handleInvalidColorCode() throws Exception { - JSONObject payload = new JSONObject(); - JSONObject chnl = new JSONObject(); - - chnl.put("id", "test_id"); - chnl.put("nm", "Test Name"); - payload.put("ledc", "FFFFFFFFY"); - payload.put("chnl", chnl.toString()); - - NotificationChannelManager_createNotificationChannel(blankActivity, payload); - - // check default to white - NotificationChannel channel = ShadowRoboNotificationManager.lastChannel; - BigInteger ledColor = new BigInteger("FFFFFFFF", 16); - assertEquals(ledColor.intValue(), channel.getLightColor()); - assertTrue(ShadowOneSignal.messages.contains("OneSignal LED Color Settings: ARGB Hex value incorrect format (E.g: FF9900FF)")); - } - - // Starting helper methods - - JSONObject createBasicChannelListPayload() throws JSONException { - createChannel("local_existing_id"); - createChannel("OS_existing_id"); - - JSONArray channelList = new JSONArray(); - JSONObject channelItem = new JSONObject(); - JSONObject channelItemChnl = new JSONObject(); - - channelItemChnl.put("id", "OS_id1"); - channelItem.put("chnl", channelItemChnl); - - channelList.put(channelItem); - JSONObject payload = new JSONObject(); - payload.put("chnl_lst", channelList); - return payload; - } - - void assertChannelsForBasicChannelList() { - assertNotNull(getChannel("local_existing_id")); - assertNull(getChannel("OS_existing_id")); - assertNotNull(getChannel("OS_id1")); - } - - private NotificationChannel getChannel(String id) { - NotificationManager notificationManager = - (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); - return notificationManager.getNotificationChannel(id); - } - - private void createChannel(String id) { - NotificationManager notificationManager = - (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); - NotificationChannel channel = new NotificationChannel(id,"name", NotificationManager.IMPORTANCE_DEFAULT); - notificationManager.createNotificationChannel(channel); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/NotificationLimitManagerRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/NotificationLimitManagerRunner.java deleted file mode 100644 index 23ac0f144..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/NotificationLimitManagerRunner.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.test.onesignal; - -import android.app.NotificationManager; -import android.content.Context; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; - -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper.NotificationLimitManager; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowGenerateNotification; -import com.onesignal.ShadowNotificationLimitManager; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import static com.onesignal.OneSignalPackagePrivateHelper.NotificationBundleProcessor_ProcessFromFCMIntentService; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.GenerateNotificationRunner.getBaseNotifBundle; -import static com.test.onesignal.TestHelpers.afterTestCleanup; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowNotificationLimitManager.class, - ShadowPushRegistratorFCM.class, - ShadowOSUtils.class, - ShadowOneSignalRestClient.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class NotificationLimitManagerRunner { - - private BlankActivity blankActivity; - private NotificationManager notificationManager; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - ActivityController blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - notificationManager = (NotificationManager)blankActivity.getSystemService(Context.NOTIFICATION_SERVICE); - TestHelpers.beforeTestInitAndCleanup(); - - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - OneSignal.setAppId("b2f7f966-d8cc-11e4-bed1-df8f05be55ba"); - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - } - - @After - public void afterEachTest() throws Exception { - afterTestCleanup(); - } - - @Test - public void clearStandardMakingRoomForOneWhenAtLimit() throws Throwable { - createNotification(blankActivity, 1); - createNotification(blankActivity, 2); - - NotificationLimitManager.clearOldestOverLimitStandard(blankActivity, 1); - threadAndTaskWait(); - - assertEquals(1, notificationManager.getActiveNotifications().length); - assertEquals(2, notificationManager.getActiveNotifications()[0].getId()); - } - - @Test - public void clearStandardShouldNotCancelAnyNotificationsWhenUnderLimit() throws Throwable { - createNotification(blankActivity, 1); - - NotificationLimitManager.clearOldestOverLimitStandard(blankActivity, 1); - threadAndTaskWait(); - - assertEquals(1, notificationManager.getActiveNotifications().length); - } - - @Test - public void clearStandardShouldSkipGroupSummaryNotification() throws Throwable { - NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(blankActivity, ""); - notifBuilder.setWhen(1); - // We should not clear summary notifications, these will go away if all child notifications are canceled - notifBuilder.setGroupSummary(true); - NotificationManagerCompat.from(blankActivity).notify(1, notifBuilder.build()); - - createNotification(blankActivity, 2); - - NotificationLimitManager.clearOldestOverLimitStandard(blankActivity, 1); - threadAndTaskWait(); - - assertEquals(1 , notificationManager.getActiveNotifications()[0].getId()); - } - - // Helper Methods - private static void createNotification(Context context, int notifId) { - NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context, ""); - notifBuilder.setWhen(notifId); // Android automatically sets this normally. - NotificationManagerCompat.from(context).notify(notifId, notifBuilder.build()); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void clearFallbackMakingRoomForOneWhenAtLimit() throws Exception { - NotificationBundleProcessor_ProcessFromFCMIntentService(blankActivity, getBaseNotifBundle("UUID1")); - threadAndTaskWait(); - NotificationBundleProcessor_ProcessFromFCMIntentService(blankActivity, getBaseNotifBundle("UUID2")); - threadAndTaskWait(); - - NotificationLimitManager.clearOldestOverLimitFallback(blankActivity, 1); - threadAndTaskWait(); - - assertEquals(1, notificationManager.getActiveNotifications().length); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void clearFallbackShouldNotCancelAnyNotificationsWhenUnderLimit() throws Exception { - NotificationBundleProcessor_ProcessFromFCMIntentService(blankActivity, getBaseNotifBundle("UUID1")); - threadAndTaskWait(); - - NotificationLimitManager.clearOldestOverLimitFallback(blankActivity, 1); - threadAndTaskWait(); - - assertEquals(1, notificationManager.getActiveNotifications().length); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OneSignalInitializationIntegrationTestsRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OneSignalInitializationIntegrationTestsRunner.java deleted file mode 100644 index 9affc68a6..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OneSignalInitializationIntegrationTestsRunner.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.test.onesignal; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockOSTimeImpl; -import com.onesignal.OneSignal; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalWithMockSetupContextListeners; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import static com.onesignal.OneSignalPackagePrivateHelper.MIN_ON_SESSION_TIME_MILLIS; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.RestClientAsserts.assertNumberOfOnSessions; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; - -@Config( - packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class, - ShadowOneSignalRestClient.class, - ShadowPushRegistratorFCM.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - }, - sdk = 26 -) - -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class OneSignalInitializationIntegrationTestsRunner { - private ActivityController blankActivityController; - private MockOSTimeImpl time; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - setRemoteParamsGetHtmlResponse(); - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - - time = new MockOSTimeImpl(); - OneSignal_setTime(time); - } - - private static final long MIN_ON_SESSION_TIME_SEC = MIN_ON_SESSION_TIME_MILLIS / 1_000L; - private static final String APP_ID = "11111111-2222-3333-4444-55555555555"; - private static void helper_OneSignal_initWithAppContext() { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - } - private void helper_OneSignal_initWithActivity() { - OneSignal.initWithContext(blankActivityController.get()); - } - - private void helper_advanceSystemTimeToNextOnSession() { - time.advanceSystemAndElapsedTimeBy(MIN_ON_SESSION_TIME_SEC + 1); - } - - @Test - public void setRequiresUserPrivacyConsent_withTrue_CalledFirst_DoesNOTCreatePlayer() throws Exception { - OneSignal.setRequiresUserPrivacyConsent(true); - - OneSignal.setAppId(APP_ID); - helper_OneSignal_initWithAppContext(); - threadAndTaskWait(); - - RestClientAsserts.assertRemoteParamsWasTheOnlyNetworkCall(); - } - - // This test reproduces https://github.com/OneSignal/OneSignal-Android-SDK/issues/1514 - @Test - @Config(shadows = { ShadowOneSignalWithMockSetupContextListeners.class }) - public void initWithContext_setupContextListenersNotCompleted_doesNotProduceNPE() throws Exception { - OneSignal.setAppId(APP_ID); - - // call initWithContext() but don't complete setupContextListeners() via the Shadow class - // this prevents the initialization of outcomeEventsController in setupContextListeners() - helper_OneSignal_initWithAppContext(); - threadAndTaskWait(); - // we implicitly test that no exception is thrown - } - - @Test - public void setRequiresUserPrivacyConsent_withFalseAndRemoteTrue_DoesNOTCreatePlayer() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - OneSignal.setRequiresUserPrivacyConsent(false); - - OneSignal.setAppId(APP_ID); - helper_OneSignal_initWithAppContext(); - threadAndTaskWait(); - - RestClientAsserts.assertRemoteParamsWasTheOnlyNetworkCall(); - } - - /** - * on_session calls should only be made if the user left the app for MIN_ON_SESSION_TIME_SEC or longer - * This test ensures that we meet the out of focus requirement, at lest through initWithContext - * being called a 2nd time code path. - */ - @Test - public void initWithContext_calledA2ndTimeAfter30OrMoreSeconds_doesNotStartNewSession() throws Exception { - // 1. Basic OneSignal init with Activity - OneSignal.setAppId(APP_ID); - helper_OneSignal_initWithActivity(); - threadAndTaskWait(); - - // 2. Keep the app in focus for 30+ seconds, which is the time required to - helper_advanceSystemTimeToNextOnSession(); - - // 3. Developer or OneSignal internally calls OneSignal.initWithContext - helper_OneSignal_initWithActivity(); - threadAndTaskWait(); - - // 4. Ensure we do NOT make an /players/{player_id}/on_session network call. - assertNumberOfOnSessions(0); - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OneSignalPrefsRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OneSignalPrefsRunner.java deleted file mode 100644 index 14906a379..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OneSignalPrefsRunner.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.test.onesignal; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; - -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper.TestOneSignalPrefs; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static org.junit.Assert.assertEquals; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowOSUtils.class - }, - sdk = 21 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class OneSignalPrefsRunner { - - private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba"; - private static final String KEY = "key"; - private static final String VALUE = "value"; - private static Activity blankActivity; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - - ActivityController blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - - // We only care about shared preferences, avoid other logic's - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - } - - @AfterClass - public static void afterEverything() throws Exception { - StaticResetHelper.restSetStaticFields(); - } - - @Test - public void testNullContextDoesNotCrash() { - TestOneSignalPrefs.saveString(TestOneSignalPrefs.PREFS_ONESIGNAL, KEY, VALUE); - TestHelpers.flushBufferedSharedPrefs(); - } - - @Test - public void tesWriteWithNullAppId_andSavesAfterSetting() throws Exception { - OneSignal.initWithContext(blankActivity); - TestOneSignalPrefs.saveString(TestOneSignalPrefs.PREFS_ONESIGNAL, KEY, VALUE); - TestHelpers.flushBufferedSharedPrefs(); - - OneSignal.setAppId(ONESIGNAL_APP_ID); - threadAndTaskWait(); - TestHelpers.flushBufferedSharedPrefs(); - - final SharedPreferences prefs = blankActivity.getSharedPreferences(TestOneSignalPrefs.PREFS_ONESIGNAL, Context.MODE_PRIVATE); - String value = prefs.getString(KEY, ""); - assertEquals(VALUE, value); - } - - @Test - public void tesWriteWithNullContext_andSavesAfterSetting() throws Exception { - OneSignal.setAppId(ONESIGNAL_APP_ID); - TestOneSignalPrefs.saveString(TestOneSignalPrefs.PREFS_ONESIGNAL, KEY, VALUE); - TestHelpers.flushBufferedSharedPrefs(); - - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - TestHelpers.flushBufferedSharedPrefs(); - - final SharedPreferences prefs = blankActivity.getSharedPreferences(TestOneSignalPrefs.PREFS_ONESIGNAL, Context.MODE_PRIVATE); - String value = prefs.getString(KEY, ""); - assertEquals(VALUE, value); - } - - @Test - public void tesWriteWithNullContextAndAppId_andSavesAfterSetting() throws Exception { - OneSignal.setAppId(ONESIGNAL_APP_ID); - TestOneSignalPrefs.saveString(TestOneSignalPrefs.PREFS_ONESIGNAL, KEY, VALUE); - TestHelpers.flushBufferedSharedPrefs(); - - OneSignal.initWithContext(blankActivity); - threadAndTaskWait(); - TestHelpers.flushBufferedSharedPrefs(); - - final SharedPreferences prefs = blankActivity.getSharedPreferences(TestOneSignalPrefs.PREFS_ONESIGNAL, Context.MODE_PRIVATE); - String value = prefs.getString(KEY, ""); - assertEquals(VALUE, value); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventIntegrationTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventIntegrationTests.java deleted file mode 100644 index 415de5c66..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventIntegrationTests.java +++ /dev/null @@ -1,1338 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.os.Bundle; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockSessionManager; -import com.onesignal.OSNotificationOpenedResult; -import com.onesignal.OSSessionManager; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalShadowPackageManager; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowFocusHandler; -import com.onesignal.ShadowGMSLocationController; -import com.onesignal.ShadowGenerateNotification; -import com.onesignal.ShadowJobService; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.ShadowTimeoutHandler; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; -import com.onesignal.influence.data.OSTrackerFactory; -import com.onesignal.influence.domain.OSInfluence; -import com.onesignal.influence.domain.OSInfluenceChannel; -import com.onesignal.influence.domain.OSInfluenceType; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; -import org.robolectric.shadows.ShadowPausedSystemClock; - -import java.util.Arrays; -import java.util.List; - -import static com.onesignal.OneSignalPackagePrivateHelper.FCMBroadcastReceiver_onReceived_withBundle; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_handleNotificationOpen; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSharedPreferences; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.GenerateNotificationRunner.getBaseNotifBundle; -import static com.test.onesignal.RestClientAsserts.assertMeasureAtIndex; -import static com.test.onesignal.RestClientAsserts.assertMeasureOnV2AtIndex; -import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndex; -import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndexDoesNotHaveKeys; -import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndexForPlayerId; -import static com.test.onesignal.RestClientAsserts.assertRestCalls; -import static com.test.onesignal.TestHelpers.afterTestCleanup; -import static com.test.onesignal.TestHelpers.assertAndRunSyncService; -import static com.test.onesignal.TestHelpers.fastColdRestartApp; -import static com.test.onesignal.TestHelpers.getAllNotificationRecords; -import static com.test.onesignal.TestHelpers.getAllUniqueOutcomeNotificationRecordsDB; -import static com.test.onesignal.TestHelpers.pauseActivity; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowPausedSystemClock.class, - ShadowOneSignalRestClient.class, - ShadowPushRegistratorFCM.class, - ShadowGMSLocationController.class, - ShadowOSUtils.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowNotificationManagerCompat.class, - ShadowJobService.class, - ShadowFocusHandler.class - }, - sdk = 26) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class OutcomeEventIntegrationTests { - - private static final String ONESIGNAL_APP_ID = "b2f7f966-d8cc-11e4-bed1-df8f05be55ba"; - private static final String ONESIGNAL_NOTIFICATION_ID = "97d8e764-81c2-49b0-a644-713d052ae7d5"; - private static final String ONESIGNAL_OUTCOME_NAME = "Testing_Outcome"; - - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - private static String notificationOpenedMessage; - private MockOneSignalDBHelper dbHelper; - private MockOSLog logger = new MockOSLog(); - private MockOSTimeImpl time; - private MockSessionManager sessionManager; - private OneSignalPackagePrivateHelper.OSSharedPreferencesWrapper preferences; - private OSTrackerFactory trackerFactory; - private static List lastInfluencesEnding; - private static OSNotificationOpenedResult notificationOpenedResult; - - OSSessionManager.SessionListener sessionListener = lastInfluences -> { - OneSignal_getSessionListener().onSessionEnding(lastInfluences); - OutcomeEventIntegrationTests.lastInfluencesEnding = lastInfluences; - }; - - private static OneSignal.OSNotificationOpenedHandler getNotificationOpenedHandler() { - return openedResult -> notificationOpenedMessage = openedResult.getNotification().getBody(); - } - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - } - - private static void cleanUp() throws Exception { - notificationOpenedMessage = null; - - TestHelpers.beforeTestInitAndCleanup(); - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - } - - @Before - public void beforeEachTest() throws Exception { - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - time = new MockOSTimeImpl(); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - preferences = new OneSignalPackagePrivateHelper.OSSharedPreferencesWrapper(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - cleanUp(); - } - - @After - public void afterEachTest() throws Exception { - lastInfluencesEnding = null; - notificationOpenedResult = null; - afterTestCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - cleanUp(); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testAppSessions_beforeOnSessionCalls() throws Exception { - foregroundAppAfterReceivingNotification(); - - // Check session INDIRECT - assertNotificationChannelIndirectInfluence(1); - - // Background app - pauseActivity(blankActivityController); - - // Click notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID + "2"); - threadAndTaskWait(); - - // Foreground app - blankActivityController.resume(); - threadAndTaskWait(); - - // Check session DIRECT - assertNotificationChannelDirectInfluence(ONESIGNAL_NOTIFICATION_ID + "2"); - // Upgrade on influence will end indirect session - assertEquals(1, lastInfluencesEnding.size()); - // Upgrade on influence will end indirect session - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, lastInfluencesEnding.get(0).getInfluenceType()); - assertEquals(1, lastInfluencesEnding.get(0).getIds().length()); - assertEquals(ONESIGNAL_NOTIFICATION_ID + "1", lastInfluencesEnding.get(0).getIds().get(0)); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testAppSessions_afterOnSessionCalls() throws Exception { - foregroundAppAfterReceivingNotification(); - - // Check session INDIRECT - assertNotificationChannelIndirectInfluence(1); - - // Background app for 30 seconds - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(31); - - // Click notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID + "2"); - threadAndTaskWait(); - - // Foreground app - blankActivityController.resume(); - threadAndTaskWait(); - - // Check session DIRECT - assertNotificationChannelDirectInfluence(ONESIGNAL_NOTIFICATION_ID + "2"); - // Upgrade on influence will end indirect session - assertEquals(1, lastInfluencesEnding.size()); - // Upgrade on influence will end indirect session - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, lastInfluencesEnding.get(0).getInfluenceType()); - assertEquals(1, lastInfluencesEnding.get(0).getIds().length()); - assertEquals(ONESIGNAL_NOTIFICATION_ID + "1", lastInfluencesEnding.get(0).getIds().get(0)); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectAttributionWindow_withNoNotifications() throws Exception { - foregroundAppAfterReceivingNotification(); - - // Check received notifications matches indirectNotificationIds - assertEquals(new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1"), trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Check session INDIRECT - assertNotificationChannelIndirectInfluence(1); - - // Background app for attribution window time - pauseActivity(blankActivityController); - time.advanceSystemTimeBy(24L * 60 * 60L); - - // Foreground app - blankActivityController.resume(); - threadAndTaskWait(); - - // Check session UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - } - - @Test - public void testUniqueOutcomeMeasureOnlySentOncePerClickedNotification_whenSendingMultipleUniqueOutcomes_inDirectSession() throws Exception { - foregroundAppAfterClickingNotification(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check measure end point was most recent request and contains clicked notification - assertMeasureAtIndex(3, true, ONESIGNAL_OUTCOME_NAME, new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1")); - // Only 4 requests have been made - assertRestCalls(4); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make still only 4 requests have been made - assertRestCalls(4); - } - - @Test - public void testOnV2UniqueOutcomeMeasureOnlySentOncePerClickedNotification_whenSendingMultipleUniqueOutcomes_inDirectSession() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - OneSignal_setSharedPreferences(preferences); - foregroundAppAfterClickingNotification(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - JSONArray notificationIds = new JSONArray(); - notificationIds.put(ONESIGNAL_NOTIFICATION_ID + "1"); - - // Check measure end point was most recent request and contains clicked notification - assertMeasureOnV2AtIndex(3, ONESIGNAL_OUTCOME_NAME, new JSONArray(), notificationIds, null, null); - // Only 4 requests have been made - assertRestCalls(4); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make still only 4 requests have been made - assertRestCalls(4); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testUniqueOutcomeMeasureOnlySentOncePerNotification_whenSendingMultipleUniqueOutcomes_inIndirectSessions() throws Exception { - foregroundAppAfterReceivingNotification(); - - // Check notificationIds equal indirectNotificationIds from OSSessionManager - JSONArray notificationIds = new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1"); - assertEquals(notificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(1); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check measure end point was most recent request and contains received notification - assertMeasureAtIndex(2, false, ONESIGNAL_OUTCOME_NAME, new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1")); - // Only 3 requests have been made - assertRestCalls(3); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make still only 3 requests have been made - assertRestCalls(3); - - // Background app - pauseActivity(blankActivityController); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Wait 31 seconds to start new session - time.advanceSystemTimeBy(31); - - // Foreground app will start a new session upgrade - blankActivityController.resume(); - threadAndTaskWait(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check notificationIds are not equal indirectNotificationIds from OSSessionManager - notificationIds.put(ONESIGNAL_NOTIFICATION_ID + "2"); - assertEquals(notificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(2); - - // Check measure end point was most recent request and contains received notification - assertMeasureAtIndex(4, false, ONESIGNAL_OUTCOME_NAME, new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "2")); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testOnV2UniqueOutcomeMeasureOnlySentOncePerNotification_whenSendingMultipleUniqueOutcomes_inIndirectSessions() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - OneSignal_setSharedPreferences(preferences); - foregroundAppAfterReceivingNotification(); - - // Check notificationIds equal indirectNotificationIds from OSSessionManager - JSONArray notificationIds = new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1"); - assertEquals(notificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(1); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check measure end point was most recent request and contains received notification - assertMeasureOnV2AtIndex(2, ONESIGNAL_OUTCOME_NAME, null, null, new JSONArray(), notificationIds); - // Only 3 requests have been made - assertRestCalls(3); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make still only 3 requests have been made - assertRestCalls(3); - - // Background app - pauseActivity(blankActivityController); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Wait 31 seconds to start new session - time.advanceSystemTimeBy(31); - - // Foreground app will start a new session upgrade - blankActivityController.resume(); - threadAndTaskWait(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check notificationIds are not equal indirectNotificationIds from OSSessionManager - notificationIds.put(ONESIGNAL_NOTIFICATION_ID + "2"); - assertEquals(notificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(2); - - // Check measure end point was most recent request and contains received notification - assertMeasureOnV2AtIndex(4, ONESIGNAL_OUTCOME_NAME, null, null, new JSONArray(), new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "2")); - } - - @Test - public void testOutcomeNameSentWithMeasureOncePerSession_whenSendingMultipleUniqueOutcomes_inUnattributedSession() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Make sure session is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check measure end point was most recent request and contains received notification - assertMeasureAtIndex(2, ONESIGNAL_OUTCOME_NAME); - // Only 3 requests have been made - assertRestCalls(3); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make still only 3 requests have been made - assertRestCalls(3); - - // Background app - pauseActivity(blankActivityController); - - // Wait 31 seconds to start new session - time.advanceSystemTimeBy(31); - - // Foreground app - blankActivityController.resume(); - threadAndTaskWait(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make sure session is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - - // Check measure end point was most recent request and contains received notification - assertMeasureAtIndex(4, ONESIGNAL_OUTCOME_NAME); - } - - @Test - public void testOnV2OutcomeNameSentWithMeasureOncePerSession_whenSendingMultipleUniqueOutcomes_inUnattributedSession() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - OneSignal_setSharedPreferences(preferences); - - OneSignalInit(); - threadAndTaskWait(); - - // Make sure session is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check measure end point was most recent request and contains received notification - assertMeasureOnV2AtIndex(2, ONESIGNAL_OUTCOME_NAME, null, null, null, null); - // Only 3 requests have been made - assertRestCalls(3); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make still only 3 requests have been made - assertRestCalls(3); - - // Background app - pauseActivity(blankActivityController); - - // Wait 31 seconds to start new session - time.advanceSystemTimeBy(31); - - // Foreground app - blankActivityController.resume(); - threadAndTaskWait(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make sure session is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - - // Check measure end point was most recent request and contains received notification - assertMeasureOnV2AtIndex(4, ONESIGNAL_OUTCOME_NAME, null, null, null, null); - } - - @Test - public void testCorrectOutcomeSent_fromNotificationOpenedHandler() throws Exception { - // Init OneSignal with a custom opened handler - OneSignalInit(new OneSignal.OSNotificationOpenedHandler() { - @Override - public void notificationOpened(OSNotificationOpenedResult result) { - OneSignal.sendOutcome(ONESIGNAL_OUTCOME_NAME); - } - }); - threadAndTaskWait(); - - // Background app - pauseActivity(blankActivityController); - - // Receive and open a notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - threadAndTaskWait(); - - // Foreground the application - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure a measure request is made with the correct session and notifications - assertMeasureAtIndex(3, true, ONESIGNAL_OUTCOME_NAME, new JSONArray("[" + ONESIGNAL_NOTIFICATION_ID + "]")); - } - - @Test - public void testOnV2CorrectOutcomeSent_fromNotificationOpenedHandler() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - OneSignal_setSharedPreferences(preferences); - - // Init OneSignal with a custom opened handler - OneSignalInit(new OneSignal.OSNotificationOpenedHandler() { - @Override - public void notificationOpened(OSNotificationOpenedResult result) { - OneSignal.sendOutcome(ONESIGNAL_OUTCOME_NAME); - } - }); - threadAndTaskWait(); - - // Background app - pauseActivity(blankActivityController); - - // Receive and open a notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - threadAndTaskWait(); - - // Foreground the application - blankActivityController.resume(); - threadAndTaskWait(); - - JSONArray notificationIds = new JSONArray(); - notificationIds.put(ONESIGNAL_NOTIFICATION_ID); - - // Make sure a measure request is made with the correct session and notifications - assertMeasureOnV2AtIndex(3, ONESIGNAL_OUTCOME_NAME, new JSONArray(), notificationIds, null, null); - } - - @Test - public void testNoDirectSession_fromNotificationOpen_whenAppIsInForeground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Make sure no notification data exists - assertNull(notificationOpenedMessage); - - // Click notification - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID); - threadAndTaskWait(); - - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedMessage); - // Make sure session is not DIRECT - assertFalse(trackerFactory.getNotificationChannelTracker().getInfluenceType().isDirect()); - // Make sure session is not INDIRECT - assertFalse(trackerFactory.getNotificationChannelTracker().getInfluenceType().isIndirect()); - // Make sure no session is ending - assertNull(lastInfluencesEnding); - } - - @Test - public void testDirectSession_fromNotificationOpen_whenAppIsInBackground() throws Exception { - foregroundAppAfterClickingNotification(); - - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedMessage); - // Make sure notification influence is DIRECT - assertNotificationChannelDirectInfluence(ONESIGNAL_NOTIFICATION_ID + "1"); - } - - @Test - @Config(shadows = { OneSignalShadowPackageManager.class }) - public void testDirectSession_fromNotificationClick_OpenHandleByUser_whenAppIsInBackground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - OneSignal.setNotificationOpenedHandler(result -> { - OneSignal.onesignalLog(OneSignal.LOG_LEVEL.VERBOSE, "OSNotificationOpenedHandler called with result: " + result); - notificationOpenedResult = result; - - // App opened after clicking notification, but Robolectric needs this to simulate onAppFocus() code after a click - blankActivityController.resume(); - }); - - // Background app - pauseActivity(blankActivityController); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - sessionManager.onNotificationReceived(notificationID); - - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"" + notificationID + "\" } }]"), notificationID); - threadAndTaskWait(); - - assertNotNull(notificationOpenedResult); - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedResult.getNotification().getBody()); - - // Make sure notification influence is DIRECT - assertNotificationChannelDirectInfluence(notificationID); - // Make sure iam influence is UNATTRIBUTED - assertIAMChannelUnattributedInfluence(); - - for (OSInfluence influence : lastInfluencesEnding) { - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - } - } - - @Test - @Config(shadows = { OneSignalShadowPackageManager.class }) - public void testDirectSession_fromNotificationClick_OpenHandleByUser_NewSession_whenAppIsInBackground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - OneSignal.setNotificationOpenedHandler(result -> { - OneSignal.onesignalLog(OneSignal.LOG_LEVEL.VERBOSE, "OSNotificationOpenedHandler called with result: " + result); - notificationOpenedResult = result; - - // App opened after clicking notification, but Robolectric needs this to simulate onAppFocus() code after a click - blankActivityController.resume(); - }); - - // Background app - pauseActivity(blankActivityController); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - sessionManager.onNotificationReceived(notificationID); - - time.advanceSystemAndElapsedTimeBy(61); - - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"" + notificationID + "\" } }]"), notificationID); - threadAndTaskWait(); - - assertNotNull(notificationOpenedResult); - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedResult.getNotification().getBody()); - - // Make sure notification influence is DIRECT - assertNotificationChannelDirectInfluence(notificationID); - // Make sure iam influence is UNATTRIBUTED - assertIAMChannelUnattributedInfluence(); - - for (OSInfluence influence : lastInfluencesEnding) { - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - } - } - - @Test - @Config(shadows = { OneSignalShadowPackageManager.class, ShadowTimeoutHandler.class }) - public void testDirectSession_fromNotificationClick_NoOpened_whenAppIsInBackground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - OneSignal.setNotificationOpenedHandler(result -> { - OneSignal.onesignalLog(OneSignal.LOG_LEVEL.VERBOSE, "OSNotificationOpenedHandler called with result: " + result); - notificationOpenedResult = result; - }); - - // Background app - pauseActivity(blankActivityController); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - sessionManager.onNotificationReceived(notificationID); - - // Mock timeout to 1, given that we are delaying the complete inside OSNotificationOpenedResult - // We depend on the timeout complete - ShadowTimeoutHandler.setMockDelayMillis(1); - - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"" + notificationID + "\" } }]"), notificationID); - threadAndTaskWait(); - - assertNotNull(notificationOpenedResult); - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedResult.getNotification().getBody()); - - // Make sure notification influence is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - // Make sure iam influence is UNATTRIBUTED - assertIAMChannelUnattributedInfluence(); - - assertNull(lastInfluencesEnding); - } - - @Test - @Config(shadows = { OneSignalShadowPackageManager.class, ShadowTimeoutHandler.class }) - public void testDirectSession_fromNotificationClick_NoOpened_NewSession_whenAppIsInBackground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - OneSignal.setNotificationOpenedHandler(result -> { - OneSignal.onesignalLog(OneSignal.LOG_LEVEL.VERBOSE, "OSNotificationOpenedHandler called with result: " + result); - notificationOpenedResult = result; - }); - - // Background app - pauseActivity(blankActivityController); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - sessionManager.onNotificationReceived(notificationID); - - // Mock timeout to 1, given that we are delaying the complete inside OSNotificationOpenedResult - // We depend on the timeout complete - ShadowTimeoutHandler.setMockDelayMillis(1); - time.advanceSystemAndElapsedTimeBy(61); - - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"" + notificationID + "\" } }]"), notificationID); - threadAndTaskWait(); - - assertNotNull(notificationOpenedResult); - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedResult.getNotification().getBody()); - - // Make sure notification influence is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - // Make sure iam influence is UNATTRIBUTED - assertIAMChannelUnattributedInfluence(); - - assertNull(lastInfluencesEnding); - } - - @Test - @Config(shadows = { OneSignalShadowPackageManager.class }) - public void testDirectSession_fromNotificationClick_OpenHandleByUser_whenAppIsInForeground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationOpened.DEFAULT", "DISABLE"); - OneSignal.setNotificationOpenedHandler(result -> { - OneSignal.onesignalLog(OneSignal.LOG_LEVEL.VERBOSE, "OSNotificationOpenedHandler called with result: " + result); - notificationOpenedResult = result; - }); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - sessionManager.onNotificationReceived(notificationID); - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"" + notificationID + "\" } }]"), notificationID); - threadAndTaskWait(); - - assertNotNull(notificationOpenedResult); - // Check message String matches data sent in open handler - assertEquals("Test Msg", notificationOpenedResult.getNotification().getBody()); - - // Make sure notification influence is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - // Make sure iam influence is UNATTRIBUTED - assertIAMChannelUnattributedInfluence(); - - assertNull(lastInfluencesEnding); - } - - @Test - public void testIndirectSession_wontOverrideUnattributedSession_fromNotificationReceived_whenAppIsInForeground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Make sure session is unattributed - assertNotificationChannelUnattributedInfluence(); - assertIAMChannelUnattributedInfluence(); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Make sure notification influence is not INDIRECT - assertFalse(trackerFactory.getNotificationChannelTracker().getInfluenceType().isIndirect()); - // Make sure not indirect notifications exist - assertNull(trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Make sure not session is ending - assertNull(lastInfluencesEnding); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testDirectSession_willOverrideIndirectSession_whenAppIsInBackground() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - foregroundAppAfterReceivingNotification(); - - // Foreground for 10 seconds - time.advanceSystemAndElapsedTimeBy(10); - - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(1); - - // Background app - pauseActivity(blankActivityController); - - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID + "2"); - threadAndTaskWait(); - - // Foreground app - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure on_focus is sent immediately since DIRECT session is going to override - assertOnFocusAtIndex(3, new JSONObject() {{ - put("active_time", 10); - put("direct", false); - put("notification_ids", new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1")); - }}); - // Check directNotificationId is set to clicked notification - assertEquals(ONESIGNAL_NOTIFICATION_ID + "2", trackerFactory.getNotificationChannelTracker().getDirectId()); - // Make sure session is DIRECT - assertNotificationChannelDirectInfluence(ONESIGNAL_NOTIFICATION_ID + "2"); - } - - @Test - public void testDirectSession_willOverrideDirectSession_whenAppIsInBackground() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Background app - pauseActivity(blankActivityController); - - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"UUID\" } }]"), ONESIGNAL_NOTIFICATION_ID + "2"); - threadAndTaskWait(); - - // Check directNotificationId is set to clicked notification - assertEquals(ONESIGNAL_NOTIFICATION_ID + "2", trackerFactory.getNotificationChannelTracker().getDirectId()); - // Make sure session is DIRECT - assertNotificationChannelDirectInfluence(ONESIGNAL_NOTIFICATION_ID + "2"); - // Make sure session is ending - assertEquals(1, lastInfluencesEnding.size()); - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.UNATTRIBUTED, lastInfluencesEnding.get(0).getInfluenceType()); - assertNull(lastInfluencesEnding.get(0).getIds()); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectSession_fromDirectSession_afterNewSession() throws Exception { - foregroundAppAfterClickingNotification(); - - // Background app - pauseActivity(blankActivityController); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Wait 31 seconds - time.advanceSystemTimeBy(31); - - // Foreground app through icon before new session - blankActivityController.resume(); - threadAndTaskWait(); - - // Check on_session is triggered - assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players/.*/on_session")); - // Make sure no directNotificationId exist - assertNull(trackerFactory.getNotificationChannelTracker().getDirectId()); - // Make sure indirectNotificationIds are correct - assertEquals(new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1").put(ONESIGNAL_NOTIFICATION_ID + "2"), trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(2); - - // Make sure session is ending - assertEquals(1, lastInfluencesEnding.size()); - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.DIRECT, lastInfluencesEnding.get(0).getInfluenceType()); - assertEquals(1, lastInfluencesEnding.get(0).getIds().length()); - assertEquals(ONESIGNAL_NOTIFICATION_ID + "1", lastInfluencesEnding.get(0).getIds().get(0)); - } - - @Test - public void testIndirectSession_wontOverrideDirectSession_beforeNewSession() throws Exception { - foregroundAppAfterClickingNotification(); - - // Background app - pauseActivity(blankActivityController); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Foreground app through icon before new session - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure no indirectNotificationIds exist - assertNull(trackerFactory.getNotificationChannelTracker().getIndirectIds()); - // Check directNotificationId is set to clicked notification - assertEquals(ONESIGNAL_NOTIFICATION_ID + "1", trackerFactory.getNotificationChannelTracker().getDirectId()); - // Make sure session is DIRECT - assertNotificationChannelDirectInfluence(ONESIGNAL_NOTIFICATION_ID + "1"); - // Make sure no session is ending - assertNull(lastInfluencesEnding); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectSession_wontOverrideIndirectSession_beforeNewSession() throws Exception { - foregroundAppAfterReceivingNotification(); - - // Background app - pauseActivity(blankActivityController); - - // Receive another notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Foreground app through icon before new session - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure indirectNotificationIds are correct - JSONArray indirectNotificationIds = new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1"); - assertEquals(indirectNotificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - - // Make sure session is INDIRECT - assertNotificationChannelIndirectInfluence(1); - // Make sure no session is ending - assertNull(lastInfluencesEnding); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectSession_sendsOnFocusFromSyncJob_after10SecondSession() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - foregroundAppAfterReceivingNotification(); - - // App in foreground for 10 seconds - time.advanceSystemAndElapsedTimeBy(10); - - // Background app - // Sync job will be scheduled here but not run yet - pauseActivity(blankActivityController); - - assertAndRunSyncService(); - assertOnFocusAtIndex(2, new JSONObject() {{ - put("active_time", 10); - put("direct", false); - put("notification_ids", new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1")); - }}); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectSession_sendsOnFocusFromSyncJob_evenAfterKillingApp_after10SecondSession() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - foregroundAppAfterReceivingNotification(); - - // App in foreground for 10 seconds - time.advanceSystemAndElapsedTimeBy(10); - - // Background app - // Sync job will be scheduled here but not run yet - pauseActivity(blankActivityController); - - fastColdRestartApp(); - - assertAndRunSyncService(); - - assertOnFocusAtIndex(3, new JSONObject() {{ - put("active_time", 10); - put("direct", false); - put("notification_ids", new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1")); - }}); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectSession_sendsOnFocusAttributionForPushPlayer_butNotEmailPlayer() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - OneSignal.setEmail("test@test.com"); - foregroundAppAfterReceivingNotification(); - - // App in foreground for 10 seconds - time.advanceSystemAndElapsedTimeBy(10); - - // Background app - // Sync job will be scheduled here but not run yet - pauseActivity(blankActivityController); - - assertAndRunSyncService(); - // Ensure we send notification attribution for push player - assertOnFocusAtIndexForPlayerId(4, ShadowOneSignalRestClient.pushUserId); - assertOnFocusAtIndex(4, new JSONObject() {{ - put("active_time", 10); - put("direct", false); - put("notification_ids", new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1")); - }}); - - // Ensure we DO NOT send notification attribution for email player - // Otherwise it would look like 2 different session to outcomes. - assertOnFocusAtIndexForPlayerId(5, ShadowOneSignalRestClient.emailUserId); - assertOnFocusAtIndexDoesNotHaveKeys(5, Arrays.asList("direct", "notification_ids")); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testIndirectSessionNotificationsUpdated_onNewIndirectSession() throws Exception { - foregroundAppAfterReceivingNotification(); - - // Make sure indirectNotificationIds are correct - JSONArray indirectNotificationIds = new JSONArray().put(ONESIGNAL_NOTIFICATION_ID + "1"); - assertEquals(indirectNotificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - - // Background app - pauseActivity(blankActivityController); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - indirectNotificationIds.put(ONESIGNAL_NOTIFICATION_ID + "2"); - - // App in background for 31 seconds to trigger new session - time.advanceSystemTimeBy(31); - - // Foreground app through icon - blankActivityController.resume(); - threadAndTaskWait(); - - // Make sure indirectNotificationIds are updated and correct - assertEquals(indirectNotificationIds, trackerFactory.getNotificationChannelTracker().getIndirectIds()); - - // Make sure session is ending - assertEquals(1, lastInfluencesEnding.size()); - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, lastInfluencesEnding.get(0).getInfluenceType()); - assertEquals(1, lastInfluencesEnding.get(0).getIds().length()); - assertEquals(ONESIGNAL_NOTIFICATION_ID + "1", lastInfluencesEnding.get(0).getIds().get(0)); - } - - @Test - @Config(shadows = { ShadowGenerateNotification.class }) - public void testCleaningCachedNotifications_after7Days_willAlsoCleanUniqueOutcomeNotifications() throws Exception { - foregroundAppAfterReceivingNotification(); - - assertEquals(1, getAllNotificationRecords(dbHelper).size()); - assertEquals(0, getAllUniqueOutcomeNotificationRecordsDB(dbHelper).size()); - - // Should add a new unique outcome notifications (total in cache = 0 + 1) - OneSignal.sendUniqueOutcome("unique_1"); - threadAndTaskWait(); - - // Should not add a new unique outcome notifications (total in cache = 1) - OneSignal.sendUniqueOutcome("unique_1"); - threadAndTaskWait(); - - assertEquals(1, getAllNotificationRecords(dbHelper).size()); - assertEquals(1, getAllUniqueOutcomeNotificationRecordsDB(dbHelper).size()); - - // Background app - pauseActivity(blankActivityController); - - // Wait for 30 seconds to trigger new session - time.advanceSystemTimeBy(31); - - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "2"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Foreground app through icon - blankActivityController.resume(); - threadAndTaskWait(); - - // Should add two unique outcome notifications (total in cache = 1 + 2) - OneSignal.sendUniqueOutcome("unique_2"); - threadAndTaskWait(); - - // Should add two unique outcome notifications (total in cache = 3 + 2) - OneSignal.sendUniqueOutcome("unique_3"); - threadAndTaskWait(); - - // Make sure only 2 notifications exist still, but 5 unique outcome notifications exist - assertEquals(2, getAllNotificationRecords(dbHelper).size()); - assertEquals(5, getAllUniqueOutcomeNotificationRecordsDB(dbHelper).size()); - - // Wait a week to clear cached notifications - time.advanceSystemTimeBy(604_800); - - // Restart the app and re-init OneSignal - fastColdRestartApp(); - OneSignalInit(); - threadAndTaskWait(); - - // Make sure when notification cache is cleaned so is the unique outcome events cache - assertEquals(0, getAllNotificationRecords(dbHelper).size()); - assertEquals(0, getAllUniqueOutcomeNotificationRecordsDB(dbHelper).size()); - } - - @Test - public void testDelayOutcomes() throws Exception { - OneSignal.sendOutcome(ONESIGNAL_OUTCOME_NAME); - OneSignalInit(); - threadAndTaskWait(); - - // Foreground app through icon - blankActivityController.resume(); - threadAndTaskWait(); - - assertMeasureAtIndex(1, ONESIGNAL_OUTCOME_NAME); - } - - @Test - public void testSendOutcomesFailWhenRequiresUserPrivacyConsent() throws Exception { - // Enable IAM v2 - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - preferences.saveBool(preferences.getPreferencesName(), preferences.getOutcomesV2KeyName(), true); - OneSignal_setSharedPreferences(preferences); - - OneSignalInit(); - threadAndTaskWait(); - assertRestCalls(2); - OneSignal.setRequiresUserPrivacyConsent(true); - - // Make sure session is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Check that the task has been queued until consent is given - assertRestCalls(2); - - // Send outcome event - OneSignal.sendOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Ensure still only 2 requests have been made - assertRestCalls(2); - - OneSignal.provideUserConsent(true); - threadAndTaskWait(); - - // Send unique outcome event - OneSignal.sendUniqueOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Send outcome event - OneSignal.sendOutcome(ONESIGNAL_OUTCOME_NAME); - threadAndTaskWait(); - - // Make sure session is UNATTRIBUTED - assertNotificationChannelUnattributedInfluence(); - - // Check measure end point was most recent request and contains received notification - assertMeasureOnV2AtIndex(3, ONESIGNAL_OUTCOME_NAME, null, null, null, null); - } - - private void foregroundAppAfterClickingNotification() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Make sure no notification data exists - assertNull(notificationOpenedMessage); - // Make no direct notification id is set - assertNull(trackerFactory.getNotificationChannelTracker().getDirectId()); - // Make sure all influences are UNATTRIBUTED - List influences = sessionManager.getInfluences(); - for (OSInfluence influence : influences) { - assertTrue(influence.getInfluenceType().isUnattributed()); - } - - // Background app - pauseActivity(blankActivityController); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - sessionManager.onNotificationReceived(notificationID); - // Click notification before new session - OneSignal_handleNotificationOpen(blankActivity, new JSONArray("[{ \"alert\": \"Test Msg\", \"custom\": { \"i\": \"" + notificationID + "\" } }]"), notificationID); - threadAndTaskWait(); - - // App opened after clicking notification, but Robolectric needs this to simulate onAppFocus() code after a click - blankActivityController.resume(); - threadAndTaskWait(); - - // Check directNotificationId is set to clicked notification - assertEquals(notificationID, trackerFactory.getNotificationChannelTracker().getDirectId()); - // Make sure notification influence is DIRECT - assertNotificationChannelDirectInfluence(notificationID); - // Make sure iam influence is UNATTRIBUTED - assertIAMChannelUnattributedInfluence(); - - // Upgrade on influence will end unattributed session - assertEquals(1, lastInfluencesEnding.size()); - for (OSInfluence influence : lastInfluencesEnding) { - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - } - - // Reset for upcoming asserts - lastInfluencesEnding = null; - } - - private void foregroundAppAfterReceivingNotification() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - // Make sure all influences are UNATTRIBUTED - List influences = sessionManager.getInfluences(); - for (OSInfluence influence : influences) { - assertTrue(influence.getInfluenceType().isUnattributed()); - } - - // Background app - pauseActivity(blankActivityController); - - String notificationID = ONESIGNAL_NOTIFICATION_ID + "1"; - // Receive notification - Bundle bundle = getBaseNotifBundle(ONESIGNAL_NOTIFICATION_ID + "1"); - FCMBroadcastReceiver_onReceived_withBundle(blankActivity, bundle); - - // Check notification was saved - assertEquals(1, trackerFactory.getNotificationChannelTracker().getLastReceivedIds().length()); - assertEquals(notificationID, trackerFactory.getNotificationChannelTracker().getLastReceivedIds().get(0)); - - // Foreground app through icon - blankActivityController.resume(); - threadAndTaskWait(); - - // Upgrade on influence will end unattributed session - assertEquals(1, lastInfluencesEnding.size()); - for (OSInfluence influence : lastInfluencesEnding) { - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - } - - // Reset for upcoming asserts - lastInfluencesEnding = null; - } - - private void assertNotificationChannelDirectInfluence(String id) throws JSONException { - OSInfluence influence = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isDirect()); - assertEquals(1, influence.getIds().length()); - assertEquals(id, influence.getIds().get(0)); - } - - private void assertNotificationChannelIndirectInfluence(int indirectIdsLength) { - OSInfluence influence = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isIndirect()); - assertEquals(indirectIdsLength, influence.getIds().length()); - } - - private void assertIAMChannelUnattributedInfluence() { - OSInfluence influence = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isUnattributed()); - assertNull(influence.getIds()); - } - - private void assertIAMChannelDirectInfluence() { - OSInfluence influence = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isDirect()); - assertEquals(1, influence.getIds().length()); - } - - private void assertIAMChannelIndirectInfluence(int indirectIdsLength) { - OSInfluence influence = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isIndirect()); - assertEquals(indirectIdsLength, influence.getIds().length()); - } - - private void assertNotificationChannelUnattributedInfluence() { - OSInfluence influence = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isUnattributed()); - assertNull(influence.getIds()); - } - - private void OneSignalInit() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - // Set mocks for mocking behaviour - OneSignal_setTime(time); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler()); - threadAndTaskWait(); - blankActivityController.resume(); - } - - private void OneSignalInit(OneSignal.OSNotificationOpenedHandler notificationOpenedHandler) throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - // Set mocks for mocking behaviour - OneSignal_setTime(time); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - OneSignal.setNotificationOpenedHandler(notificationOpenedHandler); - threadAndTaskWait(); - blankActivityController.resume(); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventUnitTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventUnitTests.java deleted file mode 100644 index 56e03f7ed..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventUnitTests.java +++ /dev/null @@ -1,548 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import androidx.annotation.NonNull; -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalAPIClient; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockOutcomeEventsController; -import com.onesignal.MockSessionManager; -import com.onesignal.OSSessionManager; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalRemoteParams; -import com.onesignal.ShadowOSUtils; -import com.onesignal.StaticResetHelper; -import com.onesignal.influence.data.OSTrackerFactory; -import com.onesignal.influence.domain.OSInfluence; -import com.onesignal.outcomes.data.OSOutcomeEventsFactory; -import com.onesignal.outcomes.domain.OSOutcomeEventParams; -import com.onesignal.outcomes.domain.OSOutcomeEventsRepository; - -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.util.List; - -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class, - }, - sdk = 21) -@RunWith(RobolectricTestRunner.class) -public class OutcomeEventUnitTests { - - private static final String OUTCOME_NAME = "testing"; - private static final String NOTIFICATION_ID = "testing"; - private static final String APP_ID = "123456789"; - - private MockOutcomeEventsController controller; - private MockOneSignalAPIClient service; - private OSOutcomeEventsRepository repository; - private MockOSSharedPreferences preferences; - private OSTrackerFactory trackerFactory; - private MockSessionManager sessionManager; - private MockOneSignalDBHelper dbHelper; - private MockOSLog logWrapper = new MockOSLog(); - private OSSessionManager.SessionListener sessionListener = new OSSessionManager.SessionListener() { - @Override - public void onSessionEnding(@NonNull List lastInfluences) { - - } - }; - - private OneSignalRemoteParams.InfluenceParams disabledInfluenceParams = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false); - - private static List outcomeEvents; - - public interface OutcomeEventsHandler { - void setOutcomes(List outcomes); - } - - private OutcomeEventsHandler handler = new OutcomeEventsHandler() { - @Override - public void setOutcomes(List outcomes) { - outcomeEvents = outcomes; - } - }; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - outcomeEvents = null; - - MockOSTimeImpl time = new MockOSTimeImpl(); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - // Mock on a custom HashMap in order to not use custom context - preferences = new MockOSSharedPreferences(); - - trackerFactory = new OSTrackerFactory(preferences, logWrapper, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logWrapper); - service = new MockOneSignalAPIClient(); - OSOutcomeEventsFactory factory = new OSOutcomeEventsFactory(logWrapper, service, dbHelper, preferences); - controller = new MockOutcomeEventsController(sessionManager, factory); - - TestHelpers.beforeTestInitAndCleanup(); - repository = factory.getRepository(); - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - OneSignal.setAppId(APP_ID); - } - - @After - public void tearDown() throws Exception { - dbHelper.close(); - StaticResetHelper.restSetStaticFields(); - threadAndTaskWait(); - } - - @Test - public void testDirectOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"notification_ids\":[\"testing\"],\"id\":\"testing\",\"app_id\":\"" + APP_ID + "\",\"device_type\":1,\"direct\":true}", service.getLastJsonObjectSent()); - } - - @Test - public void testIndirectOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - // Restart session by app open should set INDIRECT influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"notification_ids\":[\"testing\"],\"id\":\"testing\",\"app_id\":\"" + APP_ID + "\",\"device_type\":1,\"direct\":false}", service.getLastJsonObjectSent()); - } - - @Test - public void testUnattributedOutcomeSuccess() throws Exception { - service.setSuccess(true); - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDisabledOutcomeSuccess() throws Exception { - service.setSuccess(true); - // DISABLED influence - trackerFactory.saveInfluenceParams(disabledInfluenceParams); - // Init session should set UNATTRIBUTED influence but is DISABLED - sessionManager.initSessionFromCache(); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{}", service.getLastJsonObjectSent()); - } - - @Test - public void testUnattributedOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDisableOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - // DISABLED influence - trackerFactory.saveInfluenceParams(disabledInfluenceParams); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{}", service.getLastJsonObjectSent()); - } - - @Test - public void testDirectOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"notification_ids\":[\"testing\"],\"id\":\"testing\",\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1,\"direct\":true}", service.getLastJsonObjectSent()); - } - - @Test - public void testIndirectOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - // Restart session by app open should set INDIRECT influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_SUCCESS").start(); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"notification_ids\":[\"testing\"],\"id\":\"testing\",\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1,\"direct\":false}", service.getLastJsonObjectSent()); - } - - @Test - public void testUniqueOutcomeFailSavedOnDBResetSession() throws Exception { - service.setSuccess(false); - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAIL").start(); - - threadAndTaskWait(); - assertEquals(1, outcomeEvents.size()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - assertEquals("{\"id\":\"testing\",\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - - controller.cleanOutcomes(); - - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAIL").start(); - - threadAndTaskWait(); - assertEquals(2, outcomeEvents.size()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(1).getOutcomeId()); - } - - @Test - public void testUniqueOutcomeFailSavedOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAIL").start(); - - threadAndTaskWait(); - assertEquals(1, outcomeEvents.size()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - } - - @Test - public void testOutcomeFailSavedOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAIL").start(); - - threadAndTaskWait(); - assertTrue(outcomeEvents.size() > 0); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - } - - @Test - public void testOutcomeMultipleFailsSavedOnDB() throws Exception { - service.setSuccess(false); - - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - controller.sendOutcomeEvent(OUTCOME_NAME); - - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - controller.sendOutcomeEvent(OUTCOME_NAME + "1"); - - // Restart session by app open should set INDIRECT influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - controller.sendOutcomeEvent(OUTCOME_NAME + "2"); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAIL").start(); - threadAndTaskWait(); - - assertEquals(3, outcomeEvents.size()); - - // DISABLED influence - trackerFactory.saveInfluenceParams(disabledInfluenceParams); - controller.sendOutcomeEvent(OUTCOME_NAME + "3"); - controller.sendOutcomeEvent(OUTCOME_NAME + "4"); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAILS").start(); - - threadAndTaskWait(); - assertEquals(3, outcomeEvents.size()); - for (OSOutcomeEventParams outcomeEvent : outcomeEvents) { - // UNATTRIBUTED Case - if (outcomeEvent.isUnattributed()) { - assertEquals("OSOutcomeEventParams{outcomeId='testing', outcomeSource=OSOutcomeSource{directBody=null, indirectBody=null}, weight=0.0, timestamp=" + outcomeEvent.getTimestamp() + "}", outcomeEvent.toString()); - } else if (outcomeEvent.getOutcomeSource().getIndirectBody() != null) { // INDIRECT Case - assertEquals("OSOutcomeEventParams{outcomeId='testing2', outcomeSource=OSOutcomeSource{directBody=null, indirectBody=OSOutcomeSourceBody{notificationIds=[\"testing\"], inAppMessagesIds=[]}}, weight=0.0, timestamp=" + outcomeEvent.getTimestamp() + "}", outcomeEvent.toString()); - } else { // DIRECT Case - assertEquals("OSOutcomeEventParams{outcomeId='testing1', outcomeSource=OSOutcomeSource{directBody=OSOutcomeSourceBody{notificationIds=[\"testing\"], inAppMessagesIds=[]}, indirectBody=null}, weight=0.0, timestamp=" + outcomeEvent.getTimestamp() + "}", outcomeEvent.toString()); - } // DISABLED Case should not be save - } - } - - @Test - public void testSendFailedOutcomesOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - controller.sendOutcomeEvent(OUTCOME_NAME + "1"); - controller.sendOutcomeEventWithValue(OUTCOME_NAME + "2", 1); - controller.sendOutcomeEvent(OUTCOME_NAME + "3"); - controller.sendOutcomeEventWithValue(OUTCOME_NAME + "4", 1.1f); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAILS").start(); - - threadAndTaskWait(); - assertEquals(5, outcomeEvents.size()); - - service.setSuccess(true); - - controller.sendSavedOutcomes(); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAILS").start(); - threadAndTaskWait(); - - assertEquals(0, outcomeEvents.size()); - } - - @Test - public void testSendFailedOutcomeWithValueOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAILS").start(); - - threadAndTaskWait(); - assertEquals(1, outcomeEvents.size()); - assertEquals(1.1f, outcomeEvents.get(0).getWeight(), 0); - assertEquals("{\"id\":\"testing\",\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - - long timestamp = outcomeEvents.get(0).getTimestamp(); - service.setSuccess(true); - service.resetLastJsonObjectSent(); - controller.sendSavedOutcomes(); - threadAndTaskWait(); - - new Thread(new Runnable() { - @Override - public void run() { - handler.setOutcomes(repository.getSavedOutcomeEvents()); - } - }, "OS_GET_SAVED_OUTCOMES_FAILS").start(); - threadAndTaskWait(); - - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"weight\":1.1,\"timestamp\":" + timestamp + ",\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventV2UnitTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventV2UnitTests.java deleted file mode 100644 index 82659b9ec..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/OutcomeEventV2UnitTests.java +++ /dev/null @@ -1,630 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import androidx.annotation.NonNull; -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalAPIClient; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockOutcomeEventsController; -import com.onesignal.MockSessionManager; -import com.onesignal.OSSessionManager; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalRemoteParams; -import com.onesignal.ShadowOSUtils; -import com.onesignal.StaticResetHelper; -import com.onesignal.influence.data.OSTrackerFactory; -import com.onesignal.influence.domain.OSInfluence; -import com.onesignal.influence.domain.OSInfluenceType; -import com.onesignal.outcomes.data.OSOutcomeEventsFactory; -import com.onesignal.outcomes.domain.OSOutcomeEventParams; -import com.onesignal.outcomes.domain.OSOutcomeEventsRepository; - -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.util.List; - -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class, - }, - sdk = 21) -@RunWith(RobolectricTestRunner.class) -public class OutcomeEventV2UnitTests { - - private static final String OUTCOME_NAME = "testing"; - private static final String IAM_ID = "iam_id"; - private static final String NOTIFICATION_ID = "notification_id"; - private static final String APP_ID = "123456789"; - - private MockOutcomeEventsController controller; - private MockOneSignalAPIClient service; - private OSOutcomeEventsRepository repository; - private MockOSSharedPreferences preferences; - private OSTrackerFactory trackerFactory; - private MockSessionManager sessionManager; - private MockOneSignalDBHelper dbHelper; - private MockOSLog logWrapper = new MockOSLog(); - private OSSessionManager.SessionListener sessionListener = new OSSessionManager.SessionListener() { - @Override - public void onSessionEnding(@NonNull List lastInfluences) { - - } - }; - - private OneSignalRemoteParams.InfluenceParams disabledInfluenceParams = new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false); - - private static List outcomeEvents; - - public interface OutcomeEventsHandler { - - void setOutcomes(List outcomes); - } - - private OutcomeEventsHandler handler = new OutcomeEventsHandler() { - @Override - public void setOutcomes(List outcomes) { - outcomeEvents = outcomes; - } - }; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - outcomeEvents = null; - - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - // Mock on a custom HashMap in order to not use custom context - preferences = new MockOSSharedPreferences(); - // Save v2 flag - String v2Name = preferences.getOutcomesV2KeyName(); - preferences.saveBool(preferences.getPreferencesName(), v2Name, true); - - MockOSTimeImpl time = new MockOSTimeImpl(); - trackerFactory = new OSTrackerFactory(preferences, logWrapper, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logWrapper); - service = new MockOneSignalAPIClient(); - OSOutcomeEventsFactory factory = new OSOutcomeEventsFactory(logWrapper, service, dbHelper, preferences); - controller = new MockOutcomeEventsController(sessionManager, factory); - - TestHelpers.beforeTestInitAndCleanup(); - repository = factory.getRepository(); - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - OneSignal.setAppId(APP_ID); - } - - @After - public void tearDown() throws Exception { - StaticResetHelper.restSetStaticFields(); - threadAndTaskWait(); - } - - @Test - public void testDirectNotificationOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"direct\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[]}},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDirectIAMOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - // Set DIRECT iam id influence - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"direct\":{\"notification_ids\":[],\"in_app_message_ids\":[\"iam_id\"]}},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDirectIAMAndNotificationOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - // Set DIRECT iam id influence - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"direct\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[\"iam_id\"]}},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testIndirectNotificationOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - // Restart session by app open should set INDIRECT influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"indirect\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[]}},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testIndirectIAMOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onInAppMessageReceived(IAM_ID); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"indirect\":{\"notification_ids\":[],\"in_app_message_ids\":[\"iam_id\"]}},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testIndirectIAMAndNotificationOutcomeSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - - // Restart session by app open should set INDIRECT influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"indirect\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[\"iam_id\"]}},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testUnattributedOutcomeSuccess() throws Exception { - service.setSuccess(true); - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDisabledOutcomeSuccess() throws Exception { - service.setSuccess(true); - // DISABLED influence - trackerFactory.saveInfluenceParams(disabledInfluenceParams); - // Init session should set UNATTRIBUTED influence but is DISABLED - sessionManager.initSessionFromCache(); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{}", service.getLastJsonObjectSent()); - } - - @Test - public void testUnattributedOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{},\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDisableOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - // DISABLED influence - trackerFactory.saveInfluenceParams(disabledInfluenceParams); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{}", service.getLastJsonObjectSent()); - } - - @Test - public void testDirectOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"direct\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[\"iam_id\"]}},\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testDirectOutcomeSaveIndirectSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.onInAppMessageReceived(IAM_ID); - // Set DIRECT notification id influence - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"direct\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[\"iam_id\"]}},\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - - sessionManager.initSessionFromCache(); - assertEquals(OSInfluenceType.INDIRECT, trackerFactory.getIAMChannelTracker().getInfluenceType()); - assertEquals(1, trackerFactory.getIAMChannelTracker().getIndirectIds().length()); - assertEquals(IAM_ID, trackerFactory.getIAMChannelTracker().getIndirectIds().get(0)); - } - - @Test - public void testIndirectOutcomeWithValueSuccess() throws Exception { - service.setSuccess(true); - sessionManager.initSessionFromCache(); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Restart session by app open should set INDIRECT influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{\"indirect\":{\"notification_ids\":[\"notification_id\"],\"in_app_message_ids\":[\"iam_id\"]}},\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - - @Test - public void testUniqueOutcomeFailSavedOnDBResetSession() throws Exception { - service.setSuccess(false); - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(1, outcomeEvents.size()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - assertEquals("{\"id\":\"testing\",\"sources\":{},\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - - controller.cleanOutcomes(); - - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(2, outcomeEvents.size()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(1).getOutcomeId()); - } - - @Test - public void testUniqueOutcomeFailSavedOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - controller.sendUniqueOutcomeEvent(OUTCOME_NAME); - - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(1, outcomeEvents.size()); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - } - - @Test - public void testOutcomeDirectFailSavedOnDB() throws Exception { - service.setSuccess(false); - sessionManager.initSessionFromCache(); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertTrue(outcomeEvents.size() > 0); - OSOutcomeEventParams params = outcomeEvents.get(0); - assertEquals(OUTCOME_NAME, params.getOutcomeId()); - assertEquals(new Float(0), (Float) params.getWeight()); - assertTrue(params.getTimestamp() > 0); - assertNotNull(params.getOutcomeSource()); - // Direct body - assertEquals(1, params.getOutcomeSource().getDirectBody().getInAppMessagesIds().length()); - assertEquals(IAM_ID, params.getOutcomeSource().getDirectBody().getInAppMessagesIds().get(0)); - assertEquals(1, params.getOutcomeSource().getDirectBody().getNotificationIds().length()); - assertEquals(NOTIFICATION_ID, params.getOutcomeSource().getDirectBody().getNotificationIds().get(0)); - // Indirect body - assertNull(params.getOutcomeSource().getIndirectBody()); - } - - @Test - public void testOutcomeIndirectFailSavedOnDB() throws Exception { - service.setSuccess(false); - sessionManager.initSessionFromCache(); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertTrue(outcomeEvents.size() > 0); - OSOutcomeEventParams params = outcomeEvents.get(0); - assertEquals(OUTCOME_NAME, params.getOutcomeId()); - assertEquals(new Float(0), (Float) params.getWeight()); - assertTrue(params.getTimestamp() > 0); - assertNotNull(params.getOutcomeSource()); - // Indirect body - assertEquals(1, params.getOutcomeSource().getIndirectBody().getInAppMessagesIds().length()); - assertEquals(IAM_ID, params.getOutcomeSource().getIndirectBody().getInAppMessagesIds().get(0)); - assertEquals(1, params.getOutcomeSource().getIndirectBody().getNotificationIds().length()); - assertEquals(NOTIFICATION_ID, params.getOutcomeSource().getIndirectBody().getNotificationIds().get(0)); - // Direct body - assertNull(params.getOutcomeSource().getDirectBody()); - } - - @Test - public void testOutcomeUnattributedFailSavedOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertTrue(outcomeEvents.size() > 0); - assertEquals(OUTCOME_NAME, outcomeEvents.get(0).getOutcomeId()); - } - - @Test - public void testOutcomeMultipleFailsSavedOnDB() throws Exception { - service.setSuccess(false); - - // Init session should set UNATTRIBUTED influence - sessionManager.initSessionFromCache(); - controller.sendOutcomeEvent(OUTCOME_NAME); - // Set last influence ids - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - // Set DIRECT notification id influence and INDIRECT iam id influence because of upgrade - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - controller.sendOutcomeEvent(OUTCOME_NAME + "1"); - - // Restart session by app open should set INDIRECT influence for both channels - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - // Set DIRECT for iam id influence - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - controller.sendOutcomeEvent(OUTCOME_NAME + "2"); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - - assertEquals(3, outcomeEvents.size()); - - // DISABLED influence - trackerFactory.saveInfluenceParams(disabledInfluenceParams); - controller.sendOutcomeEvent(OUTCOME_NAME + "3"); - controller.sendOutcomeEvent(OUTCOME_NAME + "4"); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - // Disables outcomes should not be sent - assertEquals(3, outcomeEvents.size()); - for (OSOutcomeEventParams outcomeEvent : outcomeEvents) { - // UNATTRIBUTED Case - if (outcomeEvent.getOutcomeId().equals(OUTCOME_NAME)) { - assertEquals("OSOutcomeEventParams{outcomeId='testing', outcomeSource=OSOutcomeSource{directBody=null, indirectBody=null}, weight=0.0, timestamp=" + outcomeEvent.getTimestamp() + "}", outcomeEvent.toString()); - } else if (outcomeEvent.getOutcomeId().equals(OUTCOME_NAME + "1")) { // DIRECT By Notification INDIRECT by iam - assertEquals("OSOutcomeEventParams{outcomeId='testing1', outcomeSource=OSOutcomeSource{directBody=OSOutcomeSourceBody{notificationIds=[\"notification_id\"], inAppMessagesIds=[]}, " + - "indirectBody=OSOutcomeSourceBody{notificationIds=[], inAppMessagesIds=[\"iam_id\"]}}, weight=0.0, timestamp=" + outcomeEvent.getTimestamp() + "}", outcomeEvent.toString()); - } else if (outcomeEvent.getOutcomeId().equals(OUTCOME_NAME + "2")) { // INDIRECT By Notification DIRECT by iam - assertEquals("OSOutcomeEventParams{outcomeId='testing2', outcomeSource=OSOutcomeSource{directBody=OSOutcomeSourceBody{notificationIds=[], inAppMessagesIds=[\"iam_id\"]}, " + - "indirectBody=OSOutcomeSourceBody{notificationIds=[\"notification_id\"], inAppMessagesIds=[]}}, weight=0.0, timestamp=" + outcomeEvent.getTimestamp() + "}", outcomeEvent.toString()); - } // DISABLED Case should not be save - } - } - - @Test - public void testSendFailedOutcomesOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - controller.sendOutcomeEvent(OUTCOME_NAME); - controller.sendOutcomeEvent(OUTCOME_NAME + "1"); - controller.sendOutcomeEventWithValue(OUTCOME_NAME + "2", 1); - controller.sendOutcomeEvent(OUTCOME_NAME + "3"); - controller.sendOutcomeEventWithValue(OUTCOME_NAME + "4", 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(5, outcomeEvents.size()); - - service.setSuccess(true); - - controller.sendSavedOutcomes(); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - - assertEquals(0, outcomeEvents.size()); - } - - @Test - public void testSendFailedOutcomeWithValueOnDB() throws Exception { - service.setSuccess(false); - // Restart session by app open should set UNATTRIBUTED influence - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - controller.sendOutcomeEventWithValue(OUTCOME_NAME, 1.1f); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - assertEquals(1, outcomeEvents.size()); - assertEquals(1.1f, outcomeEvents.get(0).getWeight(), 0); - assertEquals("{\"id\":\"testing\",\"sources\":{},\"weight\":1.1,\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - - long timestamp = outcomeEvents.get(0).getTimestamp(); - service.setSuccess(true); - service.resetLastJsonObjectSent(); - controller.sendSavedOutcomes(); - threadAndTaskWait(); - - handler.setOutcomes(repository.getSavedOutcomeEvents()); - - threadAndTaskWait(); - - assertEquals(0, outcomeEvents.size()); - assertEquals("{\"id\":\"testing\",\"sources\":{},\"weight\":1.1,\"timestamp\":" + timestamp + ",\"app_id\":\"" + APP_ID + "\",\"device_type\":1}", service.getLastJsonObjectSent()); - } - -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/PushRegistratorHMSIntegrationTestsRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/PushRegistratorHMSIntegrationTestsRunner.java deleted file mode 100644 index 5c61f843d..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/PushRegistratorHMSIntegrationTestsRunner.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; - -import com.huawei.hms.common.ApiException; -import com.huawei.hms.support.api.client.Status; -import com.onesignal.InAppMessagingHelpers; -import com.onesignal.OneSignal; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowHmsInstanceId; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowPushRegistratorHMS; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.json.JSONException; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import static com.onesignal.OneSignalPackagePrivateHelper.UserState.PUSH_STATUS_HMS_API_EXCEPTION_OTHER; -import static com.onesignal.OneSignalPackagePrivateHelper.UserState.PUSH_STATUS_HMS_TOKEN_TIMEOUT; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.RestClientAsserts.assertHuaweiPlayerCreateAtIndex; -import static com.test.onesignal.RestClientAsserts.assertPlayerCreateNotSubscribedAtIndex; -import static com.test.onesignal.RestClientAsserts.assertPlayerCreateSubscribedAtIndex; -import static com.test.onesignal.RestClientAsserts.assertPlayerCreateWithNotificationTypesAtIndex; -import static com.test.onesignal.RestClientAsserts.assertRestCalls; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; - -@Config( - packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class, - ShadowOneSignalRestClient.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowHmsInstanceId.class, - ShadowPushRegistratorHMS.class - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class PushRegistratorHMSIntegrationTestsRunner { - - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - - ShadowOSUtils.supportsHMS(true); - - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - } - - private static void assertHuaweiSubscribe() throws JSONException { - assertHuaweiPlayerCreateAtIndex(1); - assertPlayerCreateSubscribedAtIndex(1); - assertRestCalls(2); - } - - private static void assertHuaweiUnsubscribeWithError(int notification_types) throws JSONException { - assertHuaweiPlayerCreateAtIndex(1); - assertPlayerCreateNotSubscribedAtIndex(1); - assertPlayerCreateWithNotificationTypesAtIndex(notification_types, 1); - assertRestCalls(2); - } - - private void OneSignalInit() throws Exception { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - OneSignal.setAppId(InAppMessagingHelpers.ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity.getApplicationContext()); - blankActivityController.resume(); - threadAndTaskWait(); - } - - @Test - public void successfulHMS_shouldRegisterSubscribed() throws Exception { - OneSignalInit(); - assertHuaweiSubscribe(); - } - - @Test - public void HMSTimeout_shouldRegisterUnsubscribed() throws Exception { - ShadowHmsInstanceId.token = null; - OneSignalInit(); - - assertHuaweiUnsubscribeWithError(PUSH_STATUS_HMS_TOKEN_TIMEOUT); - } - - @Test - public void HMSUnknownException_shouldRegisterUnsubscribed() throws Exception { - ShadowHmsInstanceId.throwException = new ApiException(new Status(0)); - OneSignalInit(); - - assertHuaweiUnsubscribeWithError(PUSH_STATUS_HMS_API_EXCEPTION_OTHER); - } - - @Test - public void EMUIPre10Device_shouldRegister() throws Exception { - // Direct calls to HmsInstanceId.getToken always return null on EMUI9 and older - ShadowHmsInstanceId.token = null; - // However HmsMessageServiceOneSignal.onNewToken should fire in the background giving us the token - ShadowPushRegistratorHMS.backgroundSuccessful = true; - - OneSignalInit(); - - assertHuaweiSubscribe(); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/PushRegistratorRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/PushRegistratorRunner.java deleted file mode 100644 index 6002c4281..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/PushRegistratorRunner.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2018 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import android.app.Activity; - -import androidx.annotation.NonNull; - -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper.PushRegistratorFCM; -import com.onesignal.PushRegistrator; -import com.onesignal.ShadowFirebaseApp; -import com.onesignal.ShadowGooglePlayServicesUtil; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import static com.test.onesignal.TestHelpers.threadAndTaskWait; - -import static junit.framework.Assert.assertTrue; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowGooglePlayServicesUtil.class, - ShadowOSUtils.class, - ShadowOneSignalRestClient.class, - ShadowFirebaseApp.class, - }, - sdk = 28 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class PushRegistratorRunner { - - private Activity blankActivity; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - blankActivity = Robolectric.buildActivity(BlankActivity.class).create().get(); - } - - @After - public void afterEachTest() throws Exception { - TestHelpers.afterTestCleanup(); - } - - static private class RegisteredHandler implements PushRegistrator.RegisteredHandler { - private final Thread testThread; - public boolean callbackFired; - - RegisteredHandler(@NonNull Thread testThread) { - this.testThread = testThread; - } - - @Override - public void complete(String id, int status) { - callbackFired = true; - testThread.interrupt(); - } - } - - private void initOneSignalAndWait() throws Exception { - OneSignal.initWithContext(blankActivity); - OneSignal.setAppId("11111111-2222-3333-4444-555555555555"); - threadAndTaskWait(); - } - - private boolean performRegisterForPush() throws Exception { - initOneSignalAndWait(); - - RegisteredHandler registeredHandler = new RegisteredHandler(Thread.currentThread()); - - PushRegistratorFCM pushReg = new PushRegistratorFCM(blankActivity, null); - pushReg.registerForPush(blankActivity, "123456789", registeredHandler); - try {Thread.sleep(5000);} catch (Throwable t) {} - - return registeredHandler.callbackFired; - } - - @Test - public void testGooglePlayServicesAPKMissingOnDevice() throws Exception { - ShadowOSUtils.isGMSInstalledAndEnabled = false; - boolean callbackFired = performRegisterForPush(); - assertTrue(callbackFired); - } - - @Test - public void testFCMPartOfGooglePlayServicesMissing() throws Exception { - ShadowOSUtils.isGMSInstalledAndEnabled = true; - boolean callbackFired = performRegisterForPush(); - assertTrue(callbackFired); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RESTClientRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RESTClientRunner.java deleted file mode 100644 index cdbf4f248..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RESTClientRunner.java +++ /dev/null @@ -1,276 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2019 OneSignal - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockHttpURLConnection; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper.OneSignalRestClient; -import com.onesignal.ShadowOneSignalRestClientWithMockConnection; -import com.onesignal.StaticResetHelper; - -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_savePrivacyConsentRequired; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClientWithMockConnection.class - }, - sdk = 26 -) -@RunWith(RobolectricTestRunner.class) -public class RESTClientRunner { - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - firstResponse = secondResponse = null; - TestHelpers.beforeTestInitAndCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - StaticResetHelper.restSetStaticFields(); - } - - @Test - public void testRESTClientFallbackTimeout() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - mockThreadHang = true; - }}; - - OneSignalRestClient.get("URL", null, ""); - threadAndTaskWait(); - - assertTrue(ShadowOneSignalRestClientWithMockConnection.lastConnection.getDidInterruptMockHang()); - } - - private static final String SDK_VERSION_HTTP_HEADER = "onesignal/android/" + OneSignal.getSdkVersionRaw(); - - @Test - public void SDKHeaderIsIncludedInGetCalls() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - OneSignalRestClient.get("URL", null, null); - threadAndTaskWait(); - - assertEquals(SDK_VERSION_HTTP_HEADER, getLastHTTPHeaderProp("SDK-Version")); - } - - @Test - public void SDKHeaderIsIncludedInPostCalls() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - OneSignal_savePrivacyConsentRequired(false); - - OneSignalRestClient.post("URL", null, null); - threadAndTaskWait(); - - assertEquals(SDK_VERSION_HTTP_HEADER, getLastHTTPHeaderProp("SDK-Version")); - } - - @Test - public void SDKHeaderIsIncludedInPutCalls() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - OneSignal_savePrivacyConsentRequired(false); - - OneSignalRestClient.put("URL", null, null); - threadAndTaskWait(); - - assertEquals(SDK_VERSION_HTTP_HEADER, getLastHTTPHeaderProp("SDK-Version")); - } - - private final static String MOCK_CACHE_KEY = "MOCK_CACHE_KEY"; - private final static String MOCK_ETAG_VALUE = "MOCK_ETAG_VALUE"; - - private String firstResponse, secondResponse; - - // Note Thread.sleep in the following two tests are used since we can't wait on threads - // created from callResponseHandlerOnSuccess due deadlock limitations with Scheduler - // in the Robolectric unit test library. - // https://github.com/robolectric/robolectric/issues/3819 - @Test - public void testReusesCache() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - // 1. Do first request to save response - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - status = 200; - responseBody = "{\"key1\": \"value1\"}"; - mockProps.put("etag", MOCK_ETAG_VALUE); - }}; - OneSignalRestClient.get("URL", new OneSignalRestClient.ResponseHandler() { - @Override - public void onSuccess(String response) { - firstResponse = response; - } - }, MOCK_CACHE_KEY); - threadAndTaskWait(); - Thread.sleep(200); - - // 2. Make 2nd request and make sure we send the ETag and use the cached response - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - status = 304; - }}; - - OneSignalRestClient.get("URL", new OneSignalRestClient.ResponseHandler() { - @Override - public void onSuccess(String response) { - secondResponse = response; - } - }, MOCK_CACHE_KEY); - threadAndTaskWait(); - Thread.sleep(200); - - assertNotNull(firstResponse); - assertEquals(firstResponse, secondResponse); - assertEquals(MOCK_ETAG_VALUE, getLastHTTPHeaderProp("if-none-match")); - } - - @Test - public void testReplacesCacheOn200() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - testReusesCache(); - firstResponse = secondResponse = null; - final String newMockResponse = "{\"key2\": \"value2\"}"; - - // 3. Make 3rd request and make sure we send the ETag and use the cached response - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - status = 200; - responseBody = newMockResponse; - mockProps.put("etag", "MOCK_ETAG_VALUE2"); - }}; - OneSignalRestClient.get("URL", null, MOCK_CACHE_KEY); - threadAndTaskWait(); - Thread.sleep(200); - - // 4. Make 4th request and make sure we get the new cached value - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - status = 304; - }}; - OneSignalRestClient.get("URL", new OneSignalRestClient.ResponseHandler() { - @Override - public void onSuccess(String response) { - secondResponse = response.replace("\u0000", ""); - } - }, MOCK_CACHE_KEY); - threadAndTaskWait(); - Thread.sleep(200); - - assertEquals(newMockResponse, secondResponse); - } - - @Test - public void testApiCall400Response() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - OneSignal_savePrivacyConsentRequired(false); - - final String newMockResponse = "{\"errors\":[\"test response\"]}"; - final int statusCode = 400; - - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - status = statusCode; - errorResponseBody = newMockResponse; - }}; - - final String[] failResponse = {null}; - final int[] statusCodeResponse = {0}; - OneSignalRestClient.post("URL", null, new OneSignalRestClient.ResponseHandler() { - @Override - public void onSuccess(String response) { - super.onSuccess(response); - } - - @Override - public void onFailure(int statusCode, String response, Throwable throwable) { - super.onFailure(statusCode, response, throwable); - failResponse[0] = response; - statusCodeResponse[0] = statusCode; - } - }); - - threadAndTaskWait(); - assertEquals(newMockResponse, failResponse[0]); - assertEquals(statusCode, statusCodeResponse[0]); - } - - @Test - public void testApiCall400EmptyResponse() throws Exception { - OneSignal.initWithContext(ApplicationProvider.getApplicationContext()); - OneSignal_savePrivacyConsentRequired(false); - - final String newMockResponse = ""; - final int statusCode = 400; - - ShadowOneSignalRestClientWithMockConnection.mockResponse = new MockHttpURLConnection.MockResponse() {{ - status = statusCode; - responseBody = newMockResponse; - }}; - - final String[] failResponse = {null}; - final int[] statusCodeResponse = {0}; - OneSignalRestClient.post("URL", null, new OneSignalRestClient.ResponseHandler() { - @Override - public void onSuccess(String response) { - super.onSuccess(response); - } - - @Override - public void onFailure(int statusCode, String response, Throwable throwable) { - super.onFailure(statusCode, response, throwable); - failResponse[0] = response; - statusCodeResponse[0] = statusCode; - } - }); - - threadAndTaskWait(); - assertEquals(newMockResponse, failResponse[0]); - assertEquals(statusCode, statusCodeResponse[0]); - } - - private static String getLastHTTPHeaderProp(String prop) { - return ShadowOneSignalRestClientWithMockConnection.lastConnection.getRequestProperty(prop); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RemoteParamsTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RemoteParamsTests.java deleted file mode 100644 index 303399708..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RemoteParamsTests.java +++ /dev/null @@ -1,391 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import android.app.Activity; - -import com.onesignal.OneSignal; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; - -import org.json.JSONObject; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; - -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_areNotificationsEnabledForSubscribedState; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getDisableGMSMissingPrompt; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_locationShared; -import static com.test.onesignal.TestHelpers.afterTestCleanup; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowOSUtils.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - }, - sdk = 21 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class RemoteParamsTests { - - private static final String ONESIGNAL_APP_ID = "b2f7f966-d8cc-11e4-bed1-df8f05be55ba"; - private static ActivityController blankActivityController; - private static Activity blankActivity; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - TestHelpers.beforeTestSuite(); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - - TestHelpers.beforeTestInitAndCleanup(); - } - - @After - public void afterEachTest() throws Exception { - afterTestCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - TestHelpers.beforeTestInitAndCleanup(); - } - - @Test - public void testUserPrivacyConsentRequired_ByUser() throws Exception { - ShadowOneSignalRestClient.setAndRemoveKeyFromRemoteParams("requires_user_privacy_consent"); - OneSignal.setRequiresUserPrivacyConsent(true); - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentNotRequired_ByUser() throws Exception { - ShadowOneSignalRestClient.setAndRemoveKeyFromRemoteParams("requires_user_privacy_consent"); - OneSignal.setRequiresUserPrivacyConsent(false); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentRequired_ByRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentNotRequired_ByRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentRequired_UserConfigurationOverrideByRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - - OneSignal.setRequiresUserPrivacyConsent(false); - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentNotRequired_UserConfigurationOverrideByRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(false); - - OneSignal.setRequiresUserPrivacyConsent(true); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentRequired_UserConfigurationNotOverrideRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal.requiresUserPrivacyConsent()); - - OneSignal.setRequiresUserPrivacyConsent(false); - assertTrue(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testUserPrivacyConsentNotRequired_UserConfigurationNotOverrideRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(false); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal.requiresUserPrivacyConsent()); - - OneSignal.setRequiresUserPrivacyConsent(true); - assertFalse(OneSignal.requiresUserPrivacyConsent()); - } - - @Test - public void testLocationSharedEnable_ByUser() throws Exception { - OneSignal.setLocationShared(true); - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedDisable_ByUser() throws Exception { - ShadowOneSignalRestClient.setAndRemoveKeyFromRemoteParams("location_shared"); - OneSignal.setLocationShared(false); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedEnable_ByRemoteParams() throws Exception { - ShadowOneSignalRestClient.setAndRemoveKeyFromRemoteParams("location_shared"); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedDisable_ByRemoteParams() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("location_shared", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedEnable_UserConfigurationOverrideByRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignal.setLocationShared(false); - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedDisable_UserConfigurationOverrideByRemoteParams() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("location_shared", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignal.setLocationShared(true); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedEnable_UserConfigurationNotOverrideRemoteParams() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_locationShared()); - - OneSignal.setLocationShared(false); - assertTrue(OneSignal_locationShared()); - } - - @Test - public void testLocationSharedDisable_UserConfigurationNotOverrideRemoteParams() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("location_shared", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_locationShared()); - - OneSignal.setLocationShared(true); - assertFalse(OneSignal_locationShared()); - } - - @Test - @Config(shadows = {ShadowNotificationManagerCompat.class}) - public void testUnsubscribeOnNotificationsDisable_EnableByUser() throws Exception { - ShadowNotificationManagerCompat.enabled = false; - OneSignal.unsubscribeWhenNotificationsAreDisabled(true); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - @Config(shadows = {ShadowNotificationManagerCompat.class}) - public void testUnsubscribeOnNotificationsDisable_DisableByUser() throws Exception { - ShadowNotificationManagerCompat.enabled = false; - ShadowOneSignalRestClient.setAndRemoveKeyFromRemoteParams("unsubscribe_on_notifications_disabled"); - OneSignal.unsubscribeWhenNotificationsAreDisabled(false); - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - @Config(shadows = {ShadowNotificationManagerCompat.class}) - public void testUnsubscribeOnNotificationsDisable_EnableByRemoteParams() throws Exception { - ShadowNotificationManagerCompat.enabled = false; - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - public void testUnsubscribeOnNotificationsDisable_DisableByRemoteParams() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("unsubscribe_on_notifications_disabled", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - @Config(shadows = {ShadowNotificationManagerCompat.class}) - public void testUnsubscribeOnNotificationsDisable_Enable_UserConfigurationOverrideByRemoteParams() throws Exception { - ShadowNotificationManagerCompat.enabled = false; - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignal.unsubscribeWhenNotificationsAreDisabled(false); - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - public void testUnsubscribeOnNotificationsDisable_Disable_UserConfigurationOverrideByRemoteParams() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("unsubscribe_on_notifications_disabled", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignal.unsubscribeWhenNotificationsAreDisabled(true); - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - @Config(shadows = {ShadowNotificationManagerCompat.class}) - public void testUnsubscribeOnNotificationsDisable_Enable_UserConfigurationNotOverrideRemoteParams() throws Exception { - ShadowNotificationManagerCompat.enabled = false; - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_areNotificationsEnabledForSubscribedState()); - - OneSignal.unsubscribeWhenNotificationsAreDisabled(false); - assertFalse(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - public void testUnsubscribeOnNotificationsDisable_Disable_UserConfigurationNotOverrideRemoteParams() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("unsubscribe_on_notifications_disabled", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_areNotificationsEnabledForSubscribedState()); - - OneSignal.unsubscribeWhenNotificationsAreDisabled(true); - assertTrue(OneSignal_areNotificationsEnabledForSubscribedState()); - } - - @Test - public void testGMSMissingPromptDisable() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(); - - OneSignalInit(); - threadAndTaskWait(); - assertTrue(OneSignal_getDisableGMSMissingPrompt()); - } - - @Test - public void testGMSMissingPromptEnabled() throws Exception { - JSONObject remoteParams = new JSONObject(); - remoteParams.put("disable_gms_missing_prompt", false); - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams); - - OneSignalInit(); - threadAndTaskWait(); - assertFalse(OneSignal_getDisableGMSMissingPrompt()); - } - - private void OneSignalInit() { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.DEBUG, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - blankActivityController.resume(); - } -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java deleted file mode 100644 index 9df09ddd2..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java +++ /dev/null @@ -1,354 +0,0 @@ -package com.test.onesignal; - -import androidx.annotation.NonNull; - -import com.onesignal.OneSignalPackagePrivateHelper.UserState; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowOneSignalRestClient.REST_METHOD; -import com.onesignal.ShadowOneSignalRestClient.Request; - -import org.hamcrest.core.AnyOf; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.List; - -import static com.onesignal.OneSignalPackagePrivateHelper.UserState.PUSH_STATUS_SUBSCRIBED; -import static com.test.onesignal.RestClientValidator.GET_REMOTE_PARAMS_ENDPOINT; -import static com.test.onesignal.TypeAsserts.assertIsUUID; -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -class RestClientAsserts { - - private static final AnyOf ANY_OF_VALID_DEVICE_TYPES = anyOf( - is(UserState.DEVICE_TYPE_ANDROID), - is(UserState.DEVICE_TYPE_FIREOS), - is(UserState.DEVICE_TYPE_EMAIL), - is(UserState.DEVICE_TYPE_HUAWEI), - is(UserState.DEVICE_TYPE_SMS) - ); - - private static final AnyOf ANY_OF_PUSH_DEVICE_TYPES = anyOf( - is(UserState.DEVICE_TYPE_ANDROID), - is(UserState.DEVICE_TYPE_FIREOS), - is(UserState.DEVICE_TYPE_HUAWEI) - ); - - static void assertPlayerCreateAnyAtIndex(int index) throws JSONException { - assertPlayerCreateAny(ShadowOneSignalRestClient.requests.get(index)); - } - - static void assertPlayerCreateAny(Request request) throws JSONException { - assertPlayerCreateMethodAndUrl(request); - assertValidDeviceType(request.payload); - } - - static void assertPlayerCreatePush(Request request) throws JSONException { - assertPlayerCreateMethodAndUrl(request); - assertDeviceTypeIsPush(request.payload); - } - - static void assertPlayerCreatePushAtIndex(int index) throws JSONException { - assertPlayerCreatePush(ShadowOneSignalRestClient.requests.get(index)); - } - - static void assertAndroidPlayerCreateAtIndex(int index) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertPlayerCreateMethodAndUrl(request); - assertDeviceTypeIsAndroid(request.payload); - } - - static void assertAmazonPlayerCreateAtIndex(int index) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertPlayerCreateMethodAndUrl(request); - assertDeviceTypeIsAmazon(request.payload); - } - - static void assertHuaweiPlayerCreateAtIndex(int index) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertPlayerCreateMethodAndUrl(request); - assertDeviceTypeIsHuawei(request.payload); - } - - static void assertPlayerCreateSubscribedAtIndex(int index) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertPlayerCreateMethodAndUrl(request); - - boolean subscribed = !request.payload.has("notification_types"); - assertTrue(subscribed); - assertNotNull(request.payload.optString("identifier", null)); - } - - static void assertPlayerCreateNotSubscribedAtIndex(int index) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertPlayerCreateMethodAndUrl(request); - - boolean unsubscribed = request.payload.getInt("notification_types") < PUSH_STATUS_SUBSCRIBED; - assertTrue(unsubscribed); - assertNull(request.payload.optString("identifier", null)); - } - - static void assertPlayerCreateWithNotificationTypesAtIndex(int notification_types, int index) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - assertPlayerCreateMethodAndUrl(request); - assertEquals(notification_types, request.payload.getInt("notification_types")); - } - - static void assertOnSessionAtIndex(int index) { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertOnSessionUrl(request.url); - } - - static void assertNumberOfOnSessions(int number) { - int successfulAsserts = 0; - for (Request request : ShadowOneSignalRestClient.requests) { - try { - assertOnSessionUrl(request.url); - successfulAsserts++; - } catch (AssertionError ignored) { } - } - - assertEquals(number, successfulAsserts); - } - - static void assertOnFocusAtIndex(int index, int focusTimeSec) throws JSONException { - assertOnFocusAtIndex(index, new JSONObject().put("active_time", focusTimeSec)); - } - - static void assertOnFocusAtIndex(int index, @NonNull JSONObject containsPayload) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertEquals(REST_METHOD.POST, request.method); - assertOnFocusUrl(request.url); - JsonAsserts.containsSubset(request.payload, containsPayload); - } - - static void assertOnFocusAtIndexForPlayerId(int index, @NonNull String id) { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertEquals(REST_METHOD.POST, request.method); - assertOnFocusUrlWithPlayerId(request.url, id); - } - - static void assertOnFocusAtIndexDoesNotHaveKeys(int index, @NonNull List omitKeys) { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertEquals(REST_METHOD.POST, request.method); - assertOnFocusUrl(request.url); - JsonAsserts.doesNotContainKeys(request.payload, omitKeys); - } - - private static void assertPlayerCreateMethodAndUrl(@NonNull Request request) { - assertEquals(REST_METHOD.POST, request.method); - assertEquals(request.url, "players"); - } - - private static void assertDeviceTypeIsPush(@NonNull JSONObject payload) throws JSONException { - assertThat(payload.getInt("device_type"), ANY_OF_PUSH_DEVICE_TYPES); - } - - private static void assertValidDeviceType(@NonNull JSONObject payload) throws JSONException { - assertThat(payload.getInt("device_type"), ANY_OF_VALID_DEVICE_TYPES); - } - - private static void assertDeviceTypeIsAndroid(@NonNull JSONObject payload) throws JSONException { - assertEquals(UserState.DEVICE_TYPE_ANDROID, payload.getInt("device_type")); - } - - private static void assertDeviceTypeIsAmazon(@NonNull JSONObject payload) throws JSONException { - assertEquals(UserState.DEVICE_TYPE_FIREOS, payload.getInt("device_type")); - } - - private static void assertDeviceTypeIsHuawei(@NonNull JSONObject payload) throws JSONException { - assertEquals(UserState.DEVICE_TYPE_HUAWEI, payload.getInt("device_type")); - } - - static void assertReportReceivedAtIndex(int index, @NonNull String notificationId, @NonNull JSONObject payload) { - Request request = ShadowOneSignalRestClient.requests.get(index); - assertEquals(REST_METHOD.PUT, request.method); - assertRemoteParamsUrlReportReceived(request.url, notificationId); - assertEquals(payload.toString(), request.payload.toString()); - } - - static void assertRemoteParamsUrlReportReceived(@NonNull String url, @NonNull String notificationId) { - String[] parts = url.split("/"); - assertEquals("notifications", parts[0]); - assertEquals(notificationId, parts[1]); - assertEquals("report_received", parts[2]); - } - - static void assertRemoteParamsAtIndex(int index) { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertEquals(REST_METHOD.GET, request.method); - assertRemoteParamsUrl(request.url); - } - - static void assertMeasureAtIndex(int index, @NonNull String outcomeName) throws JSONException { - assertMeasureAtIndex("measure", index, new JSONObject() - .put("id", outcomeName) - ); - } - - static void assertMeasureAtIndex(int index, @NonNull boolean isDirect, @NonNull String outcomeName, @NonNull JSONArray notificationIds) throws JSONException { - assertMeasureAtIndex("measure", index, new JSONObject() - .put("direct", isDirect) - .put("id", outcomeName) - .put("notification_ids", notificationIds) - ); - } - - static void assertMeasureOnV2AtIndex(int index, @NonNull String outcomeName, - JSONArray directIAMs, JSONArray directNotifications, - JSONArray indirectIAMs, JSONArray indirectNotifications) throws JSONException { - JSONObject sources = new JSONObject(); - boolean direct = false; - boolean indirect = false; - if (directIAMs != null || directNotifications != null) { - direct = true; - JSONObject directBody = new JSONObject(); - if (directNotifications != null) - directBody.put("notification_ids", directNotifications); - if (directIAMs != null) - directBody.put("in_app_message_ids", directIAMs); - sources.put("direct", directBody); - } - - if (indirectIAMs != null || indirectNotifications != null) { - indirect = true; - JSONObject indirectBody = new JSONObject(); - if (indirectNotifications != null) - indirectBody.put("notification_ids", indirectNotifications); - if (indirectIAMs != null) - indirectBody.put("in_app_message_ids", indirectIAMs); - sources.put("indirect", indirectBody); - } - - assertMeasureAtIndex("measure_sources", index, new JSONObject() - .put("id", outcomeName) - .put("sources", sources) - ); - - Request request = ShadowOneSignalRestClient.requests.get(index); - if (!direct) - assertFalse(request.payload.getJSONObject("sources").has("direct")); - if (!indirect) - assertFalse(request.payload.getJSONObject("sources").has("indirect")); - - assertFalse(request.payload.has("weight")); - } - - private static void assertMeasureAtIndex(String measureKey, int index, JSONObject containsPayload) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertEquals(REST_METHOD.POST, request.method); - assertMeasureUrl(measureKey, request.url); - JsonAsserts.containsSubset(request.payload, containsPayload); - } - - static void assertOnFocusUrlWithPlayerId(@NonNull String url, @NonNull String id) { - assertOnFocusUrl(url); - assertEquals(id, url.split("/")[1]); - } - - static void assertOnSessionUrl(String url) { - String[] parts = url.split("/"); - assertEquals("players", parts[0]); - if (parts.length == 1) - fail("Not an on_session as player_id and on_session is missing from the URL"); - assertIsUUID(parts[1]); - assertEquals("on_session", parts[2]); - } - - static void assertOnFocusUrl(@NonNull String url) { - String[] parts = url.split("/"); - assertEquals("players", parts[0]); - assertIsUUID(parts[1]); - assertEquals("on_focus", parts[2]); - } - - // Assert that URL matches the format apps/{UUID}/android_params.js - static void assertRemoteParamsUrl(@NonNull String url) { - String[] parts = url.split("/"); - - assertEquals("apps", parts[0]); - assertIsUUID(parts[1]); - - String[] playerIdParts = parts[2].split("\\?player_id="); - assertEquals(GET_REMOTE_PARAMS_ENDPOINT, playerIdParts[0]); - if (playerIdParts.length == 2) - assertIsUUID( playerIdParts[1]); - else if (playerIdParts.length > 2) - fail("Invalid format"); - - assertEquals(3, parts.length); - } - - private static void assertMeasureUrl(String measureKey, String url) { - String[] parts = url.split("/"); - assertEquals("outcomes", parts[0]); - assertEquals(measureKey, parts[1]); - } - - static void assertRestCalls(int expected) { - assertEquals(expected, ShadowOneSignalRestClient.networkCallCount); - } - - static void assertHasAppId(@NonNull Request request) { - if (request.method == REST_METHOD.GET) { - assertAppIdInUrl(request.url); - return; - } - - assertIsUUID(request.payload.optString("app_id")); - } - - public static void assertNotificationOpenAtIndex(int index, int deviceType) throws JSONException { - Request request = ShadowOneSignalRestClient.requests.get(index); - - assertEquals(REST_METHOD.PUT, request.method); - - String[] parts = request.url.split("/"); - assertEquals("notifications", parts[0]); - assertIsUUID(parts[1]); - - assertHasAppId(request); - - assertEquals(deviceType, request.payload.getInt("device_type")); - } - - private static void assertAppIdInUrl(@NonNull String url) { - String[] appsPath = url.split("apps/"); - if (appsPath.length == 2) { - String[] appIdPart = appsPath[1].split("/"); - assertIsUUID(appIdPart[0]); - } - else if (appsPath.length == 1) { - // Check for "?app_id=" or "&app_id=" - String[] appsQueryParam = url.split("\\?app_id=|&app_id="); - assertIsUUID(appsQueryParam[1]); - } - else - fail("Invalid format"); - } - - public static void assertRemoteParamsWasTheOnlyNetworkCall() { - assertRemoteParamsAtIndex(0); - assertRestCalls(1); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientValidator.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientValidator.java deleted file mode 100644 index 10f24badb..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientValidator.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.test.onesignal; - -import androidx.annotation.NonNull; - -import com.onesignal.ShadowOneSignalRestClient.Request; - -import org.json.JSONException; - -import static com.test.onesignal.RestClientAsserts.assertHasAppId; -import static com.test.onesignal.RestClientAsserts.assertPlayerCreateAny; -import static com.test.onesignal.RestClientAsserts.assertRemoteParamsUrl; - -// Validator runs on each mock REST API call on All tests to ensure the correct fields are sent -public class RestClientValidator { - - static final String GET_REMOTE_PARAMS_ENDPOINT = "android_params.js"; - - public static void validateRequest(@NonNull Request request) throws JSONException { - switch (request.method) { - case GET: - if (request.url.contains(GET_REMOTE_PARAMS_ENDPOINT)) - assertRemoteParamsUrl(request.url); - break; - case POST: - if (request.url.endsWith("players")) - assertPlayerCreateAny(request); - } - - assertHasAppId(request); - - // TODO: Add rest of the REST API calls here - } - -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SessionManagerUnitTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SessionManagerUnitTests.java deleted file mode 100644 index 63545ca29..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SessionManagerUnitTests.java +++ /dev/null @@ -1,725 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import androidx.annotation.NonNull; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockSessionManager; -import com.onesignal.OSSessionManager; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.ShadowOSUtils; -import com.onesignal.StaticResetHelper; -import com.onesignal.influence.data.OSChannelTracker; -import com.onesignal.influence.data.OSTrackerFactory; -import com.onesignal.influence.domain.OSInfluence; -import com.onesignal.influence.domain.OSInfluenceChannel; -import com.onesignal.influence.domain.OSInfluenceType; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.util.List; - -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOSUtils.class, - }, - sdk = 21) -@RunWith(RobolectricTestRunner.class) -public class SessionManagerUnitTests { - - private static final String GENERIC_ID = "generic_id"; - private static final String NOTIFICATION_ID = "notification_id"; - private static final String IAM_ID = "iam_id"; - private static final int INFLUENCE_ID_LIMIT = 10; - - private MockSessionManager sessionManager; - private OSTrackerFactory trackerFactory; - private MockOSSharedPreferences preferences; - private List lastInfluencesBySessionEnding; - - private OSSessionManager.SessionListener sessionListener = new OSSessionManager.SessionListener() { - @Override - public void onSessionEnding(@NonNull List lastInfluences) { - lastInfluencesBySessionEnding = lastInfluences; - } - }; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - MockOSLog logger = new MockOSLog(); - MockOSTimeImpl time = new MockOSTimeImpl(); - preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - sessionManager = new MockSessionManager(sessionListener, trackerFactory, logger); - TestHelpers.beforeTestInitAndCleanup(); - } - - @After - public void tearDown() throws Exception { - lastInfluencesBySessionEnding = null; - - StaticResetHelper.restSetStaticFields(); - threadAndTaskWait(); - } - - @Test - public void testUnattributedInitInfluence() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - List influences = sessionManager.getInfluences(); - for (OSInfluence influence : influences) { - assertTrue(influence.getInfluenceType().isUnattributed()); - assertNull(influence.getIds()); - } - } - - @Test - public void testIndirectInfluence() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - sessionManager.onInAppMessageReceived(GENERIC_ID); - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - for (OSInfluence influence : sessionManager.getInfluences()) { - assertTrue(influence.getInfluenceType().isIndirect()); - assertEquals(1, influence.getIds().length()); - assertEquals(GENERIC_ID, influence.getIds().get(0)); - } - } - - @Test - public void testIndirectNotificationInitInfluence() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - OSChannelTracker notificationTracker = trackerFactory.getNotificationChannelTracker(); - assertEquals(0, notificationTracker.getLastReceivedIds().length()); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.APP_OPEN); - - notificationTracker = trackerFactory.getNotificationChannelTracker(); - OSInfluence influence = notificationTracker.getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, notificationTracker.getInfluenceType()); - assertEquals(NOTIFICATION_ID, notificationTracker.getLastReceivedIds().get(0)); - assertEquals(OSInfluenceChannel.NOTIFICATION, influence.getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - assertEquals(NOTIFICATION_ID, influence.getIds().get(0)); - } - - @Test - public void testDirectNotificationInitInfluence() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - OSChannelTracker notificationTracker = trackerFactory.getNotificationChannelTracker(); - assertEquals(0, notificationTracker.getLastReceivedIds().length()); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - - notificationTracker = trackerFactory.getNotificationChannelTracker(); - OSInfluence influence = notificationTracker.getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, notificationTracker.getInfluenceType()); - assertEquals(NOTIFICATION_ID, notificationTracker.getLastReceivedIds().get(0)); - assertEquals(OSInfluenceChannel.NOTIFICATION, influence.getInfluenceChannel()); - assertEquals(OSInfluenceType.DIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - assertEquals(NOTIFICATION_ID, influence.getIds().get(0)); - } - - @Test - public void testIndirectIAMInitInfluence() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - OSChannelTracker iamTracker = trackerFactory.getIAMChannelTracker(); - assertEquals(0, iamTracker.getLastReceivedIds().length()); - - sessionManager.onInAppMessageReceived(IAM_ID); - - iamTracker = trackerFactory.getIAMChannelTracker(); - OSInfluence influence = iamTracker.getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamTracker.getInfluenceType()); - assertEquals(IAM_ID, iamTracker.getLastReceivedIds().get(0)); - assertEquals(OSInfluenceChannel.IAM, influence.getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - assertEquals(IAM_ID, influence.getIds().get(0)); - } - - @Test - public void testDirectIAMInitInfluence() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - OSChannelTracker iamTracker = trackerFactory.getIAMChannelTracker(); - assertEquals(0, iamTracker.getLastReceivedIds().length()); - - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - iamTracker = trackerFactory.getIAMChannelTracker(); - OSInfluence influence = iamTracker.getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, iamTracker.getInfluenceType()); - assertEquals(IAM_ID, iamTracker.getLastReceivedIds().get(0)); - assertEquals(OSInfluenceChannel.IAM, influence.getInfluenceChannel()); - assertEquals(OSInfluenceType.DIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - assertEquals(IAM_ID, influence.getIds().get(0)); - } - - @Test - public void testDirectIAMResetInfluence() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - OSChannelTracker iamTracker = trackerFactory.getIAMChannelTracker(); - assertEquals(0, iamTracker.getLastReceivedIds().length()); - - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - sessionManager.onDirectInfluenceFromIAMClickFinished(); - - iamTracker = trackerFactory.getIAMChannelTracker(); - OSInfluence influence = iamTracker.getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamTracker.getInfluenceType()); - assertEquals(IAM_ID, iamTracker.getLastReceivedIds().get(0)); - assertEquals(OSInfluenceChannel.IAM, influence.getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - assertEquals(IAM_ID, influence.getIds().get(0)); - } - - @Test - public void testUnattributedAddSessionData() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - JSONObject object = new JSONObject(); - sessionManager.addSessionIds(object, sessionManager.getInfluences()); - - assertEquals(0, object.length()); - } - - @Test - public void testIndirectAddSessionData() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.APP_OPEN); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.APP_OPEN); - - JSONObject object = new JSONObject(); - sessionManager.addSessionIds(object, sessionManager.getInfluences()); - - // Only Notification data should be added - // IAM data is not added on on_focus call - assertEquals(2, object.length()); - assertEquals(false, object.get("direct")); - assertEquals(new JSONArray("[\"notification_id\"]"), object.get("notification_ids")); - } - - @Test - public void testDirectAddSessionData() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - - JSONObject object = new JSONObject(); - sessionManager.addSessionIds(object, sessionManager.getInfluences()); - - // Only Notification data should be added - // IAM data is not added on on_focus call - assertEquals(2, object.length()); - assertEquals(true, object.get("direct")); - assertEquals(new JSONArray("[\"notification_id\"]"), object.get("notification_ids")); - } - - @Test - public void testDisabledAddSessionData() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false)); - sessionManager.initSessionFromCache(); - - JSONObject object = new JSONObject(); - sessionManager.addSessionIds(object, sessionManager.getInfluences()); - - assertEquals(0, object.length()); - } - - @Test - public void testDirectWithNullNotification() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - sessionManager.onNotificationReceived(null); - sessionManager.onDirectInfluenceFromNotificationOpen(null); - - OSInfluence influence = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - } - - @Test - public void testDirectWithEmptyNotification() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - sessionManager.onNotificationReceived(""); - sessionManager.onDirectInfluenceFromNotificationOpen(""); - - OSInfluence influence = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - } - - @Test - public void testSessionUpgradeFromAppClosed() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - List influences = sessionManager.getInfluences(); - - for (OSInfluence influence : influences) { - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - } - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onInAppMessageReceived(GENERIC_ID); - - influences = sessionManager.getInfluences(); - - for (OSInfluence influence : influences) { - switch (influence.getInfluenceChannel()) { - case NOTIFICATION: - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - break; - case IAM: - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - break; - } - } - - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.APP_CLOSE); - threadAndTaskWait(); - - influences = sessionManager.getInfluences(); - - for (OSInfluence influence : influences) { - switch (influence.getInfluenceChannel()) { - case NOTIFICATION: - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - break; - case IAM: - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - break; - } - } - - // We test that channel ending is working - assertNull(lastInfluencesBySessionEnding); - } - - @Test - public void testSessionUpgradeFromUnattributedToIndirect() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - List influences = sessionManager.getInfluences(); - - for (OSInfluence influence : influences) { - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - } - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onInAppMessageReceived(GENERIC_ID); - - influences = sessionManager.getInfluences(); - - for (OSInfluence influence : influences) { - switch (influence.getInfluenceChannel()) { - case NOTIFICATION: - assertEquals(OSInfluenceType.UNATTRIBUTED, influence.getInfluenceType()); - assertNull(influence.getIds()); - break; - case IAM: - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - break; - } - } - - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.APP_OPEN); - threadAndTaskWait(); - - influences = sessionManager.getInfluences(); - - for (OSInfluence influence : influences) { - assertEquals(OSInfluenceType.INDIRECT, influence.getInfluenceType()); - assertEquals(1, influence.getIds().length()); - assertEquals(GENERIC_ID, influence.getIds().get(0)); - } - - // We test that channel ending is working for both IAM and Notification - assertEquals(1, lastInfluencesBySessionEnding.size()); - OSInfluence endingNotificationInfluence = lastInfluencesBySessionEnding.get(0); - - assertEquals(OSInfluenceChannel.NOTIFICATION, endingNotificationInfluence.getInfluenceChannel()); - assertEquals(OSInfluenceType.UNATTRIBUTED, endingNotificationInfluence.getInfluenceType()); - assertNull(endingNotificationInfluence.getIds()); - } - - @Test - public void testSessionUpgradeFromUnattributedToDirectNotification() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - OSInfluence iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.UNATTRIBUTED, iamInfluences.getInfluenceType()); - assertEquals(OSInfluenceType.UNATTRIBUTED, notificationInfluences.getInfluenceType()); - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onInAppMessageReceived(GENERIC_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(GENERIC_ID); - threadAndTaskWait(); - - iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(1, iamInfluences.getIds().length()); - assertEquals(GENERIC_ID, iamInfluences.getIds().get(0)); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(1, notificationInfluences.getIds().length()); - assertEquals(GENERIC_ID, notificationInfluences.getIds().get(0)); - - // We test that channel ending is working for Notification - assertEquals(1, lastInfluencesBySessionEnding.size()); - OSInfluence endingNotificationInfluence = lastInfluencesBySessionEnding.get(0); - - assertEquals(OSInfluenceChannel.NOTIFICATION, endingNotificationInfluence.getInfluenceChannel()); - assertEquals(OSInfluenceType.UNATTRIBUTED, endingNotificationInfluence.getInfluenceType()); - assertNull(endingNotificationInfluence.getIds()); - } - - @Test - public void testSessionUpgradeFromIndirectToDirect() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onInAppMessageReceived(GENERIC_ID); - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.APP_OPEN); - - OSInfluence iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(OSInfluenceType.INDIRECT, notificationInfluences.getInfluenceType()); - assertEquals(GENERIC_ID, notificationInfluences.getIds().get(0)); - - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - threadAndTaskWait(); - - iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(1, iamInfluences.getIds().length()); - assertEquals(GENERIC_ID, iamInfluences.getIds().get(0)); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(1, notificationInfluences.getIds().length()); - assertEquals(NOTIFICATION_ID, notificationInfluences.getIds().get(0)); - - // We test that channel ending is working for both IAM and Notification - assertEquals(1, lastInfluencesBySessionEnding.size()); - OSInfluence endingNotificationInfluence = lastInfluencesBySessionEnding.get(0); - - assertEquals(OSInfluenceChannel.NOTIFICATION, endingNotificationInfluence.getInfluenceChannel()); - assertEquals(OSInfluenceType.INDIRECT, endingNotificationInfluence.getInfluenceType()); - assertEquals(1, endingNotificationInfluence.getIds().length()); - assertEquals(GENERIC_ID, endingNotificationInfluence.getIds().get(0)); - } - - @Test - public void testSessionUpgradeFromDirectToDirectDifferentID() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(GENERIC_ID); - - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(GENERIC_ID, notificationInfluences.getIds().get(0)); - - sessionManager.onNotificationReceived(NOTIFICATION_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - threadAndTaskWait(); - - notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(1, notificationInfluences.getIds().length()); - assertEquals(NOTIFICATION_ID, notificationInfluences.getIds().get(0)); - - // We test that channel ending is working - assertEquals(1, lastInfluencesBySessionEnding.size()); - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesBySessionEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.DIRECT, lastInfluencesBySessionEnding.get(0).getInfluenceType()); - assertEquals(1, lastInfluencesBySessionEnding.get(0).getIds().length()); - assertEquals(GENERIC_ID, lastInfluencesBySessionEnding.get(0).getIds().get(0)); - } - - @Test - public void testSessionUpgradeFromDirectToDirectSameID() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(GENERIC_ID); - - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(GENERIC_ID, notificationInfluences.getIds().get(0)); - - sessionManager.attemptSessionUpgrade(OneSignal.AppEntryAction.NOTIFICATION_CLICK); - threadAndTaskWait(); - - notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(1, notificationInfluences.getIds().length()); - assertEquals(GENERIC_ID, notificationInfluences.getIds().get(0)); - - // We test that channel ending is working - assertEquals(1, lastInfluencesBySessionEnding.size()); - assertEquals(OSInfluenceChannel.NOTIFICATION, lastInfluencesBySessionEnding.get(0).getInfluenceChannel()); - assertEquals(OSInfluenceType.UNATTRIBUTED, lastInfluencesBySessionEnding.get(0).getInfluenceType()); - assertNull(lastInfluencesBySessionEnding.get(0).getIds()); - } - - @Test - public void testSessionUpgradeFromDirectToDirectEndChannelsDirect() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - sessionManager.initSessionFromCache(); - - sessionManager.onNotificationReceived(GENERIC_ID); - sessionManager.onDirectInfluenceFromNotificationOpen(GENERIC_ID); - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onDirectInfluenceFromIAMClick(IAM_ID); - threadAndTaskWait(); - - OSInfluence iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, iamInfluences.getInfluenceType()); - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - assertEquals(GENERIC_ID, notificationInfluences.getIds().get(0)); - - sessionManager.onDirectInfluenceFromNotificationOpen(NOTIFICATION_ID); - threadAndTaskWait(); - - iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.DIRECT, notificationInfluences.getInfluenceType()); - assertEquals(1, notificationInfluences.getIds().length()); - assertEquals(NOTIFICATION_ID, notificationInfluences.getIds().get(0)); - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - - // We test that channel ending is working for both IAM and Notification - assertEquals(2, lastInfluencesBySessionEnding.size()); - OSInfluence endingNotificationInfluence = lastInfluencesBySessionEnding.get(0); - OSInfluence endingIAMInfluence = lastInfluencesBySessionEnding.get(1); - - assertEquals(OSInfluenceChannel.NOTIFICATION, endingNotificationInfluence.getInfluenceChannel()); - assertEquals(OSInfluenceType.DIRECT, endingNotificationInfluence.getInfluenceType()); - assertEquals(1, endingNotificationInfluence.getIds().length()); - assertEquals(GENERIC_ID, endingNotificationInfluence.getIds().get(0)); - - assertEquals(OSInfluenceChannel.IAM, endingIAMInfluence.getInfluenceChannel()); - assertEquals(OSInfluenceType.DIRECT, endingIAMInfluence.getInfluenceType()); - assertEquals(1, endingIAMInfluence.getIds().length()); - assertEquals(IAM_ID, endingIAMInfluence.getIds().get(0)); - } - - @Test - public void testRestartSessionIfNeededFromOpen() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - - OSInfluence iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - assertEquals(OSInfluenceType.INDIRECT, notificationInfluences.getInfluenceType()); - assertEquals(NOTIFICATION_ID, notificationInfluences.getIds().get(0)); - } - - @Test - public void testRestartSessionIfNeededFromClose() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - - OSInfluence iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_CLOSE); - - iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - assertEquals(OSInfluenceType.UNATTRIBUTED, notificationInfluences.getInfluenceType()); - assertNull(notificationInfluences.getIds()); - } - - @Test - public void testRestartSessionIfNeededFromNotification() throws JSONException { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - sessionManager.onInAppMessageReceived(IAM_ID); - sessionManager.onNotificationReceived(NOTIFICATION_ID); - - OSInfluence iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.NOTIFICATION_CLICK); - - iamInfluences = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - OSInfluence notificationInfluences = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - - assertEquals(OSInfluenceType.INDIRECT, iamInfluences.getInfluenceType()); - assertEquals(IAM_ID, iamInfluences.getIds().get(0)); - assertEquals(OSInfluenceType.UNATTRIBUTED, notificationInfluences.getInfluenceType()); - assertNull(notificationInfluences.getIds()); - } - - @Test - public void testIndirectNotificationQuantityInfluence() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - for (int i = 0; i < INFLUENCE_ID_LIMIT + 5; i++) { - sessionManager.onNotificationReceived(GENERIC_ID + i); - } - - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - OSInfluence influence = trackerFactory.getNotificationChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isIndirect()); - assertEquals(INFLUENCE_ID_LIMIT, influence.getIds().length()); - assertEquals(GENERIC_ID + "5", influence.getIds().get(0)); - } - - @Test - public void testIndirectIAMQuantityInfluence() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - for (int i = 0; i < INFLUENCE_ID_LIMIT + 5; i++) { - sessionManager.onInAppMessageReceived(GENERIC_ID + i); - } - - sessionManager.restartSessionIfNeeded(OneSignal.AppEntryAction.APP_OPEN); - - OSInfluence influence = trackerFactory.getIAMChannelTracker().getCurrentSessionInfluence(); - assertTrue(influence.getInfluenceType().isIndirect()); - assertEquals(INFLUENCE_ID_LIMIT, influence.getIds().length()); - assertEquals(GENERIC_ID + "5", influence.getIds().get(0)); - } - -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SynchronizerIntegrationTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SynchronizerIntegrationTests.java deleted file mode 100644 index 47243ba89..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SynchronizerIntegrationTests.java +++ /dev/null @@ -1,2498 +0,0 @@ -package com.test.onesignal; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; - -import androidx.test.core.app.ApplicationProvider; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.MockOneSignalDBHelper; -import com.onesignal.MockSessionManager; -import com.onesignal.OSDeviceState; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowCustomTabsSession; -import com.onesignal.ShadowFocusHandler; -import com.onesignal.ShadowGMSLocationController; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.StaticResetHelper; -import com.onesignal.example.BlankActivity; -import com.onesignal.influence.data.OSTrackerFactory; - -import org.json.JSONObject; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.LooperMode; -import org.robolectric.shadows.ShadowLog; - -import java.lang.reflect.Field; -import java.util.List; - -import static com.onesignal.OneSignal.ExternalIdErrorType.REQUIRES_EXTERNAL_ID_AUTH; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime; -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory; -import static com.onesignal.ShadowOneSignalRestClient.EMAIL_USER_ID; -import static com.onesignal.ShadowOneSignalRestClient.PUSH_USER_ID; -import static com.onesignal.ShadowOneSignalRestClient.SMS_USER_ID; -import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse; -import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndex; -import static com.test.onesignal.RestClientAsserts.assertRestCalls; -import static com.test.onesignal.TestHelpers.afterTestCleanup; -import static com.test.onesignal.TestHelpers.assertAndRunSyncService; -import static com.test.onesignal.TestHelpers.fastColdRestartApp; -import static com.test.onesignal.TestHelpers.pauseActivity; -import static com.test.onesignal.TestHelpers.restartAppAndElapseTimeToNextSession; -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static org.junit.Assert.assertNotEquals; - -@Config(packageName = "com.onesignal.example", - shadows = { - ShadowOneSignalRestClient.class, - ShadowOSUtils.class, - ShadowCustomTabsClient.class, - ShadowCustomTabsSession.class, - ShadowFocusHandler.class - }, - sdk = 21 -) -@RunWith(RobolectricTestRunner.class) -@LooperMode(LooperMode.Mode.LEGACY) -public class SynchronizerIntegrationTests { - private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba"; - private static final String ONESIGNAL_EMAIL_ADDRESS = "test@onesignal.com"; - private static final String ONESIGNAL_SMS_NUMBER = "123456789"; - - @SuppressLint("StaticFieldLeak") - private static Activity blankActivity; - private static ActivityController blankActivityController; - - private MockOSTimeImpl time; - private OSTrackerFactory trackerFactory; - private MockSessionManager sessionManager; - private MockOneSignalDBHelper dbHelper; - - private static JSONObject lastExternalUserIdResponse; - private static OneSignal.ExternalIdError lastExternalUserIdError; - - private static OneSignal.OSExternalUserIdUpdateCompletionHandler getExternalUserIdUpdateCompletionHandler() { - return new OneSignal.OSExternalUserIdUpdateCompletionHandler() { - @Override - public void onSuccess(JSONObject results) { - lastExternalUserIdResponse = results; - } - - @Override - public void onFailure(OneSignal.ExternalIdError error) { - lastExternalUserIdError = error; - } - }; - } - - private static boolean didEmailUpdateSucceed; - private static OneSignal.EmailUpdateError lastEmailUpdateFailure; - - private static OneSignal.EmailUpdateHandler getEmailUpdateHandler() { - return new OneSignal.EmailUpdateHandler() { - @Override - public void onSuccess() { - didEmailUpdateSucceed = true; - } - - @Override - public void onFailure(OneSignal.EmailUpdateError error) { - lastEmailUpdateFailure = error; - } - }; - } - - private static JSONObject didSMSlUpdateSucceed; - private static OneSignal.OSSMSUpdateError lastSMSUpdateFailure; - - private static OneSignal.OSSMSUpdateHandler getSMSUpdateHandler() { - return new OneSignal.OSSMSUpdateHandler() { - @Override - public void onSuccess(JSONObject result) { - didSMSlUpdateSucceed = result; - } - - @Override - public void onFailure(OneSignal.OSSMSUpdateError error) { - lastSMSUpdateFailure = error; - } - }; - } - - private static void cleanUp() throws Exception { - lastExternalUserIdResponse = null; - lastExternalUserIdError = null; - lastEmailUpdateFailure = null; - didEmailUpdateSucceed = false; - - ShadowGMSLocationController.reset(); - - TestHelpers.beforeTestInitAndCleanup(); - - // Set remote_params GET response - setRemoteParamsGetHtmlResponse(); - } - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - TestHelpers.beforeTestSuite(); - - Field OneSignal_CurrentSubscription = OneSignal.class.getDeclaredField("subscribableStatus"); - OneSignal_CurrentSubscription.setAccessible(true); - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - StaticResetHelper.saveStaticValues(); - } - - @Before - public void beforeEachTest() throws Exception { - blankActivityController = Robolectric.buildActivity(BlankActivity.class).create(); - blankActivity = blankActivityController.get(); - time = new MockOSTimeImpl(); - trackerFactory = new OSTrackerFactory(new MockOSSharedPreferences(), new MockOSLog(), time); - sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog()); - dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext()); - - TestHelpers.setupTestWorkManager(blankActivity); - - cleanUp(); - - OneSignal_setTime(time); - } - - @After - public void afterEachTest() throws Exception { - afterTestCleanup(); - } - - @AfterClass - public static void afterEverything() throws Exception { - cleanUp(); - } - - @Test - public void shouldSetEmail() throws Exception { - OneSignalInit(); - String email = "josh@onesignal.com"; - - OneSignal.setEmail(email); - threadAndTaskWait(); - - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - - JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload; - assertEquals(email, pushPost.getString("email")); - assertEquals(1, pushPost.getInt("device_type")); - - JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(email, emailPost.getString("identifier")); - assertEquals(11, emailPost.getInt("device_type")); - assertEquals(ShadowOneSignalRestClient.pushUserId, emailPost.getString("device_player_id")); - - JSONObject pushPut = ShadowOneSignalRestClient.requests.get(3).payload; - assertEquals(ShadowOneSignalRestClient.emailUserId, pushPut.getString("parent_player_id")); - assertFalse(pushPut.has("identifier")); - } - - @Test - public void shouldSetSMS() throws Exception { - OneSignalInit(); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // NO parent player id call - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload; - assertEquals(ONESIGNAL_SMS_NUMBER, pushPost.getString("sms_number")); - assertEquals(1, pushPost.getInt("device_type")); - - JSONObject smsPost = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type")); - assertEquals(ShadowOneSignalRestClient.pushUserId, smsPost.getString("device_player_id")); - } - - @Test - public void shouldSetSMSAndEmail() throws Exception { - OneSignalInit(); - - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - - JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload; - assertEquals(ONESIGNAL_EMAIL_ADDRESS, pushPost.getString("email")); - assertEquals(ONESIGNAL_SMS_NUMBER, pushPost.getString("sms_number")); - assertEquals(1, pushPost.getInt("device_type")); - - JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(ONESIGNAL_EMAIL_ADDRESS, emailPost.getString("identifier")); - assertEquals(11, emailPost.getInt("device_type")); - assertEquals(ShadowOneSignalRestClient.pushUserId, emailPost.getString("device_player_id")); - - JSONObject smsPost = ShadowOneSignalRestClient.requests.get(3).payload; - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type")); - assertEquals(ShadowOneSignalRestClient.pushUserId, smsPost.getString("device_player_id")); - - JSONObject pushPut = ShadowOneSignalRestClient.requests.get(4).payload; - assertEquals(ShadowOneSignalRestClient.emailUserId, pushPut.getString("parent_player_id")); - // add email parent id call - // TODO: check if this behaviour is not dropped - assertFalse(pushPut.has("identifier")); - } - - @Test - public void shouldSendTagsToEmailBeforeCreate() throws Exception { - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals("josh@onesignal.com", emailPost.payload.get("identifier")); - assertEquals(tagsJson.toString(), emailPost.payload.getJSONObject("tags").toString()); - } - - @Test - public void shouldSendTagsToSMSBeforeCreate() throws Exception { - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.get("identifier")); - assertEquals(tagsJson.toString(), smsPost.payload.getJSONObject("tags").toString()); - } - - @Test - public void shouldWaitBeforeCreateEmailIfPushCreateFails() throws Exception { - ShadowOneSignalRestClient.failPosts = true; - - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - // Assert we are sending / retry for the push player first. - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - for (int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) { - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(i); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals(1, emailPost.payload.getInt("device_type")); - } - - // Turn off fail mocking, call sendTags to trigger another retry - ShadowOneSignalRestClient.failPosts = false; - OneSignal.sendTag("test", "test"); - threadAndTaskWait(); - - // Should now POST to create device_type 11 (email) - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals("josh@onesignal.com", emailPost.payload.get("identifier")); - } - - @Test - public void shouldWaitBeforeCreateSMSIfPushCreateFails() throws Exception { - ShadowOneSignalRestClient.failPosts = true; - - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // Assert we are sending / retry for the push player first. - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - for (int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) { - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(i); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.getString("sms_number")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_ANDROID, smsPost.payload.getInt("device_type")); - } - - // Turn off fail mocking, call sendTags to trigger another retry - ShadowOneSignalRestClient.failPosts = false; - OneSignal.sendTag("test", "test"); - threadAndTaskWait(); - - // Should now POST to create device_type 14 (sms) - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.get("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.get("device_type")); - } - - @Test - public void shouldWaitBeforeCreateEmailAndSMSIfPushCreateFails() throws Exception { - ShadowOneSignalRestClient.failPosts = true; - - OneSignalInit(); - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // Assert we are sending / retry for the push player first. - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - for (int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) { - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(i); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(ONESIGNAL_EMAIL_ADDRESS, smsPost.payload.getString("email")); - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.getString("sms_number")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_ANDROID, smsPost.payload.getInt("device_type")); - } - - // Turn off fail mocking, call sendTags to trigger another retry - ShadowOneSignalRestClient.failPosts = false; - OneSignal.sendTag("test", "test"); - threadAndTaskWait(); - - // Should now POST to create device_type 11 (email) - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals(ONESIGNAL_EMAIL_ADDRESS, emailPost.payload.get("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_EMAIL, emailPost.payload.get("device_type")); - - // Should now POST to create device_type 14 (email) - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(7); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.get("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.get("device_type")); - } - - @Test - public void shouldSendTagsToEmailAfterCreate() throws Exception { - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(6, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method); - assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522", emailPut.url); - assertEquals(tagsJson.toString(), emailPut.payload.getJSONObject("tags").toString()); - } - - @Test - public void shouldSendTagsToSMSAfterCreate() throws Exception { - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method); - assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url); - assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString()); - } - - @Test - public void shouldSendTagsToSMSWithHashToken() throws Exception { - String mockSMSHash = new String(new char[64]).replace('\0', '0'); - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash); - threadAndTaskWait(); - - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method); - assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url); - assertEquals(3, smsPut.payload.length()); - assertTrue(smsPut.payload.has("app_id")); - assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString()); - assertEquals(mockSMSHash, smsPut.payload.getString("sms_auth_hash")); - } - - @Test - public void shouldSendTagsToEmailAndSMSAfterCreate() throws Exception { - OneSignalInit(); - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(8, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method); - assertEquals("players/" + ShadowOneSignalRestClient.emailUserId, emailPut.url); - assertEquals(tagsJson.toString(), emailPut.payload.getJSONObject("tags").toString()); - - ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(7); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method); - assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url); - assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString()); - } - - @Test - public void shouldSetEmailWithAuthHash() throws Exception { - OneSignalInit(); - String email = "josh@onesignal.com"; - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setEmail(email, mockEmailHash); - threadAndTaskWait(); - - JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(email, emailPost.getString("identifier")); - assertEquals(11, emailPost.getInt("device_type")); - assertEquals(mockEmailHash, emailPost.getString("email_auth_hash")); - } - - @Test - public void shouldSetSMSWithAuthHash() throws Exception { - OneSignalInit(); - String mockSMSHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash); - threadAndTaskWait(); - - JSONObject smsPost = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type")); - assertEquals(mockSMSHash, smsPost.getString("sms_auth_hash")); - } - - @Test - public void shouldSetEmailAndSMSWithAuthHash() throws Exception { - OneSignalInit(); - String mockEmailHash = new String(new char[64]).replace('\0', '1'); - String mockSMSHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, mockEmailHash); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash); - threadAndTaskWait(); - - JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload; - assertEquals(ONESIGNAL_EMAIL_ADDRESS, emailPost.getString("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_EMAIL, emailPost.getInt("device_type")); - assertEquals(mockEmailHash, emailPost.getString("email_auth_hash")); - - JSONObject smsPost = ShadowOneSignalRestClient.requests.get(3).payload; - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type")); - assertEquals(mockSMSHash, smsPost.getString("sms_auth_hash")); - } - - private class TestEmailUpdateHandler implements OneSignal.EmailUpdateHandler { - boolean emailFiredSuccess = false; - OneSignal.EmailUpdateError emailFiredFailure = null; - - @Override - public void onSuccess() { - emailFiredSuccess = true; - } - - @Override - public void onFailure(OneSignal.EmailUpdateError error) { - emailFiredFailure = error; - } - } - - /** - * @see #shouldSetExternalUserId_inOnSuccessOfEmailUpdate - */ - private class TestEmailUpdateHandler_onSuccess_callSetExternalUserId implements OneSignal.EmailUpdateHandler { - boolean emailFiredSuccess = false; - OneSignal.EmailUpdateError emailFiredFailure = null; - String testExternalId = "test_ext_id"; - - @Override - public void onSuccess() { - emailFiredSuccess = true; - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - } - - @Override - public void onFailure(OneSignal.EmailUpdateError error) { - emailFiredFailure = error; - } - } - - private class TestSMSUpdateHandler implements OneSignal.OSSMSUpdateHandler { - JSONObject smsResult = null; - OneSignal.OSSMSUpdateError smsFiredFailure = null; - - @Override - public void onSuccess(JSONObject result) { - smsResult = result; - } - - @Override - public void onFailure(OneSignal.OSSMSUpdateError error) { - smsFiredFailure = error; - } - } - - /** - * @see #shouldSetExternalUserId_inOnSuccessOfSMSUpdate - */ - private class TestSMSUpdateHandler_onSuccess_callSetExternalUserId implements OneSignal.OSSMSUpdateHandler { - JSONObject smsResult = null; - OneSignal.OSSMSUpdateError smsFiredFailure = null; - String testExternalId = "test_ext_id"; - - @Override - public void onSuccess(JSONObject result) { - smsResult = result; - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - } - - @Override - public void onFailure(OneSignal.OSSMSUpdateError error) { - smsFiredFailure = error; - } - } - - @Test - public void shouldFireOnSuccessOfEmailUpdate() throws Exception { - OneSignalInit(); - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler); - assertFalse(testEmailUpdateHandler.emailFiredSuccess); - threadAndTaskWait(); - - assertTrue(testEmailUpdateHandler.emailFiredSuccess); - assertNull(testEmailUpdateHandler.emailFiredFailure); - } - - @Test - public void shouldFireOnSuccessOfSMSUpdate() throws Exception { - OneSignalInit(); - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler); - assertNull(testSMSUpdateHandler.smsResult); - threadAndTaskWait(); - - assertNotNull(testSMSUpdateHandler.smsResult); - assertEquals(1, testSMSUpdateHandler.smsResult.length()); - assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.get("sms_number")); - assertNull(testSMSUpdateHandler.smsFiredFailure); - } - - @Test - public void shouldFireOnSuccessOfEmailEvenWhenNoChanges() throws Exception { - OneSignalInit(); - String email = "josh@onesignal.com"; - OneSignal.setEmail(email); - threadAndTaskWait(); - - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - OneSignal.setEmail(email, testEmailUpdateHandler); - threadAndTaskWait(); - - assertTrue(testEmailUpdateHandler.emailFiredSuccess); - assertNull(testEmailUpdateHandler.emailFiredFailure); - } - - @Test - public void shouldFireOnSuccessOfSMSEvenWhenNoChanges() throws Exception { - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler); - threadAndTaskWait(); - - assertNotNull(testSMSUpdateHandler.smsResult); - assertEquals(1, testSMSUpdateHandler.smsResult.length()); - assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.get("sms_number")); - assertNull(testSMSUpdateHandler.smsFiredFailure); - } - - @Test - public void shouldFireOnFailureOfEmailUpdateOnNetworkFailure() throws Exception { - OneSignalInit(); - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler); - ShadowOneSignalRestClient.failAll = true; - threadAndTaskWait(); - - assertFalse(testEmailUpdateHandler.emailFiredSuccess); - assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType()); - } - - @Test - public void shouldFireOnFailureOfSMSlUpdateOnNetworkFailure() throws Exception { - OneSignalInit(); - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler); - ShadowOneSignalRestClient.failAll = true; - threadAndTaskWait(); - - assertNull(testSMSUpdateHandler.smsResult); - assertNotNull(testSMSUpdateHandler.smsFiredFailure); - assertEquals(OneSignal.SMSErrorType.NETWORK, testSMSUpdateHandler.smsFiredFailure.getType()); - } - - @Test - public void shouldFireOnFailureOfEmailAndSMSlUpdateOnNetworkFailure() throws Exception { - OneSignalInit(); - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, testEmailUpdateHandler); - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler); - ShadowOneSignalRestClient.failAll = true; - threadAndTaskWait(); - - assertFalse(testEmailUpdateHandler.emailFiredSuccess); - assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType()); - - assertNull(testSMSUpdateHandler.smsResult); - assertNotNull(testSMSUpdateHandler.smsFiredFailure); - assertEquals(OneSignal.SMSErrorType.NETWORK, testSMSUpdateHandler.smsFiredFailure.getType()); - } - - @Test - public void shouldFireOnSuccessOnlyAfterNetworkCallAfterEmailLogout() throws Exception { - OneSignalInit(); - emailSetThenLogout(); - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler); - assertFalse(testEmailUpdateHandler.emailFiredSuccess); - threadAndTaskWait(); - - assertTrue(testEmailUpdateHandler.emailFiredSuccess); - assertNull(testEmailUpdateHandler.emailFiredFailure); - } - - @Test - public void shouldFireOnSuccessOnlyAfterNetworkCallAfterSMSLogout() throws Exception { - OneSignalInit(); - smsSetThenLogout(); - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler); - assertNull(testSMSUpdateHandler.smsResult); - threadAndTaskWait(); - - assertNotNull(testSMSUpdateHandler.smsResult); - assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.getString("sms_number")); - assertNull(testSMSUpdateHandler.smsFiredFailure); - } - - // Should create a new email instead of updating existing player record when no auth hash - @Test - public void shouldDoPostOnEmailChange() throws Exception { - OneSignalInit(); - - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - String newMockEmailPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533"; - ShadowOneSignalRestClient.emailUserId = newMockEmailPlayerId; - String newEmail = "different@email.com"; - OneSignal.setEmail(newEmail); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals(newEmail, emailPost.payload.get("identifier")); - - ShadowOneSignalRestClient.Request playerPut = ShadowOneSignalRestClient.requests.get(6); - assertEquals(newMockEmailPlayerId, playerPut.payload.get("parent_player_id")); - } - - // Should create a new sms instead of updating existing player record when no auth hash - @Test - public void shouldDoPostOnSMSChange() throws Exception { - OneSignalInit(); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - String newMockSMSPlayerId = "z007f967-98cc-11e4-bed1-118f05be4533"; - ShadowOneSignalRestClient.smsUserId = newMockSMSPlayerId; - String newSMS = "different_sms_number"; - OneSignal.setSMSNumber(newSMS); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(newSMS, smsPost.payload.get("identifier")); - } - - // Should update player with new email instead of creating a new one when auth hash is provided - @Test - public void shouldUpdateEmailWhenAuthHashIsUsed() throws Exception { - OneSignalInit(); - String email = "josh@onesignal.com"; - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setEmail(email, mockEmailHash); - threadAndTaskWait(); - OneSignal.setEmail("different@email.com", mockEmailHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request pushPut = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, pushPut.method); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", pushPut.url); - assertEquals("different@email.com", pushPut.payload.get("email")); - - ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method); - assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522", emailPut.url); - assertEquals("different@email.com", emailPut.payload.get("identifier")); - } - - // Should update player with new sms instead of creating a new one when auth hash is provided - @Test - public void shouldUpdateSMSlWhenAuthHashIsUsed() throws Exception { - OneSignalInit(); - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockEmailHash); - threadAndTaskWait(); - String newSMS = "different_sms_number"; - OneSignal.setSMSNumber(newSMS, mockEmailHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request pushPut = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, pushPut.method); - assertEquals("players/" + PUSH_USER_ID, pushPut.url); - assertEquals(newSMS, pushPut.payload.get("sms_number")); - - ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method); - assertEquals("players/" + SMS_USER_ID, smsPut.url); - assertEquals(newSMS, smsPut.payload.get("identifier")); - } - - @Test - public void shouldSendEmailAuthHashWithLogout() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - OneSignal.setEmail("josh@onesignal.com", mockEmailHash); - threadAndTaskWait(); - - OneSignal.logoutEmail(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/email_logout", emailPut.url); - assertEquals(mockEmailHash, emailPut.payload.get("email_auth_hash")); - } - - private void emailSetThenLogout() throws Exception { - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - OneSignal.logoutEmail(); - threadAndTaskWait(); - } - - private void smsSetThenLogout() throws Exception { - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - OneSignal.logoutSMSNumber(); - threadAndTaskWait(); - } - - @Test - public void shouldLogoutOfEmail() throws Exception { - OneSignalInit(); - - emailSetThenLogout(); - - ShadowOneSignalRestClient.Request logoutEmailPost = ShadowOneSignalRestClient.requests.get(4); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/email_logout", logoutEmailPost.url); - assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", logoutEmailPost.payload.get("parent_player_id")); - assertEquals("b4f7f966-d8cc-11e4-bed1-df8f05be55ba", logoutEmailPost.payload.get("app_id")); - } - - @Test - public void shouldLogoutOfSMS() throws Exception { - OneSignalInit(); - - smsSetThenLogout(); - - OSDeviceState deviceState = OneSignal.getDeviceState(); - assertNull(deviceState.getSMSUserId()); - assertNull(deviceState.getSMSNumber()); - } - - @Test - public void logoutEmailShouldNotSendEmailPlayersRequest() throws Exception { - // 1. Init OneSignal and set email - OneSignalInit(); - - emailSetThenLogout(); - - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertEquals(6, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(4); - assertNotEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", postPush.url); - - ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(5); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postEmail.url); - } - - @Test - public void logoutSMSShouldNotSendSMSPlayersRequest() throws Exception { - // 1. Init OneSignal and set email - OneSignalInit(); - - smsSetThenLogout(); - - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertEquals(4, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(3); - assertNotEquals("players/" + PUSH_USER_ID, postPush.url); - } - - @Test - public void shouldFireOnSuccessOfLogoutEmail() throws Exception { - OneSignalInit(); - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - OneSignal.logoutEmail(testEmailUpdateHandler); - threadAndTaskWait(); - - assertTrue(testEmailUpdateHandler.emailFiredSuccess); - assertNull(testEmailUpdateHandler.emailFiredFailure); - } - - @Test - public void shouldFireOnSuccessOfLogoutSMS() throws Exception { - OneSignalInit(); - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - OneSignal.logoutSMSNumber(testSMSUpdateHandler); - threadAndTaskWait(); - - assertNotNull(testSMSUpdateHandler.smsResult); - assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.getString("sms_number")); - assertNull(testSMSUpdateHandler.smsFiredFailure); - } - - @Test - public void shouldFireOnFailureOfLogoutEmailOnNetworkFailure() throws Exception { - OneSignalInit(); - TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler(); - - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - ShadowOneSignalRestClient.failAll = true; - OneSignal.logoutEmail(testEmailUpdateHandler); - threadAndTaskWait(); - - assertFalse(testEmailUpdateHandler.emailFiredSuccess); - assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType()); - } - - @Test - public void shouldNotFireOnFailureOfLogoutSMSOnNetworkFailure() throws Exception { - OneSignalInit(); - TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler(); - - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - ShadowOneSignalRestClient.failAll = true; - OneSignal.logoutSMSNumber(testSMSUpdateHandler); - threadAndTaskWait(); - - assertNotNull(testSMSUpdateHandler.smsResult); - assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.getString("sms_number")); - assertNull(testSMSUpdateHandler.smsFiredFailure); - } - - @Test - public void shouldCreateNewEmailAfterLogout() throws Exception { - OneSignalInit(); - - emailSetThenLogout(); - - String newMockEmailPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533"; - ShadowOneSignalRestClient.emailUserId = newMockEmailPlayerId; - OneSignal.setEmail("different@email.com"); - threadAndTaskWait(); - - // Update Push record's email field. - ShadowOneSignalRestClient.Request putPushEmail = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, putPushEmail.method); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", putPushEmail.url); - assertEquals("different@email.com", putPushEmail.payload.get("email")); - - // Create new Email record - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals("different@email.com", emailPost.payload.get("identifier")); - - // Update Push record's parent_player_id - ShadowOneSignalRestClient.Request playerPut2 = ShadowOneSignalRestClient.requests.get(7); - assertEquals(newMockEmailPlayerId, playerPut2.payload.get("parent_player_id")); - } - - @Test - public void shouldCreateNewSMSAfterLogout() throws Exception { - OneSignalInit(); - - smsSetThenLogout(); - - String newMockSMSPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533"; - String newSMSNumber = "new_sms_number"; - - ShadowOneSignalRestClient.smsUserId = newMockSMSPlayerId; - OneSignal.setSMSNumber(newSMSNumber); - threadAndTaskWait(); - - // There should not be a parent_player_id update, last SMS POST should be the last one - assertEquals(5, ShadowOneSignalRestClient.requests.size()); - - // Update Push record's sms field. - ShadowOneSignalRestClient.Request putPushSMS = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, putPushSMS.method); - assertEquals("players/" + PUSH_USER_ID, putPushSMS.url); - assertEquals(newSMSNumber, putPushSMS.payload.get("sms_number")); - - // Create new SMS record - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(newSMSNumber, smsPost.payload.get("identifier")); - } - - // ####### external_id Tests ######## - - @Test - public void shouldSendExternalUserIdAfterRegistration() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - - OneSignal.setExternalUserId(testExternalId); - - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method); - assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id")); - } - - @Test - public void shouldSendExternalUserIdBeforeRegistration() throws Exception { - String testExternalId = "test_ext_id"; - - OneSignal.setExternalUserId(testExternalId); - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method); - assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id")); - } - - @Test - public void shouldSetExternalIdWithAuthHash() throws Exception { - ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("require_user_id_auth", true)); - - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - assertNotNull(lastExternalUserIdError); - assertEquals(REQUIRES_EXTERNAL_ID_AUTH, lastExternalUserIdError.getType()); - } - - @Test - public void shouldSetExternalIdWithAuthHashAfterRegistration() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method); - assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash, externalIdRequest.payload.getString("external_user_id_auth_hash")); - } - - @Test - public void shouldSetExternalIdWithAuthHashBeforeRegistration() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method); - assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash")); - } - - @Test - public void shouldAlwaysSetExternalIdWithAuthHashAfterRegistration() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method); - assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash")); - - fastColdRestartApp(); - - time.advanceSystemTimeBy(60); - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequestAfterColdStart.method); - assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash")); - } - - @Test - public void shouldAlwaysSetExternalIdAndEmailWithAuthHashAfterRegistration() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - String email = "josh@onesignal.com"; - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - OneSignal.setEmail(email, mockEmailHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method); - assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals(email, emailPost.payload.getString("identifier")); - assertEquals(11, emailPost.payload.getInt("device_type")); - assertEquals(mockEmailHash, emailPost.payload.getString("email_auth_hash")); - - fastColdRestartApp(); - - time.advanceSystemTimeBy(60); - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequestAfterColdStart.method); - assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request emailPostAfterColdStart = ShadowOneSignalRestClient.requests.get(7); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPostAfterColdStart.method); - assertEquals(11, emailPostAfterColdStart.payload.getInt("device_type")); - assertEquals(mockEmailHash, emailPostAfterColdStart.payload.getString("email_auth_hash")); - } - - @Test - public void shouldAlwaysSetExternalIdAndSMSWithAuthHashAfterRegistration() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - String mockSMSlHash = new String(new char[64]).replace('\0', '1'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSlHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method); - assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.getString("identifier")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.getInt("device_type")); - assertEquals(mockSMSlHash, smsPost.payload.getString("sms_auth_hash")); - - fastColdRestartApp(); - - time.advanceSystemTimeBy(60); - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequestAfterColdStart.method); - assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request smsPostAfterColdStart = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPostAfterColdStart.method); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPostAfterColdStart.payload.getInt("device_type")); - assertEquals(mockSMSlHash, smsPostAfterColdStart.payload.getString("sms_auth_hash")); - } - - @Test - public void shouldSetExternalIdOnSMS() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - String mockSMSlHash = new String(new char[64]).replace('\0', '1'); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSlHash); - threadAndTaskWait(); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request setExternalIdOnSMSChannel = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, setExternalIdOnSMSChannel.method); - assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, setExternalIdOnSMSChannel.url); - assertEquals(testExternalId, setExternalIdOnSMSChannel.payload.get("external_user_id")); - assertEquals(mockExternalIdHash, setExternalIdOnSMSChannel.payload.get("external_user_id_auth_hash")); - assertEquals(mockSMSlHash, setExternalIdOnSMSChannel.payload.get("sms_auth_hash")); - } - - @Test - public void shouldSetExternalIdWithAuthHashOnSendTagsSMS() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - String mockSMSHash = new String(new char[64]).replace('\0', '0'); - - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash); - threadAndTaskWait(); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - threadAndTaskWait(); - - JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}"); - OneSignal.sendTags(tagsJson); - threadAndTaskWait(); - - assertEquals(7, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method); - assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url); - assertEquals(4, smsPut.payload.length()); - assertTrue(smsPut.payload.has("app_id")); - assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString()); - assertEquals(mockSMSHash, smsPut.payload.getString("sms_auth_hash")); - assertEquals(mockExternalIdHash, smsPut.payload.getString("external_user_id_auth_hash")); - } - - @Test - public void shouldNotSetExternalIdOnSMShWithLaterSMSNumber() throws Exception { - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - String mockSMSlHash = new String(new char[64]).replace('\0', '1'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - threadAndTaskWait(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSlHash); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request setSMSNumberSMSChannelRequest = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, setSMSNumberSMSChannelRequest.method); - assertTrue(setSMSNumberSMSChannelRequest.payload.has("identifier")); - assertTrue(setSMSNumberSMSChannelRequest.payload.has("sms_auth_hash")); - assertFalse(setSMSNumberSMSChannelRequest.payload.has("external_user_id")); - assertFalse(setSMSNumberSMSChannelRequest.payload.has("external_user_id_auth_hash")); - } - - @Test - public void shouldRemoveExternalUserId() throws Exception { - OneSignal.setExternalUserId("test_ext_id"); - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(); - threadAndTaskWait(); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - } - - @Test - public void shouldRemoveExternalUserIdFromPushWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash")); - } - - @Test - public void shouldRemoveExternalUserIdFromEmailWithAuthHash() throws Exception { - String testEmail = "test@test.com"; - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setEmail(testEmail, mockEmailHash, getEmailUpdateHandler()); - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + ", " + - " \"email\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - assertTrue(didEmailUpdateSucceed); - assertNull(lastEmailUpdateFailure); - - assertEquals(6, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertFalse(removeIdRequest.payload.has("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method); - assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), ""); - assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash")); - } - - @Test - public void shouldRemoveExternalUserIdFromSMSWithAuthHash() throws Exception { - String mockSMSHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, getSMSUpdateHandler()); - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + ", " + - " \"sms\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - assertNotNull(didSMSlUpdateSucceed); - assertNull(lastEmailUpdateFailure); - - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertFalse(removeIdRequest.payload.has("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request removeIdSMSRequest = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdSMSRequest.method); - assertEquals(removeIdSMSRequest.payload.getString("external_user_id"), ""); - assertEquals(mockSMSHash, removeIdSMSRequest.payload.getString("sms_auth_hash")); - } - - @Test - public void shouldRemoveExternalUserIdFromPushAndEmailWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - String testEmail = "test@test.com"; - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - OneSignal.setEmail(testEmail, mockEmailHash, null); - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(); - threadAndTaskWait(); - - assertEquals(6, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method); - assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), ""); - assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash")); - } - - @Test - public void shouldRemoveExternalUserIdFromPushAndSMSWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - String mockSMSHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, null); - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(); - threadAndTaskWait(); - - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request removeIdSMSRequest = ShadowOneSignalRestClient.requests.get(4); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdSMSRequest.method); - assertEquals(removeIdSMSRequest.payload.getString("external_user_id"), ""); - assertEquals(mockSMSHash, removeIdSMSRequest.payload.getString("sms_auth_hash")); - } - - @Test - public void shouldRemoveExternalUserIdFromPushAndEmailAndSMSWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - String mockEmailHash = new String(new char[64]).replace('\0', '0'); - String mockSMSHash = new String(new char[64]).replace('\0', '1'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, mockEmailHash, null); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, null); - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.removeExternalUserId(); - threadAndTaskWait(); - - assertEquals(8, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method); - assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), ""); - assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash")); - - ShadowOneSignalRestClient.Request removeIdSMSRequest = ShadowOneSignalRestClient.requests.get(7); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdSMSRequest.method); - assertEquals(removeIdSMSRequest.payload.getString("external_user_id"), ""); - assertEquals(mockSMSHash, removeIdSMSRequest.payload.getString("sms_auth_hash")); - } - - // The external_user_id_auth_hash should be removed from the user state - @Test - public void shouldPopAuthHash_afterRemoveExternalUserIdFromPushWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - OneSignalInit(); - threadAndTaskWait(); - - // Check that external_user_id_auth_hash is in syncValues - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - JSONObject syncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - assertEquals(testExternalId, syncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, syncValues.getString("external_user_id_auth_hash")); - - // Call to remove external user ID - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - assertEquals(3, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method); - assertEquals(removeIdRequest.payload.getString("external_user_id"), ""); - assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash")); - - // Check that external_user_id_auth_hash is no longer in syncValues and has "" as external_user_id - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences newPrefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - syncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - assertFalse(syncValues.has("external_user_id_auth_hash")); - assertEquals("", syncValues.getString("external_user_id")); - } - - @Test - public void shouldPopAuthHash_afterRemoveExternalUserIdFromPushAndEmailWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - String testEmail = "test@test.com"; - String mockEmailHash = new String(new char[64]).replace('\0', '1'); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set email and email hash - OneSignal.setEmail(testEmail, mockEmailHash, getEmailUpdateHandler()); - threadAndTaskWait(); - - // 3. Attempt to set external Id with auth hash - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - threadAndTaskWait(); - - // 4. Check the user state for push and email - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - JSONObject pushSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - JSONObject emailSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_emailCURRENT_STATE", null)); - - assertEquals(testExternalId, pushSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, pushSyncValues.getString("external_user_id_auth_hash")); - - assertEquals(testExternalId, emailSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, emailSyncValues.getString("external_user_id_auth_hash")); - - // 5. Call to remove external user ID - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + ", " + - " \"email\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - assertTrue(didEmailUpdateSucceed); - assertNull(lastEmailUpdateFailure); - - // 6. Check that external_user_id_auth_hash is no longer in syncValues and has "" as external_user_id - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences newPrefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - pushSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - emailSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_emailCURRENT_STATE", null)); - - assertFalse(pushSyncValues.has("external_user_id_auth_hash")); - assertEquals("", pushSyncValues.getString("external_user_id")); - - assertFalse(emailSyncValues.has("external_user_id_auth_hash")); - assertEquals("", emailSyncValues.getString("external_user_id")); - } - - @Test - public void shouldPopAuthHash_afterRemoveExternalUserIdFromPushAndSMSWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - String mockSMSHash = new String(new char[64]).replace('\0', '1'); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set SMS and SMS hash - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, null); - threadAndTaskWait(); - - // 3. Attempt to set external Id with auth hash - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - threadAndTaskWait(); - - // 4. Check the user state for sms and email - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - JSONObject pushSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - JSONObject smsSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_smsCURRENT_STATE", null)); - - assertEquals(testExternalId, pushSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, pushSyncValues.getString("external_user_id_auth_hash")); - - assertEquals(testExternalId, smsSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, smsSyncValues.getString("external_user_id_auth_hash")); - - // 5. Call to remove external user ID - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + ", " + - " \"sms\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 6. Check that external_user_id_auth_hash is no longer in syncValues and has "" as external_user_id - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences newPrefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - pushSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - smsSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_smsCURRENT_STATE", null)); - - assertFalse(pushSyncValues.has("external_user_id_auth_hash")); - assertEquals("", pushSyncValues.getString("external_user_id")); - - assertFalse(smsSyncValues.has("external_user_id_auth_hash")); - assertEquals("", smsSyncValues.getString("external_user_id")); - } - - @Test - public void shouldPopAuthHash_afterRemoveExternalUserIdFromPushAndEmailAndSMSWithAuthHash() throws Exception { - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - String mockEmailHash = new String(new char[64]).replace('\0', '1'); - String mockSMSHash = new String(new char[64]).replace('\0', '2'); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set SMS and SMS hash - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, null); - threadAndTaskWait(); - - // 3. Attempt to set email and email hash - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, mockEmailHash, null); - threadAndTaskWait(); - - // 4. Attempt to set external Id with auth hash - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null); - threadAndTaskWait(); - - // 5. Check the user state for sms and email and push - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - JSONObject pushSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - JSONObject smsSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_smsCURRENT_STATE", null)); - JSONObject emailSyncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_emailCURRENT_STATE", null)); - - assertEquals(testExternalId, pushSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, pushSyncValues.getString("external_user_id_auth_hash")); - - assertEquals(testExternalId, smsSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, smsSyncValues.getString("external_user_id_auth_hash")); - - assertEquals(testExternalId, emailSyncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash, emailSyncValues.getString("external_user_id_auth_hash")); - - // 6. Call to remove external user ID - OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }," + - " \"email\" : {" + - " \"success\" : true" + - " }," + - " \"sms\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 7. Check that external_user_id_auth_hash is no longer in syncValues and has "" as external_user_id - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences newPrefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - pushSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - smsSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_smsCURRENT_STATE", null)); - emailSyncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_emailCURRENT_STATE", null)); - - assertFalse(pushSyncValues.has("external_user_id_auth_hash")); - assertEquals("", pushSyncValues.getString("external_user_id")); - - assertFalse(smsSyncValues.has("external_user_id_auth_hash")); - assertEquals("", smsSyncValues.getString("external_user_id")); - - assertFalse(emailSyncValues.has("external_user_id_auth_hash")); - assertEquals("", emailSyncValues.getString("external_user_id")); - } - - @Test - public void doesNotSendSameExternalId() throws Exception { - String testExternalId = "test_ext_id"; - OneSignal.setExternalUserId(testExternalId); - - OneSignalInit(); - threadAndTaskWait(); - - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - - OneSignal.setExternalUserId(testExternalId); - threadAndTaskWait(); - - // Setting the same ID again should not generate a duplicate API request - // The SDK should detect it is the same and not generate a request - assertEquals(2, ShadowOneSignalRestClient.networkCallCount); - } - - @Test - public void sendsExternalIdOnEmailPlayers() throws Exception { - String testExternalId = "test_ext_id"; - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.setEmail("brad@onesignal.com"); - threadAndTaskWait(); - - int currentRequestCount = ShadowOneSignalRestClient.networkCallCount; - - OneSignal.setExternalUserId(testExternalId); - threadAndTaskWait(); - - // the SDK should have made two additional API calls - // One to set extID on the push player record, - // and another for the email player record - assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 2); - - int externalIdRequests = 0; - - for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) { - if (request.payload != null && request.payload.has("external_user_id")) { - externalIdRequests += 1; - assertEquals(request.payload.getString("external_user_id"), testExternalId); - } - } - - assertEquals(externalIdRequests, 2); - } - - @Test - public void sendsExternalIdOnSMSPlayers() throws Exception { - String testExternalId = "test_ext_id"; - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - int currentRequestCount = ShadowOneSignalRestClient.networkCallCount; - - OneSignal.setExternalUserId(testExternalId); - threadAndTaskWait(); - - // the SDK should have made two additional API calls - // One to set extID on the push player record, - // and another for the sms player record - assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 2); - - int externalIdRequests = 0; - - for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) { - if (request.payload != null && request.payload.has("external_user_id")) { - externalIdRequests += 1; - assertEquals(request.payload.getString("external_user_id"), testExternalId); - } - } - - assertEquals(externalIdRequests, 2); - } - - @Test - public void sendsExternalIdOnEmailAndSMSPlayers() throws Exception { - String testExternalId = "test_ext_id"; - - OneSignalInit(); - threadAndTaskWait(); - - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - int currentRequestCount = ShadowOneSignalRestClient.networkCallCount; - - OneSignal.setExternalUserId(testExternalId); - threadAndTaskWait(); - - // the SDK should have made two additional API calls - // One to set extID on the push player record, - // another for the sms player record - // and another for email sms player record - assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 3); - - int externalIdRequests = 0; - - for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) { - if (request.payload != null && request.payload.has("external_user_id")) { - externalIdRequests += 1; - assertEquals(request.payload.getString("external_user_id"), testExternalId); - } - } - - assertEquals(externalIdRequests, 3); - } - - @Test - public void sendExternalUserId_withCompletionHandler() throws Exception { - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse is equal to the expected response - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendDifferentExternalUserId_withCompletionHandler() throws Exception { - String testExternalId = "test_ext_id_1"; - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse is equal to the expected response - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Change test external user id to send - testExternalId = "test_ext_id_2"; - - // 5. Attempt to set same exact external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 6. Make sure lastExternalUserIdResponse is equal to the expected response - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendDifferentExternalUserId_withAuthHash_withCompletionHandler() throws Exception { - String testExternalId1 = "test_ext_id_1"; - String mockExternalIdHash1 = new String(new char[64]).replace('\0', '0'); - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set external user id and auth hash with callback - OneSignal.setExternalUserId(testExternalId1, mockExternalIdHash1, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse is equal to the expected response - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Check the external user id and auth hash values in syncValues - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences prefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - JSONObject syncValues = new JSONObject(prefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - assertEquals(testExternalId1, syncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash1, syncValues.getString("external_user_id_auth_hash")); - - // 5. Change test external user id and auth hash to send - String testExternalId2 = "test_ext_id_2"; - String mockExternalIdHash2 = new String(new char[64]).replace('\0', '1'); - - // 6. Attempt to set same another external user id and auth hash with callback - OneSignal.setExternalUserId(testExternalId2, mockExternalIdHash2, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 7. Make sure lastExternalUserIdResponse is equal to the expected response - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 8. Check that the correct external user id and auth hash values were sent in the two requests - ShadowOneSignalRestClient.Request externalIdRequest1 = ShadowOneSignalRestClient.requests.get(2); - assertEquals(testExternalId1, externalIdRequest1.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash1, externalIdRequest1.payload.getString("external_user_id_auth_hash")); - - ShadowOneSignalRestClient.Request externalIdRequest2 = ShadowOneSignalRestClient.requests.get(3); - assertEquals(testExternalId2, externalIdRequest2.payload.getString("external_user_id")); - assertEquals(mockExternalIdHash2, externalIdRequest2.payload.getString("external_user_id_auth_hash")); - - // 9. Check the external user id and auth hash values in syncValues - TestHelpers.flushBufferedSharedPrefs(); - final SharedPreferences newPrefs = blankActivity.getSharedPreferences(OneSignal.class.getSimpleName(), Context.MODE_PRIVATE); - syncValues = new JSONObject(newPrefs.getString("ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE", null)); - assertEquals(testExternalId2, syncValues.getString("external_user_id")); - assertEquals(mockExternalIdHash2, syncValues.getString("external_user_id_auth_hash")); - } - - @Test - public void sendSameExternalUserId_withCompletionHandler() throws Exception { - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse is equal to the expected response - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Attempt to set same exact external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 5. Make sure lastExternalUserIdResponse is equal to the expected response - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendExternalUserId_withFailure_withCompletionHandler() throws Exception { - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal - OneSignalInit(); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback and force failure on the network requests - ShadowOneSignalRestClient.failAll = true; - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse is equal to the expected response - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : false" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Flip ShadowOneSignalRestClient.failAll flag back to false - ShadowOneSignalRestClient.failAll = false; - - // 5. Attempt a second set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 6. Make sure lastExternalUserIdResponse is equal to the expected response - expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - /** - * This test calls setExternalUserId in the onSuccess callback of setEmail. - * By the time this callback is invoked, setting EUID should update the email player. - */ - @Test - public void shouldSetExternalUserId_inOnSuccessOfEmailUpdate() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - - // 2. Create an EmailUpdateHandler whose onSuccess callback calls setExternalUserId - TestEmailUpdateHandler_onSuccess_callSetExternalUserId testEmailUpdateHandler = new - TestEmailUpdateHandler_onSuccess_callSetExternalUserId(); - - // 3. Attempt to set email using this email update handler - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, testEmailUpdateHandler); - threadAndTaskWait(); - - // 4. Check that the email callback is successful - assertTrue(testEmailUpdateHandler.emailFiredSuccess); - assertNull(testEmailUpdateHandler.emailFiredFailure); - - // 5. Make sure that the external ID request is sent for email - ShadowOneSignalRestClient.Request setExternalIdOnEmailChannel = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, setExternalIdOnEmailChannel.method); - assertEquals("players/" + ShadowOneSignalRestClient.emailUserId, setExternalIdOnEmailChannel.url); - assertEquals(testEmailUpdateHandler.testExternalId, setExternalIdOnEmailChannel.payload.get("external_user_id")); - } - - /** - * This test calls setExternalUserId in the onSuccess callback of setSMSNumber. - * By the time this callback is invoked, setting EUID should update the SMS player. - */ - @Test - public void shouldSetExternalUserId_inOnSuccessOfSMSUpdate() throws Exception { - // 1. Init OneSignal - OneSignalInit(); - - // 2. Create an SMSUpdateHandler whose onSuccess callback calls setExternalUserId - TestSMSUpdateHandler_onSuccess_callSetExternalUserId testSMSUpdateHandler = new - TestSMSUpdateHandler_onSuccess_callSetExternalUserId(); - - // 3. Attempt to set SMS using this SMS update handler - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler); - threadAndTaskWait(); - - // 4. Check that the sms callback is invoked - assertNotNull(testSMSUpdateHandler.smsResult); - - // 5. Make sure that the external ID request is sent for sms - ShadowOneSignalRestClient.Request setExternalIdOnSMSChannel = ShadowOneSignalRestClient.requests.get(3); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, setExternalIdOnSMSChannel.method); - assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, setExternalIdOnSMSChannel.url); - assertEquals(testSMSUpdateHandler.testExternalId, setExternalIdOnSMSChannel.payload.get("external_user_id")); - } - - @Test - public void sendExternalUserId_forPushAndEmail_withFailure_withCompletionHandler() throws Exception { - String testEmail = "test@onesignal.com"; - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal - OneSignalInit(); - OneSignal.setEmail(testEmail); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback and force failure on the network requests - ShadowOneSignalRestClient.failAll = true; - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse has push and email with success : false - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : false" + - " }," + - " \"email\" : {" + - " \"success\" : false" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Flip ShadowOneSignalRestClient.failAll flag back to false - ShadowOneSignalRestClient.failAll = false; - - // 5. Attempt a second set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 6. Make sure lastExternalUserIdResponse has push and email with success : true - expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }," + - " \"email\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendExternalUserId_forPushAndSMS_withFailure_withCompletionHandler() throws Exception { - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback and force failure on the network requests - ShadowOneSignalRestClient.failAll = true; - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse has push and sms with success : false - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : false" + - " }," + - " \"sms\" : {" + - " \"success\" : false" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Flip ShadowOneSignalRestClient.failAll flag back to false - ShadowOneSignalRestClient.failAll = false; - - // 5. Attempt a second set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 6. Make sure lastExternalUserIdResponse has push and sms with success : true - expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }," + - " \"sms\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendExternalUserId_forPushAndEmailAndSMS_withFailure_withCompletionHandler() throws Exception { - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal - OneSignalInit(); - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // 2. Attempt to set external user id with callback and force failure on the network requests - ShadowOneSignalRestClient.failAll = true; - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 3. Make sure lastExternalUserIdResponse has push and sms with success : false - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : false" + - " }," + - " \"email\" : {" + - " \"success\" : false" + - " }," + - " \"sms\" : {" + - " \"success\" : false" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - - // 4. Flip ShadowOneSignalRestClient.failAll flag back to false - ShadowOneSignalRestClient.failAll = false; - - // 5. Attempt a second set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 6. Make sure lastExternalUserIdResponse has push and sms with success : true - expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }," + - " \"email\" : {" + - " \"success\" : true" + - " }," + - " \"sms\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendExternalUserId_forPush_afterLoggingOutEmail_withCompletion() throws Exception { - String testEmail = "test@onesignal.com"; - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal and set email - OneSignalInit(); - OneSignal.setEmail(testEmail); - threadAndTaskWait(); - - // 2. Logout Email - OneSignal.logoutEmail(); - threadAndTaskWait(); - - // 3. Attempt a set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 4. Make sure lastExternalUserIdResponse has push with success : true - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - @Test - public void sendExternalUserId_forPush_afterLoggingOutSMS_withCompletion() throws Exception { - String testExternalId = "test_ext_id"; - - // 1. Init OneSignal and set email - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - // 2. Logout SMS - OneSignal.logoutSMSNumber(); - threadAndTaskWait(); - - // 4. Attempt a set external user id with callback - OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler()); - threadAndTaskWait(); - - // 5. Make sure lastExternalUserIdResponse has push with success : true - JSONObject expectedExternalUserIdResponse = new JSONObject( - "{" + - " \"push\" : {" + - " \"success\" : true" + - " }" + - "}" - ); - assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString()); - } - - // ####### on_session Tests ######## - - @Test - public void shouldSendOnSessionToEmail() throws Exception { - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method); - assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_session", emailPost.url); - } - - @Test - public void shouldSendOnSessionToSMS() throws Exception { - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - restartAppAndElapseTimeToNextSession(time); - OneSignalInit(); - threadAndTaskWait(); - - ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(5); - assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method); - assertEquals("players/" + ShadowOneSignalRestClient.SMS_USER_ID + "/on_session", smsPost.url); - - // Check that the request only has app_id, device_type and device_player_id - assertEquals(3, smsPost.payload.length()); - assertEquals(PUSH_USER_ID, smsPost.payload.get("device_player_id")); - assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.get("device_type")); - assertTrue(smsPost.payload.has("app_id")); - } - - // ####### on_focus Tests ######## - - @Test - public void sendsOnFocus() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - threadAndTaskWait(); - - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertOnFocusAtIndex(2, 60); - assertRestCalls(3); - } - - @Test - public void sendsOnFocusWithExternalId() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - threadAndTaskWait(); - - String testExternalId = "test_ext_id"; - String mockExternalIdHash = new String(new char[64]).replace('\0', '0'); - - OneSignal.setExternalUserId(testExternalId, mockExternalIdHash); - threadAndTaskWait(); - - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertOnFocusAtIndex(3, 60); - assertRestCalls(4); - assertFalse(ShadowOneSignalRestClient.lastPost.has("external_user_id")); - assertFalse(ShadowOneSignalRestClient.lastPost.has("external_user_id_auth_hash")); - } - - @Test - public void sendsOnFocusToEmail() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - OneSignal.setEmail("josh@onesignal.com"); - threadAndTaskWait(); - - blankActivityController.resume(); - threadAndTaskWait(); - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertEquals(6, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request post = ShadowOneSignalRestClient.requests.get(3); - assertFalse(post.url.contains("on_focus")); - - ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(4); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postPush.url); - assertEquals(60, postPush.payload.getInt("active_time")); - - ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(5); - assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_focus", postEmail.url); - assertEquals(60, postEmail.payload.getInt("active_time")); - } - - @Test - public void sendsOnFocusToSMS() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - blankActivityController.resume(); - threadAndTaskWait(); - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertEquals(5, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request post = ShadowOneSignalRestClient.requests.get(2); - assertFalse(post.url.contains("on_focus")); - - ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(3); - assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postPush.url); - assertEquals(60, postPush.payload.getInt("active_time")); - - ShadowOneSignalRestClient.Request postSMSl = ShadowOneSignalRestClient.requests.get(4); - assertEquals("players/" + SMS_USER_ID + "/on_focus", postSMSl.url); - assertEquals(60, postSMSl.payload.getInt("active_time")); - } - - @Test - public void sendsOnFocusToEmailAndSMS() throws Exception { - time.advanceSystemAndElapsedTimeBy(0); - OneSignalInit(); - OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS); - OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER); - threadAndTaskWait(); - - blankActivityController.resume(); - threadAndTaskWait(); - time.advanceSystemAndElapsedTimeBy(60); - pauseActivity(blankActivityController); - assertAndRunSyncService(); - - assertEquals(8, ShadowOneSignalRestClient.networkCallCount); - - ShadowOneSignalRestClient.Request post = ShadowOneSignalRestClient.requests.get(4); - assertFalse(post.url.contains("on_focus")); - - ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(5); - assertEquals("players/" + PUSH_USER_ID + "/on_focus", postPush.url); - assertEquals(60, postPush.payload.getInt("active_time")); - - ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(6); - assertEquals("players/" + EMAIL_USER_ID + "/on_focus", postEmail.url); - assertEquals(60, postEmail.payload.getInt("active_time")); - - ShadowOneSignalRestClient.Request postSMSl = ShadowOneSignalRestClient.requests.get(7); - assertEquals("players/" + SMS_USER_ID + "/on_focus", postSMSl.url); - assertEquals(60, postSMSl.payload.getInt("active_time")); - } - - private void OneSignalInit() { - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - ShadowOSUtils.subscribableStatus = 1; - OneSignal_setTime(time); - OneSignal_setTrackerFactory(trackerFactory); - OneSignal_setSessionManager(sessionManager); - OneSignal.setAppId(ONESIGNAL_APP_ID); - OneSignal.initWithContext(blankActivity); - blankActivityController.resume(); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TestHelpers.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TestHelpers.java deleted file mode 100644 index ab563a3b0..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TestHelpers.java +++ /dev/null @@ -1,615 +0,0 @@ -package com.test.onesignal; - -import android.app.AlarmManager; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.app.job.JobService; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.os.Looper; -import android.os.SystemClock; -import android.util.Log; - -import androidx.annotation.Nullable; -import androidx.test.core.app.ApplicationProvider; -import androidx.work.Configuration; -import androidx.work.testing.SynchronousExecutor; -import androidx.work.testing.WorkManagerTestInitHelper; - -import com.onesignal.MockOSTimeImpl; -import com.onesignal.OneSignalDb; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.OneSignalPackagePrivateHelper.OSTestInAppMessageInternal; -import com.onesignal.OneSignalPackagePrivateHelper.TestOneSignalPrefs; -import com.onesignal.OneSignalShadowPackageManager; -import com.onesignal.OSOutcomeEvent; -import com.onesignal.ShadowBadgeCountUpdater; -import com.onesignal.ShadowCustomTabsClient; -import com.onesignal.ShadowDynamicTimer; -import com.onesignal.ShadowFCMBroadcastReceiver; -import com.onesignal.ShadowFirebaseAnalytics; -import com.onesignal.ShadowFocusHandler; -import com.onesignal.ShadowFusedLocationApiWrapper; -import com.onesignal.ShadowGenerateNotification; -import com.onesignal.ShadowGoogleApiClientCompatProxy; -import com.onesignal.ShadowHMSFusedLocationProviderClient; -import com.onesignal.ShadowHmsInstanceId; -import com.onesignal.ShadowHmsNotificationPayloadProcessor; -import com.onesignal.ShadowNotificationManagerCompat; -import com.onesignal.ShadowNotificationReceivedEvent; -import com.onesignal.ShadowOSUtils; -import com.onesignal.ShadowOSWebView; -import com.onesignal.ShadowOneSignalDbHelper; -import com.onesignal.ShadowOneSignalNotificationManager; -import com.onesignal.ShadowOneSignalRestClient; -import com.onesignal.ShadowOneSignalRestClientWithMockConnection; -import com.onesignal.ShadowPushRegistratorADM; -import com.onesignal.ShadowPushRegistratorFCM; -import com.onesignal.ShadowPushRegistratorHMS; -import com.onesignal.ShadowTimeoutHandler; -import com.onesignal.StaticResetHelper; -import com.onesignal.SyncJobService; -import com.onesignal.influence.domain.OSInfluenceType; -import com.onesignal.outcomes.data.MockOSCachedUniqueOutcomeTable; -import com.onesignal.outcomes.data.MockOSOutcomeEventsTable; -import com.onesignal.outcomes.OSOutcomeEventDB; -import com.onesignal.outcomes.domain.OSCachedUniqueOutcomeName; - -import junit.framework.Assert; - -import org.json.JSONArray; -import org.json.JSONException; -import org.robolectric.Robolectric; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.shadows.ShadowAlarmManager; -import org.robolectric.util.Scheduler; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_OSTaskController_ShutdownNow; -import static junit.framework.Assert.assertEquals; -import static org.robolectric.Shadows.shadowOf; - -public class TestHelpers { - - private static final String TAG = TestHelpers.class.getCanonicalName(); - private static final long SIX_MONTHS_TIME_SECONDS = 6 * 30 * 24 * 60 * 60; - - static Exception lastException; - - static void beforeTestInitAndCleanup() throws Exception { - TestOneSignalPrefs.initializePool(); - if (!ranBeforeTestSuite) - return; - - setupTestWorkManager(ApplicationProvider.getApplicationContext()); - - resetAlarmManager(); - - resetSystemClock(); - - stopAllOSThreads(); - - StaticResetHelper.restSetStaticFields(); - - ShadowOneSignalRestClient.resetStatics(); - - ShadowPushRegistratorFCM.resetStatics(); - ShadowPushRegistratorADM.resetStatics(); - ShadowHmsInstanceId.resetStatics(); - ShadowPushRegistratorHMS.resetStatics(); - - ShadowNotificationManagerCompat.enabled = true; - - ShadowCustomTabsClient.resetStatics(); - ShadowFCMBroadcastReceiver.resetStatics(); - - ShadowFusedLocationApiWrapper.resetStatics(); - ShadowHMSFusedLocationProviderClient.resetStatics(); - - ShadowFirebaseAnalytics.resetStatics(); - - ShadowGoogleApiClientCompatProxy.restSetStaticFields(); - ShadowOneSignalDbHelper.restSetStaticFields(); - ShadowOneSignalRestClientWithMockConnection.resetStatics(); - - ShadowOSWebView.resetStatics(); - - ShadowDynamicTimer.resetStatics(); - - OneSignalShadowPackageManager.resetStatics(); - - ShadowOSUtils.resetStatics(); - ShadowTimeoutHandler.resetStatics(); - ShadowGenerateNotification.resetStatics(); - ShadowNotificationReceivedEvent.resetStatics(); - ShadowOneSignalNotificationManager.resetStatics(); - ShadowBadgeCountUpdater.resetStatics(); - ShadowHmsNotificationPayloadProcessor.resetStatics(); - ShadowFocusHandler.Companion.resetStatics(); - - lastException = null; - } - - public static void afterTestCleanup() throws Exception { - try { - OneSignal_OSTaskController_ShutdownNow(); - stopAllOSThreads(); - } catch (Exception e) { - e.printStackTrace(); - } - - stopJobs(); - - if (lastException != null) - throw lastException; - } - - static void stopAllOSThreads() { - boolean joinedAThread; - do { - joinedAThread = false; - Set threadSet = Thread.getAllStackTraces().keySet(); - - for (Thread thread : threadSet) { - if (thread.getName().startsWith("OS_")) { - thread.interrupt(); - joinedAThread = true; - } - } - } while (joinedAThread); - } - - static void flushBufferedSharedPrefs() { - TestOneSignalPrefs.WritePrefHandlerThread handlerThread = TestOneSignalPrefs.prefsHandler; - - if (handlerThread.getLooper() == null) - return; - Scheduler scheduler = shadowOf(handlerThread.getLooper()).getScheduler(); - while (scheduler.runOneTask()); - } - - // Join all OS_ threads - // Returns true if we had to join any threads - static boolean runOSThreads() throws Exception { - boolean createdNewThread = false; - boolean joinedAThread; - do { - joinedAThread = false; - Set threadSet = Thread.getAllStackTraces().keySet(); - - for (Thread thread : threadSet) { - if (!thread.getName().startsWith("OS_")) - continue; - if (ShadowOneSignalRestClient.isAFrozenThread(thread)) - continue; - - thread.join(0, 1); - - if (lastException != null) - throw lastException; - joinedAThread = createdNewThread = true; - } - } while (joinedAThread); - - return createdNewThread; - } - - static Thread getThreadByName(String threadName) { - for (Thread t : Thread.getAllStackTraces().keySet()) { - if (t.getName().equals(threadName)) - return t; - } - return null; - } - - // Run any OneSignal background threads including any pending runnables - public static void threadAndTaskWait() throws Exception { - shadowOf(RuntimeEnvironment.application).getForegroundThreadScheduler().runOneTask(); - // Runs Runnables posted by calling View.post() which are run on the main thread. - Robolectric.getForegroundThreadScheduler().runOneTask(); - - boolean createdNewThread; - do { - // We run a 2nd time if we did not find any threads to ensure we don't skip any - createdNewThread = runOSThreads() || runOSThreads(); - - boolean advancedRunnables = OneSignalPackagePrivateHelper.runAllNetworkRunnables(); - - if (advancedRunnables) - createdNewThread = true; - } while (createdNewThread); - - if (lastException != null) - throw lastException; - } - - private static boolean ranBeforeTestSuite; - public static void beforeTestSuite() throws Exception { - if (ranBeforeTestSuite) - return; - - StaticResetHelper.load(); - - beforeTestInitAndCleanup(); - - System.out.println("beforeTestSuite!!!!!!"); - - // Setup process global exception handler to catch any silent exceptions on background threads - Thread.setDefaultUncaughtExceptionHandler( - new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - lastException = new Exception(e); - } - } - ); - ranBeforeTestSuite = true; - } - - static void fastColdRestartApp() throws Exception { - stopAllOSThreads(); - flushBufferedSharedPrefs(); - StaticResetHelper.restSetStaticFields(); - Log.d(TAG, "************ FAST COLD RESTART FINISHED! ************"); - } - - static void restartAppAndElapseTimeToNextSession(MockOSTimeImpl time) throws Exception { - stopAllOSThreads(); - flushBufferedSharedPrefs(); - StaticResetHelper.restSetStaticFields(); - time.advanceSystemAndElapsedTimeBy(31); - Log.d(TAG, "************ restartAppAndElapseTimeToNextSession finished ************"); - } - - static ArrayList> getAllNotificationRecords(OneSignalDb db) { - Cursor cursor = db.query( - OneSignalPackagePrivateHelper.NotificationTable.TABLE_NAME, - null, - null, - null, - null, // group by - null, // filter by row groups - null, // sort order, new to old - null // limit - ); - - ArrayList> mapList = new ArrayList<>(); - while (cursor.moveToNext()) { - HashMap map = new HashMap<>(); - for(int i = 0; i < cursor.getColumnCount(); i++) { - int type = cursor.getType(i); - String key = cursor.getColumnName(i); - - if (type == Cursor.FIELD_TYPE_INTEGER) - map.put(key, cursor.getLong(i)); - else if (type == Cursor.FIELD_TYPE_FLOAT) - map.put(key, cursor.getFloat(i)); - else - map.put(key, cursor.getString(i)); - } - mapList.add(map); - } - - cursor.close(); - - return mapList; - } - - static List getAllOutcomesRecordsDBv5(OneSignalDb db) { ; - Cursor cursor = db.query( - MockOSOutcomeEventsTable.TABLE_NAME, - null, - null, - null, - null, // group by - null, // filter by row groups - null, // sort order, new to old - null // limit - ); - - List events = new ArrayList<>(); - if (cursor.moveToFirst()) { - do { - String notificationIds = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS)); - String name = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_NAME)); - String sessionString = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_SESSION)); - OSInfluenceType session = OSInfluenceType.fromString(sessionString); - long timestamp = cursor.getLong(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_TIMESTAMP)); - float weight = cursor.getFloat(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_WEIGHT)); - - try { - OSOutcomeEvent event = new OSOutcomeEvent(session, new JSONArray(notificationIds), name, timestamp, weight); - events.add(event); - - } catch (JSONException e) { - e.printStackTrace(); - } - } while (cursor.moveToNext()); - } - - cursor.close(); - - return events; - } - - static List getAllOutcomesRecords(OneSignalDb db) { - Cursor cursor = db.query( - MockOSOutcomeEventsTable.TABLE_NAME, - null, - null, - null, - null, // group by - null, // filter by row groups - null, // sort order, new to old - null // limit - ); - - List events = new ArrayList<>(); - if (cursor.moveToFirst()) { - do { - String name = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_NAME)); - String iamIds = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_IAM_IDS)); - String iamInfluenceTypeString = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE)); - String notificationIds = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS)); - String notificationInfluenceTypeString = cursor.getString(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE)); - OSInfluenceType iamInfluenceType = OSInfluenceType.fromString(iamInfluenceTypeString); - OSInfluenceType notificationInfluenceType = OSInfluenceType.fromString(notificationInfluenceTypeString); - - long timestamp = cursor.getLong(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_TIMESTAMP)); - float weight = cursor.getFloat(cursor.getColumnIndex(MockOSOutcomeEventsTable.COLUMN_NAME_WEIGHT)); - - try { - OSOutcomeEventDB event = new OSOutcomeEventDB(iamInfluenceType, notificationInfluenceType, - new JSONArray(iamIds != null ? iamIds : "[]"), new JSONArray(notificationIds != null ? notificationIds : "[]"), - name, timestamp, weight); - events.add(event); - - } catch (JSONException e) { - e.printStackTrace(); - } - } while (cursor.moveToNext()); - } - - cursor.close(); - - return events; - } - - static ArrayList getAllUniqueOutcomeNotificationRecordsDBv5(OneSignalDb db) { - Cursor cursor = db.query( - MockOSCachedUniqueOutcomeTable.TABLE_NAME_V1, - null, - null, - null, - null, // group by - null, // filter by row groups - null, // sort order, new to old - null // limit - ); - - ArrayList cachedUniqueOutcomes = new ArrayList<>(); - if (cursor.moveToFirst()) { - do { - String name = cursor.getString(cursor.getColumnIndex(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME)); - String influenceId = cursor.getString(cursor.getColumnIndex(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID)); - - OSCachedUniqueOutcomeName uniqueOutcome = new OSCachedUniqueOutcomeName(name, influenceId); - cachedUniqueOutcomes.add(uniqueOutcome); - - } while (cursor.moveToNext()); - } - - cursor.close(); - - return cachedUniqueOutcomes; - } - - static ArrayList getAllUniqueOutcomeNotificationRecordsDB(OneSignalDb db) { - Cursor cursor = db.query( - MockOSCachedUniqueOutcomeTable.TABLE_NAME_V2, - null, - null, - null, - null, // group by - null, // filter by row groups - null, // sort order, new to old - null // limit - ); - - ArrayList cachedUniqueOutcomes = new ArrayList<>(); - if (cursor.moveToFirst()) { - do { - String name = cursor.getString(cursor.getColumnIndex(MockOSCachedUniqueOutcomeTable.COLUMN_NAME_NAME)); - String influenceId = cursor.getString(cursor.getColumnIndex(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID)); - String channelType = cursor.getString(cursor.getColumnIndex(MockOSCachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE)); - - OSCachedUniqueOutcomeName uniqueOutcome = new OSCachedUniqueOutcomeName(name, influenceId, channelType); - cachedUniqueOutcomes.add(uniqueOutcome); - - } while (cursor.moveToNext()); - } - - cursor.close(); - - return cachedUniqueOutcomes; - } - - synchronized static void saveIAM(OSTestInAppMessageInternal inAppMessage, OneSignalDb db) { - ContentValues values = new ContentValues(); - values.put(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_NAME_MESSAGE_ID, inAppMessage.getMessageId()); - values.put(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY, inAppMessage.getRedisplayStats().getDisplayQuantity()); - values.put(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY, inAppMessage.getRedisplayStats().getLastDisplayTime()); - values.put(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_CLICK_IDS, inAppMessage.getClickedClickIds().toString()); - values.put(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION, inAppMessage.isDisplayedInSession()); - - db.insert(OneSignalPackagePrivateHelper.InAppMessageTable.TABLE_NAME, null, values); - } - - synchronized static List getAllInAppMessages(OneSignalDb db) throws JSONException { - Cursor cursor = db.query( - OneSignalPackagePrivateHelper.InAppMessageTable.TABLE_NAME, - null, - null, - null, - null, - null, - null - ); - - List iams = new ArrayList<>(); - if (cursor.moveToFirst()) - do { - String messageId = cursor.getString(cursor.getColumnIndex(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_NAME_MESSAGE_ID)); - String clickIds = cursor.getString(cursor.getColumnIndex(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_CLICK_IDS)); - int displayQuantity = cursor.getInt(cursor.getColumnIndex(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY)); - long lastDisplay = cursor.getLong(cursor.getColumnIndex(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY)); - boolean displayed = cursor.getInt(cursor.getColumnIndex(OneSignalPackagePrivateHelper.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION)) == 1; - - JSONArray clickIdsArray = new JSONArray(clickIds); - Set clickIdsSet = new HashSet<>(); - - for (int i = 0; i < clickIdsArray.length(); i++) { - clickIdsSet.add(clickIdsArray.getString(i)); - } - - OSTestInAppMessageInternal inAppMessage = new OSTestInAppMessageInternal(messageId, displayQuantity, lastDisplay, displayed, clickIdsSet); - iams.add(inAppMessage); - } while (cursor.moveToNext()); - - cursor.close(); - - return iams; - } - - static void setupTestWorkManager(Context context) { - final Configuration config = new Configuration.Builder() - .setMinimumLoggingLevel(Log.DEBUG) - .setExecutor(new SynchronousExecutor()) - .build(); - WorkManagerTestInitHelper.initializeTestWorkManager(context, config); - } - - private static void resetAlarmManager() { - AlarmManager alarmManager = (AlarmManager) ApplicationProvider.getApplicationContext() - .getSystemService(Context.ALARM_SERVICE); - ShadowAlarmManager shadowAlarmManager = shadowOf(alarmManager); - shadowAlarmManager.getScheduledAlarms().clear(); - } - - static void resetSystemClock() { - SystemClock.setCurrentTimeMillis(System.currentTimeMillis()); - } - - public static void assertMainThread() { - if (!Looper.getMainLooper().getThread().equals(Thread.currentThread())) - Assert.fail("assertMainThread - Not running on main thread when expected to!"); - } - - static void stopJobs() throws Exception { - JobScheduler jobScheduler = - (JobScheduler) ApplicationProvider.getApplicationContext().getSystemService(Context.JOB_SCHEDULER_SERVICE); - if (jobScheduler != null) { - List jobs = jobScheduler.getAllPendingJobs(); - for (JobInfo jobInfo : jobs) { - stopJob(jobInfo); - threadAndTaskWait(); - } - } - } - public static @Nullable JobInfo getNextJob() { - return getJob(0); - } - - private static @Nullable JobInfo getJob(int index) { - JobScheduler jobScheduler = - (JobScheduler)ApplicationProvider.getApplicationContext().getSystemService(Context.JOB_SCHEDULER_SERVICE); - List jobs = jobScheduler.getAllPendingJobs(); - if (jobs.size() == 0 || jobs.size() <= index) - return null; - else - return jobs.get(index); - } - - public static void runNextJob() { - try { - Class jobClass = Class.forName(getNextJob().getService().getClassName()); - runJob(jobClass); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } - - public static void runJob(Class jobClass) { - JobService jobService = (JobService) Robolectric.buildService(jobClass).create().get(); - jobService.onStartJob(null); - } - - public static void stopJob(JobInfo jobInfo) { - try { - Class jobClass = Class.forName(jobInfo.getService().getClassName()); - JobService jobService = (JobService) Robolectric.buildService(jobClass).create().get(); - jobService.jobFinished(null, false); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } - - public static void assertNumberOfServicesAvailable(int quantity) { - JobScheduler jobScheduler = - (JobScheduler)ApplicationProvider.getApplicationContext().getSystemService(Context.JOB_SCHEDULER_SERVICE); - List jobs = jobScheduler.getAllPendingJobs(); - assertEquals(quantity, jobs.size()); - } - - public static void assertAndRunNextJob(Class jobClass) { - assertNumberOfServicesAvailable(1); - assertNextJob(jobClass); - runNextJob(); - } - - public static void assertAndRunJobAtIndex(Class jobClass, int index) { - assertNextJob(jobClass, index); - runJob(jobClass); - } - - public static void assertNextJob(Class jobClass) { - assertNextJob(jobClass, 0); - } - - public static void assertNextJob(Class jobClass, int index) { - assertEquals(jobClass.getName(), getJob(index).getService().getClassName()); - } - - public static void pauseActivity(ActivityController activityController) throws Exception { - activityController.pause(); - threadAndTaskWait(); - } - - public static void stopActivity(ActivityController activityController) throws Exception { - activityController.stop(); - threadAndTaskWait(); - } - - public static void assertAndRunSyncService() throws Exception { - // There should be a SyncJobService service scheduled - assertNumberOfServicesAvailable(1); - // A sync job should have been schedule, lets run it to ensure on_focus is called. - TestHelpers.assertAndRunJobAtIndex(SyncJobService.class, 0); - threadAndTaskWait(); - } - - /** - * Add the correct manifest meta-data key and value regarding the NotificationServiceExtension to the - * mocked OneSignalShadowPackageManager metaData Bundle - */ - public static void startRemoteNotificationReceivedHandlerService(String servicePath) { - OneSignalShadowPackageManager.addManifestMetaData("com.onesignal.NotificationServiceExtension", servicePath); - } -} diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TrackerUnitTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TrackerUnitTests.java deleted file mode 100644 index 9a798c328..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TrackerUnitTests.java +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Modified MIT License - *

- * Copyright 2018 OneSignal - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * 1. The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.test.onesignal; - -import com.onesignal.MockOSLog; -import com.onesignal.MockOSSharedPreferences; -import com.onesignal.MockOSTimeImpl; -import com.onesignal.OneSignal; -import com.onesignal.OneSignalPackagePrivateHelper; -import com.onesignal.StaticResetHelper; -import com.onesignal.influence.data.OSTrackerFactory; -import com.onesignal.influence.domain.OSInfluence; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; - -import java.util.List; - -import static com.test.onesignal.TestHelpers.threadAndTaskWait; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -@Config(packageName = "com.onesignal.example", - sdk = 21) -@RunWith(RobolectricTestRunner.class) -public class TrackerUnitTests { - - private static final String NOTIFICATION_ID = "notification_id"; - private static final String IAM_ID = "iam_id"; - - private OSTrackerFactory trackerFactory; - - @BeforeClass // Runs only once, before any tests - public static void setUpClass() throws Exception { - ShadowLog.stream = System.out; - - OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - } - - @Before // Before each test - public void beforeEachTest() throws Exception { - MockOSLog logger = new MockOSLog(); - MockOSTimeImpl time = new MockOSTimeImpl(); - MockOSSharedPreferences preferences = new MockOSSharedPreferences(); - trackerFactory = new OSTrackerFactory(preferences, logger, time); - } - - @Test - public void testUnattributedInitInfluence() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - trackerFactory.initFromCache(); - List influences = trackerFactory.getInfluences(); - for (OSInfluence influence : influences) { - assertTrue(influence.getInfluenceType().isUnattributed()); - assertNull(influence.getIds()); - } - } - - @Test - public void testInfluenceIdsSaved() throws Exception { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - - assertEquals(0, trackerFactory.getNotificationChannelTracker().getLastReceivedIds().length()); - assertEquals(0, trackerFactory.getIAMChannelTracker().getLastReceivedIds().length()); - - trackerFactory.getNotificationChannelTracker().saveLastId(NOTIFICATION_ID); - trackerFactory.getIAMChannelTracker().saveLastId(IAM_ID); - - JSONArray lastNotificationIds = trackerFactory.getNotificationChannelTracker().getLastReceivedIds(); - JSONArray lastIAMIds = trackerFactory.getIAMChannelTracker().getLastReceivedIds(); - - assertEquals(1, lastNotificationIds.length()); - assertEquals(NOTIFICATION_ID, lastNotificationIds.get(0)); - assertEquals(1, lastIAMIds.length()); - assertEquals(IAM_ID, lastIAMIds.get(0)); - } - - @Test - public void testDisabledInitInfluence() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false)); - trackerFactory.initFromCache(); - List influences = trackerFactory.getInfluences(); - for (OSInfluence influence : influences) { - assertTrue(influence.getInfluenceType().isDisabled()); - assertNull(influence.getIds()); - } - } - - @Test - public void testUnattributedAddSessionData() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams()); - trackerFactory.initFromCache(); - - JSONObject object = new JSONObject(); - trackerFactory.addSessionData(object, trackerFactory.getInfluences()); - - assertEquals(0, object.length()); - } - - @Test - public void testDisabledAddSessionData() { - trackerFactory.saveInfluenceParams(new OneSignalPackagePrivateHelper.RemoteOutcomeParams(false, false, false)); - trackerFactory.initFromCache(); - - JSONObject object = new JSONObject(); - trackerFactory.addSessionData(object, trackerFactory.getInfluences()); - - assertEquals(0, object.length()); - } - - @Test - public void testGetChannelsByEntryPoint() { - assertNull(trackerFactory.getChannelByEntryAction(OneSignal.AppEntryAction.APP_OPEN)); - assertNull(trackerFactory.getChannelByEntryAction(OneSignal.AppEntryAction.APP_CLOSE)); - assertEquals(NOTIFICATION_ID, trackerFactory.getChannelByEntryAction(OneSignal.AppEntryAction.NOTIFICATION_CLICK).getIdTag()); - } - - @Test - public void testGetChannelToResetByEntryAction() { - assertEquals(2, trackerFactory.getChannelsToResetByEntryAction(OneSignal.AppEntryAction.APP_OPEN).size()); - assertEquals(0, trackerFactory.getChannelsToResetByEntryAction(OneSignal.AppEntryAction.APP_CLOSE).size()); - assertEquals(1, trackerFactory.getChannelsToResetByEntryAction(OneSignal.AppEntryAction.NOTIFICATION_CLICK).size()); - assertEquals(IAM_ID, trackerFactory.getChannelsToResetByEntryAction(OneSignal.AppEntryAction.NOTIFICATION_CLICK).get(0).getIdTag()); - } - -} \ No newline at end of file diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TypeAsserts.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TypeAsserts.java deleted file mode 100644 index 7ca480ed0..000000000 --- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/TypeAsserts.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.test.onesignal; - -import androidx.annotation.Nullable; - -import java.util.UUID; - -class TypeAsserts { - - static void assertIsUUID(@Nullable String value) { - UUID.fromString(value); - } - -}