From a3ee171e913954eb9bf3b42163fecd19cefde198 Mon Sep 17 00:00:00 2001 From: Mansi Pandya Date: Thu, 30 May 2024 10:10:35 -0400 Subject: [PATCH] fix: Add callback functionality to upload method --- android-core/build.gradle | 1 + .../mparticle/internal/MessageManager.java | 14 ++++- .../com/mparticle/internal/UploadHandler.java | 15 ++++++ .../mparticle/internal/MessageManagerTest.kt | 31 ++++++++++- .../mparticle/internal/UploadHandlerTest.kt | 51 +++++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/android-core/build.gradle b/android-core/build.gradle index e4b7d1df9..00765d012 100644 --- a/android-core/build.gradle +++ b/android-core/build.gradle @@ -83,6 +83,7 @@ android { jvmArgs += ['--add-opens', 'java.base/java.util=ALL-UNNAMED'] jvmArgs += ['--add-opens', 'java.base/java.text=ALL-UNNAMED'] jvmArgs += ['--add-opens', 'java.base/java.math=ALL-UNNAMED'] + jvmArgs += ['--add-opens', 'java.base/java.lang.reflect=ALL-UNNAMED'] jvmArgs += ['--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED'] jvmArgs += ['--add-opens', 'java.base/java.lang.ref=ALL-UNNAMED'] } diff --git a/android-core/src/main/java/com/mparticle/internal/MessageManager.java b/android-core/src/main/java/com/mparticle/internal/MessageManager.java index 8824a7e2e..3849114c8 100644 --- a/android-core/src/main/java/com/mparticle/internal/MessageManager.java +++ b/android-core/src/main/java/com/mparticle/internal/MessageManager.java @@ -62,6 +62,7 @@ public class MessageManager implements MessageManagerCallbacks, ReportingManager private ConfigManager mConfigManager = null; private MParticleDBManager mMParticleDBManager; private MParticle.OperatingSystem mOperatingSystem; + private MParticle.UploadCallback uploadCallback; /** @@ -525,7 +526,10 @@ public void startUploadLoop() { mUploadHandler.sendMessageDelayed(mUploadHandler.obtainMessage(UploadHandler.UPLOAD_MESSAGES, mConfigManager.getMpid()), Constants.INITIAL_UPLOAD_DELAY); } - public void doUpload() { + public void doUpload(MParticle.UploadCallback... callbacks) { + if (callbacks.length > 0) { + uploadCallback = callbacks[0]; + } mMessageHandler.sendMessage(mMessageHandler.obtainMessage(MessageHandler.CLEAR_MESSAGES_FOR_UPLOAD)); } @@ -979,6 +983,14 @@ void setFirstRunForAST(boolean firstRun) { .apply(); } + public MParticle.UploadCallback getUploadCallback() { + return uploadCallback; + } + + public void setUploadCallback(MParticle.UploadCallback uploadCallback) { + this.uploadCallback = uploadCallback; + } + @SuppressLint("MissingPermission") private class StatusBroadcastReceiver extends BroadcastReceiver { @Override diff --git a/android-core/src/main/java/com/mparticle/internal/UploadHandler.java b/android-core/src/main/java/com/mparticle/internal/UploadHandler.java index 790c8def4..55c397454 100644 --- a/android-core/src/main/java/com/mparticle/internal/UploadHandler.java +++ b/android-core/src/main/java/com/mparticle/internal/UploadHandler.java @@ -238,13 +238,28 @@ protected boolean upload(boolean history) { } } } + if (mMessageManager != null && mMessageManager.getUploadCallback() != null) { + mMessageManager.getUploadCallback().onSuccess(); + } } catch (MParticleApiClientImpl.MPThrottleException e) { + if (mMessageManager != null && mMessageManager.getUploadCallback() != null) { + mMessageManager.getUploadCallback().onFailed(); + } } catch (SSLHandshakeException ssle) { Logger.debug("SSL handshake failed while preparing uploads - possible MITM attack detected."); + if (mMessageManager != null && mMessageManager.getUploadCallback() != null) { + mMessageManager.getUploadCallback().onFailed(); + } } catch (MParticleApiClientImpl.MPConfigException e) { Logger.error("Bad API request - is the correct API key and secret configured?"); + if (mMessageManager != null && mMessageManager.getUploadCallback() != null) { + mMessageManager.getUploadCallback().onFailed(); + } } catch (Exception e) { Logger.error(e, "Error processing batch uploads in mParticle DB."); + if (mMessageManager != null && mMessageManager.getUploadCallback() != null) { + mMessageManager.getUploadCallback().onFailed(); + } } return processingSessionEnd; } diff --git a/android-core/src/test/kotlin/com/mparticle/internal/MessageManagerTest.kt b/android-core/src/test/kotlin/com/mparticle/internal/MessageManagerTest.kt index cb7b030ea..0e0a80e5b 100644 --- a/android-core/src/test/kotlin/com/mparticle/internal/MessageManagerTest.kt +++ b/android-core/src/test/kotlin/com/mparticle/internal/MessageManagerTest.kt @@ -18,8 +18,8 @@ import org.json.JSONArray import org.json.JSONException import org.json.JSONObject import org.junit.Assert +import org.junit.Assert.assertNotNull import org.junit.Before -import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mockito @@ -30,8 +30,11 @@ import java.io.PrintWriter import java.io.StringWriter import java.util.Random import java.util.concurrent.atomic.AtomicLong +import kotlin.test.Test +import kotlin.test.assertNull @RunWith(PowerMockRunner::class) +@PrepareForTest(MessageManager::class) class MessageManagerTest { private lateinit var context: MockContext private lateinit var configManager: ConfigManager @@ -545,6 +548,32 @@ class MessageManagerTest { ) } + @Test + @Throws(Exception::class) + fun testDoUpload_With_callback() { + val mockCallback = Mockito.mock(MParticle.UploadCallback::class.java) + manager.doUpload(mockCallback) + Mockito.verify(messageHandler, Mockito.times(1)).sendMessage( + Mockito.any( + Message::class.java + ) + ) + assertNotNull(manager.uploadCallback) + } + + @Test + @Throws(Exception::class) + fun testDoUpload_With_set_NUll_callback() { + manager.uploadCallback = null + manager.doUpload() + Mockito.verify(messageHandler, Mockito.times(1)).sendMessage( + Mockito.any( + Message::class.java + ) + ) + assertNull(manager.uploadCallback) + } + @Test @Throws(Exception::class) fun testSetLocation() { diff --git a/android-core/src/test/kotlin/com/mparticle/internal/UploadHandlerTest.kt b/android-core/src/test/kotlin/com/mparticle/internal/UploadHandlerTest.kt index 9f9dccf56..0db6291f8 100644 --- a/android-core/src/test/kotlin/com/mparticle/internal/UploadHandlerTest.kt +++ b/android-core/src/test/kotlin/com/mparticle/internal/UploadHandlerTest.kt @@ -30,8 +30,11 @@ import org.powermock.api.mockito.PowerMockito import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner import java.io.IOException +import java.lang.reflect.Field import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit +import kotlin.test.assertNotNull +import kotlin.test.assertNull @RunWith(PowerMockRunner::class) class UploadHandlerTest { @@ -180,6 +183,54 @@ class UploadHandlerTest { Mockito.verify(mockApiClient).sendMessageBatch(Mockito.eq("a message batch")) } + @Test + @Throws(Exception::class) + fun testUploadWithCallBack_OnComplete() { + handler.handleMessage(Message()) + val mockMessageManager = Mockito.mock(MessageManager::class.java) + val mockCallback = Mockito.mock(MParticle.UploadCallback::class.java) + Mockito.`when`(mockMessageManager.uploadCallback).thenReturn(mockCallback) + val field: Field = UploadHandler::class.java.getDeclaredField("mMessageManager") + field.apply { + isAccessible = true + } + field.set(handler, mockMessageManager) + + Mockito.`when`(mConfigManager.includeSessionHistory).thenReturn(false) + val mockCursor = Mockito.mock( + Cursor::class.java + ) + Mockito.`when`(mockCursor.moveToNext()).thenReturn(true, false) + Mockito.`when`(mockCursor.getInt(Mockito.anyInt())).thenReturn(123) + Mockito.`when`(mockCursor.getString(Mockito.anyInt())).thenReturn("cool message batch!") + handler.upload(true) + assertNotNull(field.get(handler)) + } + + @Test + @Throws(Exception::class) + fun testUpload_When_MessageManager_IS_NULL() { + handler.handleMessage(Message()) + val mockMessageManager = Mockito.mock(MessageManager::class.java) + val mockCallback = Mockito.mock(MParticle.UploadCallback::class.java) + Mockito.`when`(mockMessageManager.uploadCallback).thenReturn(mockCallback) + val field: Field = UploadHandler::class.java.getDeclaredField("mMessageManager") + field.apply { + isAccessible = true + } + field.set(handler, null) + + Mockito.`when`(mConfigManager.includeSessionHistory).thenReturn(false) + val mockCursor = Mockito.mock( + Cursor::class.java + ) + Mockito.`when`(mockCursor.moveToNext()).thenReturn(true, false) + Mockito.`when`(mockCursor.getInt(Mockito.anyInt())).thenReturn(123) + Mockito.`when`(mockCursor.getString(Mockito.anyInt())).thenReturn("cool message batch!") + handler.upload(true) + assertNull(field.get(handler)) + } + @Test @Throws( IOException::class,