From 49ad09573a0c0e8e9368a5f58075b6a88a8379d6 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 14 Feb 2024 17:34:08 -0500 Subject: [PATCH 01/17] bump anrdoid compile and target to version 34 This fixes an error compile tests for in-app messages. androidx.work:work-runtime-ktx:2.8.1 was interduced and it requires android compile SDK version 33. --- OneSignalSDK/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OneSignalSDK/build.gradle b/OneSignalSDK/build.gradle index 878c7ec981..c2609ddcfb 100644 --- a/OneSignalSDK/build.gradle +++ b/OneSignalSDK/build.gradle @@ -4,8 +4,8 @@ buildscript { ext { buildVersions = [ - compileSdkVersion: 31, - targetSdkVersion: 31, + compileSdkVersion: 34, + targetSdkVersion: 34, minSdkVersion: 19 ] androidGradlePluginVersion = '7.2.0' From e5bcef7e8169ba26e2b3e193aa075efc03e5344f Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 15 Feb 2024 15:58:21 -0500 Subject: [PATCH 02/17] replace ShadowFusedLocationProviderApi Replaced ShadowFusedLocationProviderApi with FusedLocationApiWrapperMock as it depended on Field::class.java.getDeclaredField("modifiers") which was a reflection feature dropped in somewhere between Java 11 -> 17. Since there wasn't a straightforward way to keep this as a shadow it was worth the time instead to use dependency inject. --- .../com/onesignal/location/LocationModule.kt | 8 +- .../impl/FusedLocationApiWrapperImpl.kt | 46 +++++ .../controller/impl/GmsLocationController.kt | 52 +----- .../impl/IFusedLocationApiWrapper.kt | 21 +++ .../controller/GmsLocationControllerTests.kt | 18 +- .../mocks/FusedLocationApiWrapperMock.kt | 32 ++++ .../shadows/ShadowFusedLocationProviderApi.kt | 161 ------------------ 7 files changed, 123 insertions(+), 215 deletions(-) create mode 100644 OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/FusedLocationApiWrapperImpl.kt create mode 100644 OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/IFusedLocationApiWrapper.kt create mode 100644 OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/FusedLocationApiWrapperMock.kt delete mode 100644 OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt index 6a4a3bdcd4..3cb897e14e 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt @@ -12,8 +12,10 @@ import com.onesignal.location.internal.capture.ILocationCapturer import com.onesignal.location.internal.capture.impl.LocationCapturer import com.onesignal.location.internal.common.LocationUtils import com.onesignal.location.internal.controller.ILocationController +import com.onesignal.location.internal.controller.impl.FusedLocationApiWrapperImpl import com.onesignal.location.internal.controller.impl.GmsLocationController import com.onesignal.location.internal.controller.impl.HmsLocationController +import com.onesignal.location.internal.controller.impl.IFusedLocationApiWrapper import com.onesignal.location.internal.controller.impl.NullLocationController import com.onesignal.location.internal.permissions.LocationPermissionController import com.onesignal.location.internal.preferences.ILocationPreferencesService @@ -25,11 +27,15 @@ internal class LocationModule : IModule { .provides() .provides() + builder.register().provides() builder.register { val deviceService = it.getService(IDeviceService::class.java) val service = if (deviceService.isAndroidDeviceType && LocationUtils.hasGMSLocationLibrary()) { - GmsLocationController(it.getService(IApplicationService::class.java)) + GmsLocationController( + it.getService(IApplicationService::class.java), + it.getService(IFusedLocationApiWrapper::class.java), + ) } else if (deviceService.isHuaweiDeviceType && LocationUtils.hasHMSLocationLibrary()) { HmsLocationController(it.getService(IApplicationService::class.java)) } else { diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/FusedLocationApiWrapperImpl.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/FusedLocationApiWrapperImpl.kt new file mode 100644 index 0000000000..b35cbfcb4c --- /dev/null +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/FusedLocationApiWrapperImpl.kt @@ -0,0 +1,46 @@ +package com.onesignal.location.internal.controller.impl + +import android.location.Location +import android.os.Looper +import com.google.android.gms.common.api.GoogleApiClient +import com.google.android.gms.location.LocationListener +import com.google.android.gms.location.LocationRequest +import com.google.android.gms.location.LocationServices +import com.onesignal.debug.internal.logging.Logging + +internal class FusedLocationApiWrapperImpl : IFusedLocationApiWrapper { + override fun cancelLocationUpdates( + googleApiClient: GoogleApiClient, + locationListener: LocationListener, + ) { + if (googleApiClient.isConnected) { + LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, locationListener) + } else { + Logging.warn("GoogleApiClient is not connected. Unable to cancel location updates.") + } + } + + override fun requestLocationUpdates( + googleApiClient: GoogleApiClient, + locationRequest: LocationRequest, + locationListener: LocationListener, + ) { + try { + if (Looper.myLooper() == null) { + Looper.prepare() + } + if (googleApiClient.isConnected) { + LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationListener) + } + } catch (t: Throwable) { + Logging.warn("FusedLocationApi.requestLocationUpdates failed!", t) + } + } + + override fun getLastLocation(googleApiClient: GoogleApiClient): Location? { + if (googleApiClient.isConnected) { + return LocationServices.FusedLocationApi.getLastLocation(googleApiClient) + } + return null + } +} diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt index e40923a88a..1c489f1670 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt @@ -4,7 +4,6 @@ import android.location.Location import android.os.Bundle import android.os.Handler import android.os.HandlerThread -import android.os.Looper import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.api.GoogleApiClient import com.google.android.gms.location.LocationListener @@ -29,6 +28,7 @@ import java.io.Closeable internal class GmsLocationController( private val _applicationService: IApplicationService, + private val _fusedLocationApiWrapper: IFusedLocationApiWrapper, ) : ILocationController { private val locationHandlerThread = LocationHandlerThread() private val startStopMutex = Mutex() @@ -75,14 +75,14 @@ internal class GmsLocationController( if (result?.isSuccess == true) { if (lastLocation == null) { - var lastLocation = FusedLocationApiWrapper.getLastLocation(googleApiClient) + var lastLocation = _fusedLocationApiWrapper.getLastLocation(googleApiClient) if (lastLocation != null) { setLocationAndFire(lastLocation) } } // only after the connect do we save - self.locationUpdateListener = LocationUpdateListener(_applicationService, self, proxyGoogleApiClient.realInstance) + self.locationUpdateListener = LocationUpdateListener(_applicationService, self, proxyGoogleApiClient.realInstance, _fusedLocationApiWrapper) self.googleApiClient = proxyGoogleApiClient wasSuccessful = true } else { @@ -121,7 +121,7 @@ internal class GmsLocationController( override fun getLastLocation(): Location? { val apiInstance = googleApiClient?.realInstance ?: return null - return FusedLocationApiWrapper.getLastLocation(apiInstance) + return _fusedLocationApiWrapper.getLastLocation(apiInstance) } override fun subscribe(handler: ILocationUpdatedHandler) = event.subscribe(handler) @@ -162,6 +162,7 @@ internal class GmsLocationController( private val _applicationService: IApplicationService, private val _parent: GmsLocationController, private val googleApiClient: GoogleApiClient, + private val _fusedLocationApiWrapper: IFusedLocationApiWrapper, ) : LocationListener, IApplicationLifecycleHandler, Closeable { private var hasExistingRequest = false @@ -188,7 +189,7 @@ internal class GmsLocationController( _applicationService.removeApplicationLifecycleHandler(this) if (hasExistingRequest) { - FusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this) + _fusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this) } } @@ -199,7 +200,7 @@ internal class GmsLocationController( } if (hasExistingRequest) { - FusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this) + _fusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this) } val updateInterval = @@ -216,7 +217,7 @@ internal class GmsLocationController( .setMaxWaitTime((updateInterval * 1.5).toLong()) .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) Logging.debug("GMSLocationController GoogleApiClient requestLocationUpdates!") - FusedLocationApiWrapper.requestLocationUpdates(googleApiClient, locationRequest, this) + _fusedLocationApiWrapper.requestLocationUpdates(googleApiClient, locationRequest, this) hasExistingRequest = true } @@ -226,43 +227,6 @@ internal class GmsLocationController( } } - internal object FusedLocationApiWrapper { - fun cancelLocationUpdates( - googleApiClient: GoogleApiClient, - locationListener: LocationListener, - ) { - if (googleApiClient.isConnected) { - LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, locationListener) - } else { - Logging.warn("GoogleApiClient is not connected. Unable to cancel location updates.") - } - } - - fun requestLocationUpdates( - googleApiClient: GoogleApiClient, - locationRequest: LocationRequest, - locationListener: LocationListener, - ) { - try { - if (Looper.myLooper() == null) { - Looper.prepare() - } - if (googleApiClient.isConnected) { - LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationListener) - } - } catch (t: Throwable) { - Logging.warn("FusedLocationApi.requestLocationUpdates failed!", t) - } - } - - fun getLastLocation(googleApiClient: GoogleApiClient): Location? { - if (googleApiClient.isConnected) { - return LocationServices.FusedLocationApi.getLastLocation(googleApiClient) - } - return null - } - } - protected class LocationHandlerThread internal constructor() : HandlerThread("OSH_LocationHandlerThread") { var mHandler: Handler diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/IFusedLocationApiWrapper.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/IFusedLocationApiWrapper.kt new file mode 100644 index 0000000000..1854bac323 --- /dev/null +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/IFusedLocationApiWrapper.kt @@ -0,0 +1,21 @@ +package com.onesignal.location.internal.controller.impl + +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 + +internal interface IFusedLocationApiWrapper { + fun cancelLocationUpdates( + googleApiClient: GoogleApiClient, + locationListener: LocationListener, + ) + + fun requestLocationUpdates( + googleApiClient: GoogleApiClient, + locationRequest: LocationRequest, + locationListener: LocationListener, + ) + + fun getLastLocation(googleApiClient: GoogleApiClient): Location? +} diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt index 39cccfe6e8..a4ced5d54f 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt @@ -4,7 +4,7 @@ import android.location.Location import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging import com.onesignal.location.internal.controller.impl.GmsLocationController -import com.onesignal.location.shadows.ShadowFusedLocationProviderApi +import com.onesignal.location.mocks.FusedLocationApiWrapperMock import com.onesignal.location.shadows.ShadowGoogleApiClient import com.onesignal.location.shadows.ShadowGoogleApiClientBuilder import com.onesignal.mocks.AndroidMockHelper @@ -37,11 +37,11 @@ class GmsLocationControllerTests : FunSpec({ val location = Location("TEST_PROVIDER") location.latitude = 123.45 location.longitude = 678.91 + val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location)) - ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location)) val applicationService = AndroidMockHelper.applicationService() every { applicationService.isInForeground } returns true - val gmsLocationController = GmsLocationController(applicationService) + val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock) val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) @@ -71,11 +71,11 @@ class GmsLocationControllerTests : FunSpec({ val location2 = Location("TEST_PROVIDER") location2.latitude = 678.91 location2.longitude = 123.45 + val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location1, location2)) - ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location1, location2)) val applicationService = AndroidMockHelper.applicationService() every { applicationService.isInForeground } returns true - val gmsLocationController = GmsLocationController(applicationService) + val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock) val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) @@ -114,10 +114,10 @@ class GmsLocationControllerTests : FunSpec({ location2.latitude = 678.91 location2.longitude = 123.45 - ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location1, location2)) + val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location1, location2)) val applicationService = AndroidMockHelper.applicationService() every { applicationService.isInForeground } returns true - val gmsLocationController = GmsLocationController(applicationService) + val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock) val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) @@ -152,10 +152,10 @@ class GmsLocationControllerTests : FunSpec({ location2.latitude = 678.91 location2.longitude = 123.45 - ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location1, location2)) + val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location1, location2)) val applicationService = AndroidMockHelper.applicationService() every { applicationService.isInForeground } returns true - val gmsLocationController = GmsLocationController(applicationService) + val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock) val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/FusedLocationApiWrapperMock.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/FusedLocationApiWrapperMock.kt new file mode 100644 index 0000000000..89961b7a65 --- /dev/null +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/FusedLocationApiWrapperMock.kt @@ -0,0 +1,32 @@ +package com.onesignal.location.mocks + +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 com.onesignal.location.internal.controller.impl.IFusedLocationApiWrapper +import java.util.LinkedList +import java.util.Queue + +internal class FusedLocationApiWrapperMock(locationsList: List) : IFusedLocationApiWrapper { + private val locations: Queue + + init { + this.locations = LinkedList(locationsList) + } + + override fun cancelLocationUpdates( + googleApiClient: GoogleApiClient, + locationListener: LocationListener, + ) {} + + override fun requestLocationUpdates( + googleApiClient: GoogleApiClient, + locationRequest: LocationRequest, + locationListener: LocationListener, + ) {} + + override fun getLastLocation(googleApiClient: GoogleApiClient): Location? { + return locations.remove() + } +} diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt deleted file mode 100644 index 395cb2b6e1..0000000000 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt +++ /dev/null @@ -1,161 +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.location.shadows - -import android.app.PendingIntent -import android.location.Location -import android.os.Looper -import com.google.android.gms.common.api.GoogleApiClient -import com.google.android.gms.common.api.PendingResult -import com.google.android.gms.common.api.ResultCallback -import com.google.android.gms.common.api.Status -import com.google.android.gms.location.FusedLocationProviderApi -import com.google.android.gms.location.LocationAvailability -import com.google.android.gms.location.LocationCallback -import com.google.android.gms.location.LocationListener -import com.google.android.gms.location.LocationRequest -import com.google.android.gms.location.LocationServices -import java.lang.reflect.Field -import java.lang.reflect.Modifier -import java.util.concurrent.TimeUnit - -class ShadowFusedLocationProviderApi : FusedLocationProviderApi { - val pendingResult = - object : PendingResult() { - override fun await(): Status = Status.RESULT_SUCCESS - - override fun await( - p0: Long, - p1: TimeUnit, - ): Status = Status.RESULT_SUCCESS - - override fun cancel() { } - - override fun isCanceled(): Boolean = false - - override fun setResultCallback(p0: ResultCallback) { } - - override fun setResultCallback( - p0: ResultCallback, - p1: Long, - p2: TimeUnit, - ) {} - } - - override fun getLastLocation(p0: GoogleApiClient): Location { - if (locations != null) { - val location = locations!![index] - index++ - if (index >= locations!!.count()) { - index = 0 - } - - return location - } - - val location = Location("TEST_PROVIDER") - location.latitude = 123.45 - location.longitude = 678.91 - return location - } - - override fun getLocationAvailability(p0: GoogleApiClient): LocationAvailability = throw Exception() - - override fun requestLocationUpdates( - p0: GoogleApiClient, - p1: LocationRequest, - p2: LocationListener, - ): PendingResult = pendingResult - - override fun requestLocationUpdates( - p0: GoogleApiClient, - p1: LocationRequest, - p2: LocationListener, - p3: Looper, - ): PendingResult = pendingResult - - override fun requestLocationUpdates( - p0: GoogleApiClient, - p1: LocationRequest, - p2: LocationCallback, - p3: Looper, - ): PendingResult = pendingResult - - override fun requestLocationUpdates( - p0: GoogleApiClient, - p1: LocationRequest, - p2: PendingIntent, - ): PendingResult = pendingResult - - override fun removeLocationUpdates( - p0: GoogleApiClient, - p1: LocationListener, - ): PendingResult = pendingResult - - override fun removeLocationUpdates( - p0: GoogleApiClient, - p1: PendingIntent, - ): PendingResult = pendingResult - - override fun removeLocationUpdates( - p0: GoogleApiClient, - p1: LocationCallback, - ): PendingResult = pendingResult - - override fun setMockMode( - p0: GoogleApiClient, - p1: Boolean, - ): PendingResult = pendingResult - - override fun setMockLocation( - p0: GoogleApiClient, - p1: Location, - ): PendingResult = pendingResult - - override fun flushLocations(p0: GoogleApiClient): PendingResult = pendingResult - - companion object { - private var locations: List? = null - private var index: Int = 0 - - fun injectToLocationServices(locations: List) { - this.index = 0 - this.locations = locations - val currentFused = LocationServices.FusedLocationApi - val newFused = ShadowFusedLocationProviderApi() - - val field = LocationServices::class.java.getDeclaredField("FusedLocationApi") - field.isAccessible = true - - val modifiersField: Field = Field::class.java.getDeclaredField("modifiers") - modifiersField.isAccessible = true - modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv()) - - field.set(null, newFused) - } - } -} From 109157eecc08f08d2ba40df8eec6ce43a459af48 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 15 Feb 2024 17:20:56 -0500 Subject: [PATCH 03/17] fixed FAIL_PAUSE_OPREPO not updated in test PR #1900 intorduced FAIL_PAUSE_OPREPO but never updated the test --- .../user/internal/operations/LoginUserOperationExecutorTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt index 75a2187841..9ee605b624 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt @@ -129,7 +129,7 @@ class LoginUserOperationExecutorTests : FunSpec({ val response = loginUserOperationExecutor.execute(operations) // Then - response.result shouldBe ExecutionResult.FAIL_NORETRY + response.result shouldBe ExecutionResult.FAIL_PAUSE_OPREPO coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) } } From 6ddcaf91e92d1e75d0bd597cbdb2108b3001e8bb Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 15 Feb 2024 17:24:38 -0500 Subject: [PATCH 04/17] fixed create user test to ensure we omit aliases PR #1794 made changes to omit aliases on user create, but the test was never updated. Also the SubscriptionStatus arg part of this test wasn't compare the corret types, causing it to fail the test. --- .../operations/LoginUserOperationExecutorTests.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt index 9ee605b624..e448054390 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt @@ -392,13 +392,18 @@ class LoginUserOperationExecutorTests : FunSpec({ coVerify(exactly = 1) { mockUserBackendService.createUser( appId, - mapOf("aliasLabel1" to "aliasValue1-2"), + // Aliases omitted intentionally in PR #1794, to avoid failed create user calls. + // - Ideally we batch as much as possible into the create as most of the time it + // should be successful. Then when there are failures omit the "bad data" and try + // again, however this is more complex which is why it wasn't done initially. + mapOf(), withArg { it.count() shouldBe 1 - it[0].type shouldBe SubscriptionObjectType.ANDROID_PUSH - it[0].enabled shouldBe true - it[0].token shouldBe "pushToken2" - it[0].notificationTypes shouldBe SubscriptionStatus.SUBSCRIBED + val subscription = it[0] + subscription.type shouldBe SubscriptionObjectType.ANDROID_PUSH + subscription.enabled shouldBe true + subscription.token shouldBe "pushToken2" + SubscriptionStatus.fromInt(subscription.notificationTypes!!) shouldBe SubscriptionStatus.SUBSCRIBED }, any(), ) From b38b483e7d086c47e2343015a139f5635880e892 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Tue, 20 Feb 2024 21:03:52 -0500 Subject: [PATCH 05/17] ensure @RobolectricTest can't be silently skipped It seems Kotest's intercept caller eats expections and moves on silently. Adding a try-catch and reporting TestResult.Error to solve this. --- .../onesignal/extensions/RobolectricExtension.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt index f5353ceab5..2935751873 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt @@ -16,6 +16,7 @@ import io.kotest.core.test.TestResult import org.robolectric.annotation.Config import kotlin.reflect.KClass import kotlin.reflect.full.findAnnotation +import kotlin.time.Duration /** * We override TestCaseExtension to configure the Robolectric environment because TestCase intercept @@ -62,6 +63,19 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { override suspend fun intercept( testCase: TestCase, execute: suspend (TestCase) -> TestResult, + ): TestResult { + return try { + runTest(testCase, execute) + } catch (t: Throwable) { + // Without this the whole test class will be silently be skipped + // if something throws + TestResult.Error(Duration.ZERO, t) + } + } + + private suspend fun runTest( + testCase: TestCase, + execute: suspend (TestCase) -> TestResult, ): TestResult { // FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717 val hasRobolectricAnnotation = From 66fd002b0f8751a36355a33856239066c16a27f6 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Tue, 20 Feb 2024 21:11:03 -0500 Subject: [PATCH 06/17] split up Robolectric specific code for readability --- .../com/onesignal/extensions/RobolectricExtension.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt index 2935751873..89af808825 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt @@ -83,10 +83,17 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName } - if (!hasRobolectricAnnotation) { - return execute(testCase) + return if (hasRobolectricAnnotation) { + runTestRobolectric(testCase, execute) + } else { + execute(testCase) } + } + private suspend fun runTestRobolectric( + testCase: TestCase, + execute: suspend (TestCase) -> TestResult, + ): TestResult { val containedRobolectricRunner = ContainedRobolectricRunner(testCase.spec::class.getConfig()) containedRobolectricRunner.containedBefore() val result = execute(testCase) From 52dad804ccfeec8ac26dcf22ef01a209a5acd0e9 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Tue, 20 Feb 2024 21:31:43 -0500 Subject: [PATCH 07/17] fix issue with @RobolectricTest failing The first class with @RobolectricTest would run fine, but then every test class after in the run would fail with a looper already started error. This fix was discovered by looking through Robolectric's RobolectricTestRunner and SandboxTestRunner clases. Most of the pre-existing kotest-extensions-robolectric code seemed to be reripped from those 2 classes and I notice this was something this extension was not doing. Looper's are linked to a thread so this seems related, however I don't understand any more than this to explain why this fixes the error. --- .../extensions/RobolectricExtension.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt index 89af808825..7e1c3451e1 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt @@ -7,6 +7,7 @@ package com.onesignal.extensions import android.app.Application +import io.kotest.common.runBlocking import io.kotest.core.extensions.ConstructorExtension import io.kotest.core.extensions.TestCaseExtension import io.kotest.core.spec.AutoScan @@ -14,6 +15,7 @@ import io.kotest.core.spec.Spec import io.kotest.core.test.TestCase import io.kotest.core.test.TestResult import org.robolectric.annotation.Config +import java.util.concurrent.Callable import kotlin.reflect.KClass import kotlin.reflect.full.findAnnotation import kotlin.time.Duration @@ -94,11 +96,18 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { testCase: TestCase, execute: suspend (TestCase) -> TestResult, ): TestResult { - val containedRobolectricRunner = ContainedRobolectricRunner(testCase.spec::class.getConfig()) - containedRobolectricRunner.containedBefore() - val result = execute(testCase) - containedRobolectricRunner.containedAfter() - return result + val containedRobolectricRunner = + ContainedRobolectricRunner(testCase.spec::class.getConfig()) + // sdkEnvironment.runOnMainThread is important to ensure Robolectric's + // looper state doesn't carry over to the next test class. + return containedRobolectricRunner.sdkEnvironment.runOnMainThread( + Callable { + containedRobolectricRunner.containedBefore() + val result = runBlocking { execute(testCase) } + containedRobolectricRunner.containedAfter() + result + }, + ) } } From b7ff4b7239b877b3d3fa0fc9f9541483733aa3de Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Tue, 20 Feb 2024 22:48:39 -0500 Subject: [PATCH 08/17] new testhelpers module to share test extensions De-duplicated ContainedRobolectricRunner.kt and RobolectricExtension.kt by moving them into their own module. Before landing on this implementation I attempted to use the gradle feature testFixtures, however this doesn't work with the android gradle plugin. --- OneSignalSDK/onesignal/core/build.gradle | 1 + .../application/ApplicationServiceTests.kt | 2 +- .../core/internal/database/OSDatabaseTests.kt | 2 +- .../preferences/PreferencesServiceTests.kt | 2 +- .../outcomes/OutcomeEventsRepositoryTests.kt | 2 +- .../SubscriptionBackendServiceTests.kt | 2 +- .../LoginUserOperationExecutorTests.kt | 2 +- .../SubscriptionOperationExecutorTests.kt | 2 +- .../onesignal/in-app-messages/build.gradle | 1 + .../extensions/ContainedRobolectricRunner.kt | 70 ------------ .../extensions/RobolectricExtension.kt | 100 ------------------ .../InAppMessagePreviewHandlerTests.kt | 2 +- OneSignalSDK/onesignal/location/build.gradle | 1 + .../extensions/ContainedRobolectricRunner.kt | 70 ------------ .../extensions/RobolectricExtension.kt | 100 ------------------ .../LocationBackgroundServiceTests.kt | 2 +- .../controller/GmsLocationControllerTests.kt | 2 +- .../LocationPermissionControllerTests.kt | 2 +- .../onesignal/notifications/build.gradle | 1 + .../extensions/ContainedRobolectricRunner.kt | 70 ------------ .../extensions/RobolectricExtension.kt | 100 ------------------ .../NotificationChannelManagerTests.kt | 2 +- .../NotificationGenerationProcessorTests.kt | 2 +- .../limiting/NotificationLimitManagerTests.kt | 2 +- .../NotificationSummaryManagerTests.kt | 2 +- OneSignalSDK/onesignal/testhelpers/.gitignore | 1 + .../onesignal/testhelpers/build.gradle | 47 ++++++++ .../extensions/ContainedRobolectricRunner.kt | 4 +- .../extensions/RobolectricExtension.kt | 4 +- OneSignalSDK/settings.gradle | 1 + 30 files changed, 72 insertions(+), 529 deletions(-) delete mode 100644 OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt delete mode 100644 OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt delete mode 100644 OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt delete mode 100644 OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt delete mode 100644 OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt delete mode 100644 OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt create mode 100644 OneSignalSDK/onesignal/testhelpers/.gitignore create mode 100644 OneSignalSDK/onesignal/testhelpers/build.gradle rename OneSignalSDK/onesignal/{core/src/test/java/com/onesignal => testhelpers/src/main/java/com/onesignal/testhelpers}/extensions/ContainedRobolectricRunner.kt (96%) rename OneSignalSDK/onesignal/{core/src/test/java/com/onesignal => testhelpers/src/main/java/com/onesignal/testhelpers}/extensions/RobolectricExtension.kt (97%) diff --git a/OneSignalSDK/onesignal/core/build.gradle b/OneSignalSDK/onesignal/core/build.gradle index 50df86cd10..ec7d5212a2 100644 --- a/OneSignalSDK/onesignal/core/build.gradle +++ b/OneSignalSDK/onesignal/core/build.gradle @@ -78,6 +78,7 @@ dependencies { } } + testImplementation(project(':OneSignal:testhelpers')) testImplementation("junit:junit:$junitVersion") testImplementation("io.kotest:kotest-runner-junit4:$kotestVersion") testImplementation("io.kotest:kotest-runner-junit4-jvm:$kotestVersion") diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt index 900959ee1a..8408df863d 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt @@ -8,7 +8,7 @@ import com.onesignal.common.threading.suspendifyOnThread import com.onesignal.core.internal.application.impl.ApplicationService import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging -import com.onesignal.extensions.RobolectricTest +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt index a32d20b438..0500ba704b 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt @@ -6,8 +6,8 @@ import com.onesignal.core.internal.database.impl.OSDatabase import com.onesignal.core.internal.database.impl.OneSignalDbContract import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging -import com.onesignal.extensions.RobolectricTest import com.onesignal.session.internal.outcomes.impl.OutcomeTableProvider +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt index 1a9065b6da..d1fdb5d13f 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt @@ -5,9 +5,9 @@ import androidx.test.core.app.ApplicationProvider import com.onesignal.core.internal.preferences.impl.PreferencesService import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging -import com.onesignal.extensions.RobolectricTest import com.onesignal.mocks.AndroidMockHelper import com.onesignal.mocks.MockHelper +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.assertions.throwables.shouldThrowUnit import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt index 05a05f14fe..e3c26477d4 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt @@ -2,7 +2,6 @@ package com.onesignal.session.internal.outcomes import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging -import com.onesignal.extensions.RobolectricTest import com.onesignal.mocks.DatabaseMockHelper import com.onesignal.session.internal.influence.Influence import com.onesignal.session.internal.influence.InfluenceChannel @@ -13,6 +12,7 @@ import com.onesignal.session.internal.outcomes.impl.OutcomeEventsRepository import com.onesignal.session.internal.outcomes.impl.OutcomeEventsTable import com.onesignal.session.internal.outcomes.impl.OutcomeSource import com.onesignal.session.internal.outcomes.impl.OutcomeSourceBody +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt index 2fe09b7a4e..09852a0859 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt @@ -5,7 +5,7 @@ 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.extensions.RobolectricTest +import com.onesignal.testhelpers.extensions.RobolectricTest import com.onesignal.user.internal.backend.impl.SubscriptionBackendService import com.onesignal.user.internal.subscriptions.SubscriptionStatus import io.kotest.assertions.throwables.shouldThrowUnit diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt index e448054390..1a3b9fc3c9 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt @@ -4,9 +4,9 @@ import com.onesignal.common.exceptions.BackendException import com.onesignal.core.internal.operations.ExecutionResponse import com.onesignal.core.internal.operations.ExecutionResult import com.onesignal.core.internal.operations.Operation -import com.onesignal.extensions.RobolectricTest import com.onesignal.mocks.AndroidMockHelper import com.onesignal.mocks.MockHelper +import com.onesignal.testhelpers.extensions.RobolectricTest import com.onesignal.user.internal.backend.CreateUserResponse import com.onesignal.user.internal.backend.IUserBackendService import com.onesignal.user.internal.backend.IdentityConstants diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt index ea38d8cf6a..5d8e67f1c4 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt @@ -3,9 +3,9 @@ package com.onesignal.user.internal.operations import com.onesignal.common.exceptions.BackendException import com.onesignal.core.internal.operations.ExecutionResult import com.onesignal.core.internal.operations.Operation -import com.onesignal.extensions.RobolectricTest import com.onesignal.mocks.AndroidMockHelper import com.onesignal.mocks.MockHelper +import com.onesignal.testhelpers.extensions.RobolectricTest import com.onesignal.user.internal.backend.ISubscriptionBackendService import com.onesignal.user.internal.backend.IdentityConstants import com.onesignal.user.internal.backend.SubscriptionObjectType diff --git a/OneSignalSDK/onesignal/in-app-messages/build.gradle b/OneSignalSDK/onesignal/in-app-messages/build.gradle index ced85d59d3..e5cf77856e 100644 --- a/OneSignalSDK/onesignal/in-app-messages/build.gradle +++ b/OneSignalSDK/onesignal/in-app-messages/build.gradle @@ -78,6 +78,7 @@ dependencies { } } + testImplementation(project(':OneSignal:testhelpers')) testImplementation("junit:junit:$junitVersion") testImplementation("io.kotest:kotest-runner-junit4:$kotestVersion") testImplementation("io.kotest:kotest-runner-junit4-jvm:$kotestVersion") diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt deleted file mode 100644 index 123fe4a883..0000000000 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt +++ /dev/null @@ -1,70 +0,0 @@ -/** - * 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.inAppMessages.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/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt deleted file mode 100644 index 5e02113ecd..0000000000 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt +++ /dev/null @@ -1,100 +0,0 @@ -/** - * 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.inAppMessages.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/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt index 572bba363b..462a7c5429 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt @@ -3,13 +3,13 @@ package com.onesignal.inAppMessages.internal.preview import android.app.Activity import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging -import com.onesignal.inAppMessages.extensions.RobolectricTest import com.onesignal.inAppMessages.internal.display.IInAppDisplayer import com.onesignal.inAppMessages.internal.state.InAppStateService import com.onesignal.inAppMessages.mocks.MockHelper import com.onesignal.notifications.internal.INotificationActivityOpener import com.onesignal.notifications.internal.display.INotificationDisplayer import com.onesignal.notifications.internal.lifecycle.INotificationLifecycleService +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner diff --git a/OneSignalSDK/onesignal/location/build.gradle b/OneSignalSDK/onesignal/location/build.gradle index 00f31eb7bf..5c4990d96f 100644 --- a/OneSignalSDK/onesignal/location/build.gradle +++ b/OneSignalSDK/onesignal/location/build.gradle @@ -77,6 +77,7 @@ dependencies { // KEEP as "compileOnly", so OneSignal isn't a direct dependency in the POM file. compileOnly "com.huawei.hms:location:$huaweiHMSLocationVersion" + testImplementation(project(':OneSignal:testhelpers')) testImplementation("junit:junit:$junitVersion") testImplementation("io.kotest:kotest-runner-junit4:$kotestVersion") testImplementation("io.kotest:kotest-runner-junit4-jvm:$kotestVersion") diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt deleted file mode 100644 index fa722e93ad..0000000000 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt +++ /dev/null @@ -1,70 +0,0 @@ -/** - * 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/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt deleted file mode 100644 index 3250906490..0000000000 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt +++ /dev/null @@ -1,100 +0,0 @@ -/** - * 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/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt index eb65a886b0..a300b68565 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt @@ -11,7 +11,7 @@ import com.onesignal.location.internal.common.LocationConstants import com.onesignal.location.internal.preferences.ILocationPreferencesService import com.onesignal.mocks.AndroidMockHelper import com.onesignal.mocks.MockHelper -import com.onesignal.notifications.extensions.RobolectricTest +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt index a4ced5d54f..6cf711be47 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt @@ -8,7 +8,7 @@ import com.onesignal.location.mocks.FusedLocationApiWrapperMock import com.onesignal.location.shadows.ShadowGoogleApiClient import com.onesignal.location.shadows.ShadowGoogleApiClientBuilder import com.onesignal.mocks.AndroidMockHelper -import com.onesignal.notifications.extensions.RobolectricTest +import com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt index 1b5e132596..713253a18a 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt @@ -4,7 +4,7 @@ import com.onesignal.core.internal.permissions.IRequestPermissionService 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.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.longs.shouldBeGreaterThan import io.kotest.matchers.shouldBe diff --git a/OneSignalSDK/onesignal/notifications/build.gradle b/OneSignalSDK/onesignal/notifications/build.gradle index 10da2da4f7..c31add7d5c 100644 --- a/OneSignalSDK/onesignal/notifications/build.gradle +++ b/OneSignalSDK/onesignal/notifications/build.gradle @@ -90,6 +90,7 @@ dependencies { } } + testImplementation(project(':OneSignal:testhelpers')) testImplementation("junit:junit:$junitVersion") testImplementation("io.kotest:kotest-runner-junit4:$kotestVersion") testImplementation("io.kotest:kotest-runner-junit4-jvm:$kotestVersion") 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 deleted file mode 100644 index fa722e93ad..0000000000 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt +++ /dev/null @@ -1,70 +0,0 @@ -/** - * 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 deleted file mode 100644 index 3250906490..0000000000 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt +++ /dev/null @@ -1,100 +0,0 @@ -/** - * 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/channels/NotificationChannelManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt index a5fa36f336..382787c2d4 100644 --- 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 @@ -9,10 +9,10 @@ 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 com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe 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 index 33d66ddb03..3697ccb66b 100644 --- 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 @@ -8,12 +8,12 @@ import com.onesignal.mocks.AndroidMockHelper import com.onesignal.mocks.MockHelper import com.onesignal.notifications.INotificationReceivedEvent import com.onesignal.notifications.INotificationWillDisplayEvent -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 com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner 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 index 79ba17c980..f925daf36e 100644 --- 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 @@ -7,10 +7,10 @@ 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 com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.runner.junit4.KotestTestRunner import io.mockk.coEvery 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 index cb727dc58d..87e36f99e9 100644 --- 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 @@ -4,12 +4,12 @@ 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 com.onesignal.testhelpers.extensions.RobolectricTest import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner diff --git a/OneSignalSDK/onesignal/testhelpers/.gitignore b/OneSignalSDK/onesignal/testhelpers/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/OneSignalSDK/onesignal/testhelpers/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/OneSignalSDK/onesignal/testhelpers/build.gradle b/OneSignalSDK/onesignal/testhelpers/build.gradle new file mode 100644 index 0000000000..e612ba8333 --- /dev/null +++ b/OneSignalSDK/onesignal/testhelpers/build.gradle @@ -0,0 +1,47 @@ +plugins { + id 'com.android.library' + id 'kotlin-android' + id 'org.jlleitschuh.gradle.ktlint' +} + +android { + compileSdkVersion rootProject.buildVersions.compileSdkVersion + defaultConfig { + minSdkVersion rootProject.buildVersions.minSdkVersion + } + + buildTypes { + original { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + release { + minifyEnabled false + } + unity { + minifyEnabled false + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + namespace 'com.onesignal.testhelpers' + + kotlinOptions.freeCompilerArgs += ['-module-name', namespace] +} + +dependencies { + implementation("junit:junit:$junitVersion") + implementation("io.kotest:kotest-runner-junit4:$kotestVersion") + implementation("org.robolectric:robolectric:4.8.1") + implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion") +} + +ktlint { + version = "$ktlintVersion" +} diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/ContainedRobolectricRunner.kt similarity index 96% rename from OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt rename to OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/ContainedRobolectricRunner.kt index 3f6529695a..ab8d352e2c 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt +++ b/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/ContainedRobolectricRunner.kt @@ -3,7 +3,7 @@ * * LICENSE: https://github.com/kotest/kotest-extensions-robolectric/blob/master/LICENSE */ -package com.onesignal.extensions +package com.onesignal.testhelpers.extensions import org.junit.runners.model.FrameworkMethod import org.robolectric.RobolectricTestRunner @@ -13,7 +13,7 @@ import org.robolectric.pluginapi.config.ConfigurationStrategy import org.robolectric.plugins.ConfigConfigurer import java.lang.reflect.Method -internal class ContainedRobolectricRunner( +class ContainedRobolectricRunner( private val config: Config?, ) : RobolectricTestRunner(PlaceholderTest::class.java, injector) { private val placeHolderMethod: FrameworkMethod = children[0] diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt similarity index 97% rename from OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt rename to OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt index 7e1c3451e1..0bf1c4ff1d 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt @@ -4,7 +4,7 @@ * * LICENSE: https://github.com/kotest/kotest-extensions-robolectric/blob/master/LICENSE */ -package com.onesignal.extensions +package com.onesignal.testhelpers.extensions import android.app.Application import io.kotest.common.runBlocking @@ -26,7 +26,7 @@ import kotlin.time.Duration * rather than every spec. But the SpecExtension intercept is run on a different thread. */ @AutoScan -internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { +class RobolectricExtension : ConstructorExtension, TestCaseExtension { private fun Class<*>.getParentClass(): List> { if (superclass == null) return listOf() return listOf(superclass) + superclass.getParentClass() diff --git a/OneSignalSDK/settings.gradle b/OneSignalSDK/settings.gradle index b4845708f3..b114b0b152 100644 --- a/OneSignalSDK/settings.gradle +++ b/OneSignalSDK/settings.gradle @@ -25,3 +25,4 @@ include ':OneSignal:core' include ':OneSignal:in-app-messages' include ':OneSignal:location' include ':OneSignal:notifications' +include ':OneSignal:testhelpers' From edcbd3db8a38b2dbd7f3423895b89b85f97a78a0 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 21 Feb 2024 00:25:42 -0500 Subject: [PATCH 09/17] Always run all tests, even if one module fails This makes sure you can see all failures --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d108601db..2aa1feb062 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - name: "[Test] SDK Unit Tests" working-directory: OneSignalSDK run: | - ./gradlew test --console=plain + ./gradlew test --console=plain --continue - name: Unit tests results if: failure() uses: actions/upload-artifact@v3 From ab7dcaba74f5406316dae027c59d155197d5bfee Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 21 Feb 2024 00:53:41 -0500 Subject: [PATCH 10/17] run only the release tests to speed up tests Test were being run 3 times since it was running debug, release, and unity targets. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2aa1feb062..c5e77c3d09 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - name: "[Test] SDK Unit Tests" working-directory: OneSignalSDK run: | - ./gradlew test --console=plain --continue + ./gradlew testReleaseUnitTest --console=plain --continue - name: Unit tests results if: failure() uses: actions/upload-artifact@v3 From dad718fd703e2bdd765a49b764c18f7a1cf62b89 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 21 Feb 2024 20:40:26 -0500 Subject: [PATCH 11/17] fix `@Config` with RobolectricExtension In a previous commit I assumed all 4 copies of RobolectricExtension.kt were the same, however there was a difference in their getConfig implementation. This fixes a number of failing tests, such as the location tests. --- .../extensions/RobolectricExtension.kt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt index 0bf1c4ff1d..e6ea8cf0a0 100644 --- a/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/testhelpers/src/main/java/com/onesignal/testhelpers/extensions/RobolectricExtension.kt @@ -33,15 +33,26 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension { } private fun KClass<*>.getConfig(): Config { - val annotations = + 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? = - annotations + robolectricTestAnnotations .firstOrNull { it.application != KotestDefaultApplication::class }?.application - val sdk: Int? = annotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk + val sdk: Int? = robolectricTestAnnotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk return Config.Builder() .also { builder -> From f68ec94a0d65df5e4502cbf63e8a8b27b5c7729a Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 21 Feb 2024 23:24:17 -0500 Subject: [PATCH 12/17] rm susbcription id from susbcription create id isn't a valid parameter to the OneSignal POST /subscriptions REST API --- .../internal/backend/impl/SubscriptionBackendService.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt index ac48f4fc7d..e6f6d23c92 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt @@ -17,9 +17,9 @@ internal class SubscriptionBackendService( aliasValue: String, subscription: SubscriptionObject, ): String? { - val requestJSON = - JSONObject() - .put("subscription", JSONConverter.convertToJSON(subscription)) + val jsonSubscription = JSONConverter.convertToJSON(subscription) + jsonSubscription.remove("id") + val requestJSON = JSONObject().put("subscription", jsonSubscription) val response = _httpClient.post("apps/$appId/users/by/$aliasLabel/$aliasValue/subscriptions", requestJSON) From 48f9633bf155481e0c066eaa0590753b01947241 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 21 Feb 2024 23:26:03 -0500 Subject: [PATCH 13/17] fixed SubscriptionBackendServiceTests Test was out-of-date to the production changes we made a while ago. --- .../SubscriptionBackendServiceTests.kt | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt index 09852a0859..e98293db46 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt @@ -5,7 +5,6 @@ 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.testhelpers.extensions.RobolectricTest import com.onesignal.user.internal.backend.impl.SubscriptionBackendService import com.onesignal.user.internal.subscriptions.SubscriptionStatus import io.kotest.assertions.throwables.shouldThrowUnit @@ -17,7 +16,8 @@ import io.mockk.coVerify import io.mockk.mockk import org.junit.runner.RunWith -@RobolectricTest +// WARNING: Adding @RobolectricTest will cause JSONObject.map() to stop working +// at runtime. @RunWith(KotestTestRunner::class) class SubscriptionBackendServiceTests : FunSpec({ beforeAny { @@ -29,7 +29,7 @@ class SubscriptionBackendServiceTests : FunSpec({ val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() - coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{id: \"subscriptionId\"}") + coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{ \"subscription\": { id: \"subscriptionId\" } }") val subscriptionBackendService = SubscriptionBackendService(spyHttpClient) // When @@ -48,13 +48,14 @@ class SubscriptionBackendServiceTests : FunSpec({ response shouldBe "subscriptionId" coVerify { spyHttpClient.post( - "apps/appId/user/by/$aliasLabel/$aliasValue/subscription", + "apps/appId/users/by/$aliasLabel/$aliasValue/subscriptions", withArg { - it.has("id") shouldBe false - it.getString("type") shouldBe "AndroidPush" - it.getString("token") shouldBe "pushToken" - it.getBoolean("enabled") shouldBe true - it.getInt("notification_types") shouldBe 1 + val sub = it.getJSONObject("subscription") + sub.has("id") shouldBe false + sub.getString("type") shouldBe "AndroidPush" + sub.getString("token") shouldBe "pushToken" + sub.getBoolean("enabled") shouldBe true + sub.getInt("notification_types") shouldBe 1 }, ) } @@ -92,13 +93,14 @@ class SubscriptionBackendServiceTests : FunSpec({ // Then coVerify { spyHttpClient.post( - "apps/appId/user/by/$aliasLabel/$aliasValue/subscription", + "apps/appId/users/by/$aliasLabel/$aliasValue/subscriptions", withArg { - it.has("id") shouldBe false - it.getString("type") shouldBe "AndroidPush" - it.getString("token") shouldBe "pushToken" - it.getBoolean("enabled") shouldBe true - it.getInt("notification_types") shouldBe 1 + val sub = it.getJSONObject("subscription") + sub.has("id") shouldBe false + sub.getString("type") shouldBe "AndroidPush" + sub.getString("token") shouldBe "pushToken" + sub.getBoolean("enabled") shouldBe true + sub.getInt("notification_types") shouldBe 1 }, ) } From 0fce61cf1b58d322e0bb88b5d90de5a3c92257fd Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 22 Feb 2024 00:12:57 -0500 Subject: [PATCH 14/17] fix missing sessionTime in outcomes test This was the only test failing in this file and now it is passing. --- .../internal/outcomes/OutcomeEventsRepositoryTests.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt index e3c26477d4..efede32e7c 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt @@ -171,6 +171,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId1", OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.2f, OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 1111L, + OutcomeEventsTable.COLUMN_NAME_SESSION_TIME to 1L, OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "unattributed", OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "unattributed", ), @@ -178,6 +179,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId2", OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.4f, OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 2222L, + OutcomeEventsTable.COLUMN_NAME_SESSION_TIME to 2L, OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "indirect", OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS to "[\"notificationId1\",\"notificationId2\"]", OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "indirect", @@ -187,6 +189,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId3", OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.6f, OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 3333L, + OutcomeEventsTable.COLUMN_NAME_SESSION_TIME to 3L, OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "direct", OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS to "[\"notificationId3\"]", OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "direct", @@ -205,12 +208,14 @@ class OutcomeEventsRepositoryTests : FunSpec({ events[0].outcomeId shouldBe "outcomeId1" events[0].weight shouldBe 0.2f events[0].timestamp shouldBe 1111L + events[0].sessionTime shouldBe 1L events[0].outcomeSource shouldNotBe null events[0].outcomeSource!!.directBody shouldBe null events[0].outcomeSource!!.indirectBody shouldBe null events[1].outcomeId shouldBe "outcomeId2" events[1].weight shouldBe 0.4f events[1].timestamp shouldBe 2222L + events[1].sessionTime shouldBe 2L events[1].outcomeSource shouldNotBe null events[1].outcomeSource!!.directBody shouldBe null events[1].outcomeSource!!.indirectBody shouldNotBe null @@ -223,6 +228,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ events[2].outcomeId shouldBe "outcomeId3" events[2].weight shouldBe 0.6f events[2].timestamp shouldBe 3333L + events[2].sessionTime shouldBe 3L events[2].outcomeSource shouldNotBe null events[2].outcomeSource!!.indirectBody shouldBe null events[2].outcomeSource!!.directBody shouldNotBe null From 4573974cb186dd0e1031b73700c19c768f42b8a2 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 22 Feb 2024 01:24:00 -0500 Subject: [PATCH 15/17] fix test by adding a missing mock --- .../internal/operations/SubscriptionOperationExecutorTests.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt index 5d8e67f1c4..c0a940a883 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt @@ -149,6 +149,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() + every { mockBuildUserService.getRebuildOperationsIfCurrentUser(any(), any()) } answers { null } val subscriptionOperationExecutor = SubscriptionOperationExecutor( From 3faf8e29b1e62099420c58cf0ef6df09b4f7ff07 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 22 Feb 2024 01:26:41 -0500 Subject: [PATCH 16/17] rm checking module in update test Update allways follow from the module to resulting in making a network request to reflect it on the backed. An update operation will never result in property update to the model. This was proabably true at one point the code base, but if so it was a mistake. --- .../internal/operations/SubscriptionOperationExecutorTests.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt index c0a940a883..012943aca1 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt @@ -351,7 +351,6 @@ class SubscriptionOperationExecutorTests : FunSpec({ // Then response.result shouldBe ExecutionResult.SUCCESS - subscriptionModel1.address shouldBe "pushToken3" coVerify(exactly = 1) { mockSubscriptionBackendService.updateSubscription( appId, From 900d76af4c45f157cfd066379c3258fe762e639c Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 22 Feb 2024 01:27:53 -0500 Subject: [PATCH 17/17] fixed subscription delete test when 404 If we get a 404 when we try to delete then it was already done at some point, so we count it as successful --- .../operations/SubscriptionOperationExecutorTests.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt index 012943aca1..9b31d48b27 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt @@ -539,7 +539,9 @@ class SubscriptionOperationExecutorTests : FunSpec({ coVerify(exactly = 1) { mockSubscriptionBackendService.deleteSubscription(appId, remoteSubscriptionId) } } - test("delete subscription fails without retry when there is a backend error") { + // If we get a 404 then the subscription has already been deleted, + // so we count it as successful + test("delete subscription is successful if there is a 404") { // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.deleteSubscription(any(), any()) } throws BackendException(404) @@ -566,7 +568,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ val response = subscriptionOperationExecutor.execute(operations) // Then - response.result shouldBe ExecutionResult.FAIL_NORETRY + response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockSubscriptionBackendService.deleteSubscription(appId, remoteSubscriptionId) } } })