From 604c1b976e753a282bf0173b559f0427c144fe47 Mon Sep 17 00:00:00 2001 From: mchuangatmp <85254535+mchuangatmp@users.noreply.github.com> Date: Wed, 12 Oct 2022 08:31:28 -0700 Subject: [PATCH] fix: Convert MParticleTest.java file to kotlin and fix failing test (#251) --- .../java/com/mparticle/MParticleTest.java | 410 ------------------ .../kotlin/com.mparticle/MParticleTest.kt | 390 +++++++++++++++++ .../MParticleIdentityClientImplTest.kt | 4 +- .../main/java/com/mparticle/MParticle.java | 45 +- .../mparticle/internal/MessageManager.java | 5 +- .../main/java/com/mparticle/AccessUtils.java | 4 - 6 files changed, 416 insertions(+), 442 deletions(-) delete mode 100644 android-core/src/androidTest/java/com/mparticle/MParticleTest.java create mode 100644 android-core/src/androidTest/kotlin/com.mparticle/MParticleTest.kt diff --git a/android-core/src/androidTest/java/com/mparticle/MParticleTest.java b/android-core/src/androidTest/java/com/mparticle/MParticleTest.java deleted file mode 100644 index 1960068bd..000000000 --- a/android-core/src/androidTest/java/com/mparticle/MParticleTest.java +++ /dev/null @@ -1,410 +0,0 @@ -package com.mparticle; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.content.Context; -import android.content.SharedPreferences; -import android.location.Location; -import android.os.Handler; -import android.os.Looper; -import android.webkit.WebView; - -import com.mparticle.identity.IdentityApiRequest; -import com.mparticle.identity.IdentityStateListener; -import com.mparticle.identity.MParticleUser; -import com.mparticle.internal.ConfigManager; -import com.mparticle.internal.KitFrameworkWrapper; -import com.mparticle.internal.MParticleJSInterface; -import com.mparticle.internal.MessageManager; -import com.mparticle.internal.PushRegistrationHelper; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; -import com.mparticle.testutils.TestingUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; -import org.junit.Assert; - -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - -public class MParticleTest extends BaseCleanStartedEachTest { - private String configResponse = "{\"dt\":\"ac\", \"id\":\"fddf1f96-560e-41f6-8f9b-ddd070be0765\", \"ct\":1434392412994, \"dbg\":false, \"cue\":\"appdefined\", \"pmk\":[\"mp_message\", \"com.urbanairship.push.ALERT\", \"alert\", \"a\", \"message\"], \"cnp\":\"appdefined\", \"soc\":0, \"oo\":false, \"eks\":[] }, \"pio\":30 }"; - - @Test - public void testEnsureSessionActive() { - MParticle.getInstance().mAppStateManager.ensureActiveSession(); - ensureSessionActive(); - } - - @Test - public void testEnsureSessionActiveAtStart() { - assertFalse(MParticle.getInstance().isSessionActive()); - } - - @Test - public void testSessionEndsOnOptOut() { - MParticle.getInstance().mAppStateManager.ensureActiveSession(); - assertTrue(MParticle.getInstance().mAppStateManager.getSession().isActive()); - MParticle.getInstance().setOptOut(true); - assertFalse(MParticle.getInstance().mAppStateManager.getSession().isActive()); - } - - @Test - public void testSetInstallReferrer() { - MParticle.getInstance().setInstallReferrer("foo install referrer"); - Assert.assertEquals("foo install referrer", MParticle.getInstance().getInstallReferrer()); - } - - @Test - public void testInstallReferrerUpdate() { - String randomName = mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(4, 64)); - MParticle.getInstance().setInstallReferrer(randomName); - assertTrue(MParticle.getInstance().getInstallReferrer().equals(randomName)); - } - - /** - * These tests are to make sure that we are not missing any instances of the InstallReferrer - * being set at any of the entry points, without the corresponding installReferrerUpdated() calls - * being made. - * @throws Exception - */ - @Test - public void testCalledUpdateInstallReferrer() throws Exception { - final boolean[] called = new boolean[2]; - MParticle.getInstance().mMessageManager = new MessageManager(){ - @Override - public void installReferrerUpdated() { - called[0] = true; - } - }; - - MParticle.getInstance().mKitManager = new KitFrameworkWrapper(mContext, null,null, null, true, null) { - @Override - public void installReferrerUpdated() { - called[1] = true; - } - }; - - //Test when the InstallReferrer is set directly on the InstallReferrerHelper. - String installReferrer = mRandomUtils.getAlphaNumericString(10); - InstallReferrerHelper.setInstallReferrer(mContext, installReferrer); - - assertTrue(called[0]); - assertTrue(called[1]); - - Arrays.fill(called, false); - - //Test when it is set through the MParticle object in the public API. - installReferrer = mRandomUtils.getAlphaNumericString(10); - MParticle.getInstance().setInstallReferrer(installReferrer); - - assertTrue(called[0]); - assertTrue(called[1]); - - Arrays.fill(called, false); - - //Just a sanity check, if Context is null, it should not set mark the InstallReferrer as updated. - installReferrer = mRandomUtils.getAlphaNumericString(10); - InstallReferrerHelper.setInstallReferrer(null, installReferrer); - - org.junit.Assert.assertFalse(called[0]); - org.junit.Assert.assertFalse(called[1]); - } - - @Test - public void testRegisterWebView() throws JSONException, InterruptedException { - MParticle.setInstance(null); - final String token = mRandomUtils.getAlphaNumericString(15); - mServer.setupConfigResponse(new JSONObject().put(ConfigManager.WORKSPACE_TOKEN, token).toString()); - startMParticle(); - final Map jsInterfaces = new HashMap(); - final MPLatch latch = new MPLatch(1); - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - WebView webView = new WebView(mContext) { - - @Override - public void addJavascriptInterface(Object object, String name) { - jsInterfaces.put(name, object); - } - }; - - MParticle.getInstance().registerWebView(webView); - assertTrue(jsInterfaces.get(MParticleJSInterface.INTERFACE_BASE_NAME + "_" + token+ "_v2") instanceof MParticleJSInterface); - - String clientToken = mRandomUtils.getAlphaNumericString(15); - MParticle.getInstance().registerWebView(webView, clientToken); - assertTrue(jsInterfaces.get(MParticleJSInterface.INTERFACE_BASE_NAME + "_" + clientToken + "_v2") instanceof MParticleJSInterface); - latch.countDown(); - } - }); - latch.await(); - assertEquals(2, jsInterfaces.size()); - } - - private void ensureSessionActive() { - if (!MParticle.getInstance().isSessionActive()) { - MParticle.getInstance().logEvent(TestingUtils.getInstance().getRandomMPEventSimple()); - assertTrue(MParticle.getInstance().isSessionActive()); - } - } - - @OrchestratorOnly - @Test - public void testResetSync() throws JSONException, InterruptedException { - testReset(new Runnable() { - @Override - public void run() { - MParticle.reset(mContext); - } - }); - } - - @OrchestratorOnly - @Test - public void testResetAsync() throws JSONException, InterruptedException { - testReset(new Runnable() { - @Override - public void run() { - final CountDownLatch latch = new MPLatch(1); - MParticle.reset(mContext, new MParticle.ResetListener() { - @Override - public void onReset() { - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }); - } - - @OrchestratorOnly - @Test - public void testResetIdentitySync() throws JSONException, InterruptedException { - testResetIdentityCall(new Runnable() { - @Override - public void run() { - MParticle.reset(mContext); - } - }); - } - - @OrchestratorOnly - @Test - public void testResetIdentityAsync() throws JSONException, InterruptedException { - testResetIdentityCall(new Runnable() { - @Override - public void run() { - final CountDownLatch latch = new MPLatch(1); - MParticle.reset(mContext, new MParticle.ResetListener() { - @Override - public void onReset() { - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }); - } - - @OrchestratorOnly - @Test - public void testResetConfigCall() throws InterruptedException { - mServer.setupConfigResponse(configResponse, 100); - MParticle.getInstance().refreshConfiguration(); - MParticle.reset(mContext); - //This sleep is here just to - Thread.sleep(100); - assertSDKGone(); - } - - - /** - * Test that Identity calls in progress will exit gracefully, and not trigger any callbacks. - */ - public void testResetIdentityCall(Runnable resetRunnable) throws InterruptedException { - final boolean[] called = new boolean[2]; - IdentityStateListener crashListener = new IdentityStateListener() { - @Override - public void onUserIdentified(MParticleUser user, MParticleUser previousUser) { - assertTrue(called[0]); - throw new IllegalStateException("Should not be getting callbacks after reset"); - } - }; - - mServer.setupHappyIdentify(ran.nextLong(), 100); - MParticle.getInstance().Identity().addIdentityStateListener(crashListener); - MParticle.getInstance().Identity().identify(IdentityApiRequest.withEmptyUser().build()); - - called[0] = true; - mServer.waitForVerify(new Matcher(mServer.Endpoints().getIdentifyUrl())); - - resetRunnable.run(); - - assertSDKGone(); - } - - @Test - public void testPushEnabledApi() throws InterruptedException { - String senderId = "senderId"; - startMParticle(); - MParticle.getInstance().Messaging().enablePushNotifications(senderId); - String fetchedSenderId = MParticle.getInstance().Internal().getConfigManager().getPushSenderId(); - assertTrue(MParticle.getInstance().Internal().getConfigManager().isPushEnabled()); - - assertEquals(senderId, fetchedSenderId); - - String otherSenderId = "senderIdLogPushRegistration"; - MParticle.getInstance().logPushRegistration("instanceId", otherSenderId); - fetchedSenderId = MParticle.getInstance().Internal().getConfigManager().getPushSenderId(); - assertEquals(otherSenderId, fetchedSenderId); - - MParticle.getInstance().Messaging().disablePushNotifications(); - fetchedSenderId = MParticle.getInstance().Internal().getConfigManager().getPushSenderId(); - assertFalse(MParticle.getInstance().Internal().getConfigManager().isPushEnabled()); - assertNull(fetchedSenderId); - } - - @Test - public void testLogPushRegistrationModifyMessages() throws InterruptedException { - PushRegistrationTest pushRegistrationTest = new PushRegistrationTest().setServer(mServer); - pushRegistrationTest.setContext(mContext); - for (final PushRegistrationTest.SetPush setPush: pushRegistrationTest.setPushes) { - final PushRegistrationHelper.PushRegistration oldRegistration = new PushRegistrationHelper.PushRegistration(mRandomUtils.getAlphaNumericString(10), mRandomUtils.getAlphaNumericString(15)); - setPush.setPushRegistration(oldRegistration); - final PushRegistrationHelper.PushRegistration newPushRegistration = new PushRegistrationHelper.PushRegistration(mRandomUtils.getAlphaNumericString(10), mRandomUtils.getAlphaNumericString(15)); - final CountDownLatch latch = new MPLatch(1); - final AndroidUtils.Mutable received = new AndroidUtils.Mutable(false); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getModifyUrl(mStartingMpid)).bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject jsonObject) { - if (jsonObject.has("identity_changes")) { - try { - JSONArray identityChanges = jsonObject.getJSONArray("identity_changes"); - assertEquals(1, identityChanges.length()); - JSONObject identityChange = identityChanges.getJSONObject(0); - String failureMessage = "When " + oldRegistration + " set with: " + setPush.getName(); - - //This is a wierd case. We might be setting the old pushRegistration with "logPushRegistration()", - //which will kick of its own modify request. We want to ignore this if this is the case. - if (identityChange.getString("new_value").equals(oldRegistration.instanceId)) { - return false; - } - assertEquals(failureMessage, oldRegistration.instanceId, identityChange.getString("old_value")); - assertEquals(failureMessage, newPushRegistration.instanceId, identityChange.getString("new_value")); - assertEquals(failureMessage, "push_token", identityChange.getString("identity_type")); - } catch (JSONException jse) { - jse.toString(); - } - return true; - } - return false; - } - }), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - received.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().logPushRegistration(newPushRegistration.instanceId, newPushRegistration.senderId); - latch.await(); - } - } - - @Test - public void testSetLocation() { - Location location = new Location(""); - MParticle.getInstance().setLocation(location); - assertEquals(location, MParticle.getInstance().mMessageManager.getLocation()); - MParticle.getInstance().setLocation(null); - assertNull(MParticle.getInstance().mMessageManager.getLocation()); - } - - private void testReset(Runnable resetRunnable) throws JSONException, InterruptedException { - for (int i = 0; i < 10; i++) { - MParticle.getInstance().logEvent(TestingUtils.getInstance().getRandomMPEventRich()); - } - for (int i = 0; i < 10; i++) { - MParticle.getInstance().Internal().getConfigManager().setMpid(ran.nextLong(), ran.nextBoolean()); - } - JSONObject databaseJson = getDatabaseContents(Collections.singletonList("messages")); - assertTrue(databaseJson.getJSONArray("messages").length() > 0); - assertEquals(6, getAllTables().size()); - assertTrue(10 < MParticle.getInstance().Internal().getConfigManager().getMpids().size()); - - //Set strict mode, so if we get any warning or error messages during the reset/restart phase, - //it will throw an exception. - TestingUtils.setStrictMode(MParticle.LogLevel.WARNING); - - resetRunnable.run(); - assertSDKGone(); - - //Restart the SDK, to the point where the initial Identity call returns, make sure there are no errors on startup. - TestingUtils.setStrictMode(MParticle.LogLevel.WARNING, "Failed to get MParticle instance, getInstance() called prior to start()."); - beforeBase(); - } - - private void assertSDKGone() { - //Check post-reset state: - //should be 2 entries in default SharedPreferences (the install boolean and the original install time) - //and 0 other SharedPreferences tables. - //Make sure the 2 entries in default SharedPreferences are the correct values. - //0 tables should exist. - //Then we call DatabaseHelper.getInstance(Context).openDatabase, which should create the database, - //and make sure it is created without an error message, and that all the tables are empty. - String sharedPrefsDirectory = mContext.getFilesDir().getPath().replace("files", "shared_prefs/"); - File[] files = new File(sharedPrefsDirectory).listFiles(); - for (File file : files) { - String sharedPreferenceName = file.getPath().replace(sharedPrefsDirectory, "").replace(".xml", ""); - if (!sharedPreferenceName.equals("WebViewChromiumPrefs") && !sharedPreferenceName.equals("com.mparticle.test_preferences")) { - fail("SharedPreference file failed to clear:\n" + getSharedPrefsContents(sharedPreferenceName)); - } - } - assertEquals(0, mContext.databaseList().length); - try { - JSONObject databaseJson = getDatabaseContents(); - Iterator keys = databaseJson.keys(); - while (keys.hasNext()) { - String key = keys.next(); - assertEquals(key, 0, databaseJson.getJSONArray(key).length()); - } - } catch (JSONException e) { - fail(e.getMessage()); - } - } - - private String getSharedPrefsContents(String name) { - try { - SharedPreferences prefs = mContext.getSharedPreferences(name, Context.MODE_PRIVATE); - return name + ":\n" + new JSONObject(prefs.getAll()).toString(4); - } catch (JSONException e) { - return "error printing SharedPrefs :/"; - } - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/kotlin/com.mparticle/MParticleTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/MParticleTest.kt new file mode 100644 index 000000000..9172d49a0 --- /dev/null +++ b/android-core/src/androidTest/kotlin/com.mparticle/MParticleTest.kt @@ -0,0 +1,390 @@ +package com.mparticle + +import android.content.Context +import android.location.Location +import android.os.Handler +import android.os.Looper +import android.webkit.WebView +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.identity.IdentityStateListener +import com.mparticle.internal.ConfigManager +import com.mparticle.internal.KitFrameworkWrapper +import com.mparticle.internal.MParticleJSInterface +import com.mparticle.internal.MessageManager +import com.mparticle.internal.PushRegistrationHelper.PushRegistration +import com.mparticle.networking.Matcher +import com.mparticle.networking.MockServer.JSONMatch +import com.mparticle.testutils.AndroidUtils +import com.mparticle.testutils.BaseCleanStartedEachTest +import com.mparticle.testutils.MPLatch +import com.mparticle.testutils.TestingUtils +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Test +import java.io.File +import java.util.Arrays +import java.util.concurrent.CountDownLatch +import kotlin.collections.HashMap + +class MParticleTest : BaseCleanStartedEachTest() { + private val configResponse = + "{\"dt\":\"ac\", \"id\":\"fddf1f96-560e-41f6-8f9b-ddd070be0765\", \"ct\":1434392412994, \"dbg\":false, \"cue\":\"appdefined\", \"pmk\":[\"mp_message\", \"com.urbanairship.push.ALERT\", \"alert\", \"a\", \"message\"], \"cnp\":\"appdefined\", \"soc\":0, \"oo\":false, \"eks\":[] }, \"pio\":30 }" + + @Test + fun testEnsureSessionActive() { + MParticle.getInstance()!!.mAppStateManager.ensureActiveSession() + ensureSessionActive() + } + + @Test + fun testEnsureSessionActiveAtStart() { + Assert.assertFalse(MParticle.getInstance()!!.isSessionActive) + } + + @Test + fun testSessionEndsOnOptOut() { + MParticle.getInstance()!!.mAppStateManager.ensureActiveSession() + Assert.assertTrue(MParticle.getInstance()!!.mAppStateManager.session.isActive) + MParticle.getInstance()!!.optOut = true + Assert.assertFalse(MParticle.getInstance()!!.mAppStateManager.session.isActive) + } + + @Test + fun testSetInstallReferrer() { + MParticle.getInstance()!!.installReferrer = "foo install referrer" + Assert.assertEquals("foo install referrer", MParticle.getInstance()!!.installReferrer) + } + + @Test + fun testInstallReferrerUpdate() { + val randomName = mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(4, 64)) + MParticle.getInstance()!!.installReferrer = randomName + Assert.assertTrue(MParticle.getInstance()!!.installReferrer == randomName) + } + + /** + * These tests are to make sure that we are not missing any instances of the InstallReferrer + * being set at any of the entry points, without the corresponding installReferrerUpdated() calls + * being made. + * @throws Exception + */ + @Test + @Throws(Exception::class) + fun testCalledUpdateInstallReferrer() { + val called = BooleanArray(2) + MParticle.getInstance()!!.mMessageManager = object : MessageManager() { + override fun installReferrerUpdated() { + called[0] = true + } + } + MParticle.getInstance()!!.mKitManager = + object : KitFrameworkWrapper(mContext, null, null, null, true, null) { + override fun installReferrerUpdated() { + called[1] = true + } + } + + // Test when the InstallReferrer is set directly on the InstallReferrerHelper. + var installReferrer = mRandomUtils.getAlphaNumericString(10) + InstallReferrerHelper.setInstallReferrer(mContext, installReferrer) + Assert.assertTrue(called[0]) + Assert.assertTrue(called[1]) + Arrays.fill(called, false) + + // Test when it is set through the MParticle object in the public API. + installReferrer = mRandomUtils.getAlphaNumericString(10) + MParticle.getInstance()!!.installReferrer = installReferrer + Assert.assertTrue(called[0]) + Assert.assertTrue(called[1]) + Arrays.fill(called, false) + + // Just a sanity check, if Context is null, it should not set mark the InstallReferrer as updated. + installReferrer = mRandomUtils.getAlphaNumericString(10) + // InstallReferrerHelper.setInstallReferrer(null, installReferrer) //function does nothing when context is null + Assert.assertFalse(called[0]) + Assert.assertFalse(called[1]) + } + + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testRegisterWebView() { + MParticle.setInstance(null) + val token = mRandomUtils.getAlphaNumericString(15) + mServer.setupConfigResponse( + JSONObject().put(ConfigManager.WORKSPACE_TOKEN, token).toString() + ) + startMParticle() + val jsInterfaces: MutableMap = HashMap() + val latch = MPLatch(1) + Handler(Looper.getMainLooper()).post { + val webView: WebView = object : WebView(mContext) { + override fun addJavascriptInterface(`object`: Any, name: String) { + jsInterfaces[name] = `object` + } + } + MParticle.getInstance()!!.registerWebView(webView) + Assert.assertTrue(jsInterfaces[MParticleJSInterface.INTERFACE_BASE_NAME + "_" + token + "_v2"] is MParticleJSInterface) + val clientToken = mRandomUtils.getAlphaNumericString(15) + MParticle.getInstance()!!.registerWebView(webView, clientToken) + Assert.assertTrue(jsInterfaces[MParticleJSInterface.INTERFACE_BASE_NAME + "_" + clientToken + "_v2"] is MParticleJSInterface) + latch.countDown() + } + latch.await() + Assert.assertEquals(2, jsInterfaces.size.toLong()) + } + + private fun ensureSessionActive() { + if (!MParticle.getInstance()!!.isSessionActive) { + MParticle.getInstance()!!.logEvent(TestingUtils.getInstance().randomMPEventSimple) + Assert.assertTrue(MParticle.getInstance()!!.isSessionActive) + } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetSync() { + testReset { MParticle.reset(mContext) } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetAsync() { + testReset { + val latch: CountDownLatch = MPLatch(1) + MParticle.reset(mContext) { latch.countDown() } + try { + latch.await() + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetIdentitySync() { + testResetIdentityCall { MParticle.reset(mContext) } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetIdentityAsync() { + testResetIdentityCall { + val latch: CountDownLatch = MPLatch(1) + MParticle.reset(mContext) { latch.countDown() } + try { + latch.await() + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + } + + @OrchestratorOnly + @Test + @Throws(InterruptedException::class) + fun testResetConfigCall() { + mServer.setupConfigResponse(configResponse, 100) + MParticle.getInstance()!!.refreshConfiguration() + MParticle.reset(mContext) + // This sleep is here just to + Thread.sleep(100) + assertSDKGone() + } + + /** + * Test that Identity calls in progress will exit gracefully, and not trigger any callbacks. + */ + @Throws(InterruptedException::class) + fun testResetIdentityCall(resetRunnable: Runnable) { + val called = BooleanArray(2) + val crashListener = IdentityStateListener { user, previousUser -> + Assert.assertTrue(called[0]) + throw IllegalStateException("Should not be getting callbacks after reset") + } + mServer.setupHappyIdentify(ran.nextLong(), 100) + MParticle.getInstance()!!.Identity().addIdentityStateListener(crashListener) + MParticle.getInstance()!!.Identity().identify(IdentityApiRequest.withEmptyUser().build()) + called[0] = true + mServer.waitForVerify(Matcher(mServer.Endpoints().identifyUrl)) + resetRunnable.run() + assertSDKGone() + } + + @Test + @Throws(InterruptedException::class) + fun testPushEnabledApi() { + val senderId = "senderId" + startMParticle() + MParticle.getInstance()!!.Messaging().enablePushNotifications(senderId) + var fetchedSenderId: String? = + MParticle.getInstance()!!.mInternal.getConfigManager().getPushSenderId() + Assert.assertTrue(MParticle.getInstance()!!.mInternal.getConfigManager().isPushEnabled() ?: false) + Assert.assertEquals(senderId, fetchedSenderId) + val otherSenderId = "senderIdLogPushRegistration" + MParticle.getInstance()!!.logPushRegistration("instanceId", otherSenderId) + fetchedSenderId = MParticle.getInstance()!!.mInternal.getConfigManager().getPushSenderId() + Assert.assertEquals(otherSenderId, fetchedSenderId) + MParticle.getInstance()!!.Messaging().disablePushNotifications() + fetchedSenderId = MParticle.getInstance()!!.mInternal.getConfigManager().getPushSenderId() + Assert.assertFalse(MParticle.getInstance()!!.mInternal.getConfigManager().isPushEnabled() ?: false) + Assert.assertNull(fetchedSenderId) + } + + @Test + @Throws(InterruptedException::class) + fun testLogPushRegistrationModifyMessages() { + val pushRegistrationTest = PushRegistrationTest().setServer(mServer) + pushRegistrationTest.setContext(mContext) + for (setPush in pushRegistrationTest.setPushes) { + val oldRegistration = PushRegistration( + mRandomUtils.getAlphaNumericString(10), + mRandomUtils.getAlphaNumericString(15) + ) + setPush.setPushRegistration(oldRegistration) + val newPushRegistration = PushRegistration( + mRandomUtils.getAlphaNumericString(10), + mRandomUtils.getAlphaNumericString(15) + ) + val latch: CountDownLatch = MPLatch(1) + val received = AndroidUtils.Mutable(false) + mServer.waitForVerify( + Matcher(mServer.Endpoints().getModifyUrl(mStartingMpid)).bodyMatch( + JSONMatch { jsonObject -> + if (jsonObject.has("identity_changes")) { + try { + val identityChanges = jsonObject.getJSONArray("identity_changes") + Assert.assertEquals(1, identityChanges.length().toLong()) + val identityChange = identityChanges.getJSONObject(0) + val failureMessage = + "When " + oldRegistration + " set with: " + setPush.name + + // This is a wierd case. We might be setting the old pushRegistration with "logPushRegistration()", + // which will kick of its own modify request. We want to ignore this if this is the case. + if (identityChange.getString("new_value") == oldRegistration.instanceId) { + return@JSONMatch false + } + Assert.assertEquals( + failureMessage, + oldRegistration.instanceId, + identityChange.getString("old_value") + ) + Assert.assertEquals( + failureMessage, + newPushRegistration.instanceId, + identityChange.getString("new_value") + ) + Assert.assertEquals( + failureMessage, + "push_token", + identityChange.getString("identity_type") + ) + } catch (jse: JSONException) { + jse.toString() + } + return@JSONMatch true + } + false + } + ) + ) { + received.value = true + latch.countDown() + } + MParticle.getInstance()!! + .logPushRegistration(newPushRegistration.instanceId, newPushRegistration.senderId) + latch.await() + } + } + + @Test + fun testSetLocation() { + val location = Location("") + MParticle.getInstance()!!.setLocation(location) + Assert.assertEquals(location, MParticle.getInstance()!!.mMessageManager.location) + MParticle.getInstance()!!.setLocation(null) + Assert.assertNull(MParticle.getInstance()!!.mMessageManager.location) + } + + @Throws(JSONException::class, InterruptedException::class) + private fun testReset(resetRunnable: Runnable) { + for (i in 0..9) { + MParticle.getInstance()!!.logEvent(TestingUtils.getInstance().randomMPEventRich) + } + for (i in 0..9) { + MParticle.getInstance()!!.mInternal.getConfigManager() + .setMpid(ran.nextLong(), ran.nextBoolean()) + } + val databaseJson = getDatabaseContents(listOf("messages")) + Assert.assertTrue(databaseJson.getJSONArray("messages").length() > 0) + Assert.assertEquals(6, allTables.size.toLong()) + Assert.assertTrue( + 10 < (MParticle.getInstance()!!.mInternal.getConfigManager().getMpids()?.size ?: 0) + ) + + // Set strict mode, so if we get any warning or error messages during the reset/restart phase, + // it will throw an exception. + TestingUtils.setStrictMode(MParticle.LogLevel.WARNING) + resetRunnable.run() + assertSDKGone() + + // Restart the SDK, to the point where the initial Identity call returns, make sure there are no errors on startup. + TestingUtils.setStrictMode( + MParticle.LogLevel.WARNING, + "Failed to get MParticle instance, getInstance() called prior to start()." + ) + beforeBase() + } + + private fun assertSDKGone() { + // Check post-reset state: + // should be 2 entries in default SharedPreferences (the install boolean and the original install time) + // and 0 other SharedPreferences tables. + // Make sure the 2 entries in default SharedPreferences are the correct values. + // 0 tables should exist. + // Then we call DatabaseHelper.getInstance(Context).openDatabase, which should create the database, + // and make sure it is created without an error message, and that all the tables are empty. + val sharedPrefsDirectory = mContext.filesDir.path.replace("files", "shared_prefs/") + val files = File(sharedPrefsDirectory).listFiles() + files?.iterator()?.forEach { file -> + val sharedPreferenceName = + file.path.replace(sharedPrefsDirectory, "").replace(".xml", "") + if (sharedPreferenceName != "WebViewChromiumPrefs" && sharedPreferenceName != "com.mparticle.test_preferences") { + Assert.fail( + """ + SharedPreference file failed to clear: + ${getSharedPrefsContents(sharedPreferenceName)} + """.trimIndent() + ) + } + } + Assert.assertEquals(0, mContext.databaseList().size.toLong()) + try { + val databaseJson = databaseContents + val keys = databaseJson.keys() + while (keys.hasNext()) { + val key = keys.next() + Assert.assertEquals(key, 0, databaseJson.getJSONArray(key).length().toLong()) + } + } catch (e: JSONException) { + Assert.fail(e.message) + } + } + + private fun getSharedPrefsContents(name: String): String { + return try { + val prefs = mContext.getSharedPreferences(name, Context.MODE_PRIVATE) + """ + $name: + ${JSONObject(prefs.all).toString(4)} + """.trimIndent() + } catch (e: JSONException) { + "error printing SharedPrefs :/" + } + } +} diff --git a/android-core/src/androidTest/kotlin/com.mparticle/identity/MParticleIdentityClientImplTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/identity/MParticleIdentityClientImplTest.kt index 8fe569315..5d030b005 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/identity/MParticleIdentityClientImplTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/identity/MParticleIdentityClientImplTest.kt @@ -313,14 +313,14 @@ class MParticleIdentityClientImplTest : BaseCleanStartedEachTest() { private fun checkStaticsAndRemove(knowIdentites: JSONObject) { if (knowIdentites.has(MParticleIdentityClientImpl.ANDROID_AAID)) { Assert.assertEquals( - MPUtility.getAdIdInfo(mContext).id, + MPUtility.getAdIdInfo(mContext)?.id, knowIdentites.getString(MParticleIdentityClientImpl.ANDROID_AAID) ) knowIdentites.remove(MParticleIdentityClientImpl.ANDROID_AAID) } else { Assert.assertTrue( MPUtility.getAdIdInfo(mContext) == null || MPUtility.isEmpty( - MPUtility.getAdIdInfo(mContext).id + MPUtility.getAdIdInfo(mContext)?.id ) ) } diff --git a/android-core/src/main/java/com/mparticle/MParticle.java b/android-core/src/main/java/com/mparticle/MParticle.java index 855d7c280..36c1f6e75 100644 --- a/android-core/src/main/java/com/mparticle/MParticle.java +++ b/android-core/src/main/java/com/mparticle/MParticle.java @@ -1143,20 +1143,22 @@ static void reset(@NonNull Context context, boolean deleteDatabase) { String sharedPrefsDirectory = context.getFilesDir().getPath().replace("files", "shared_prefs/"); File[] files = new File(sharedPrefsDirectory).listFiles(); - for (File file : files) { - String sharedPreferenceName = file.getPath().replace(sharedPrefsDirectory, "").replace(".xml", ""); - // it is going to be difficult/impossible to come up with a finite list of Kit SharedPreference files, with the custom kits - // coming, so we will look for any kit shared preference files by their prefix "mp::kit::" - if (sharedPreferenceName.startsWith("mp::kit::") - || sharedPreferenceName.startsWith(ConfigManager.PREFERENCES_FILE + ":") - || prefFiles.contains(sharedPreferenceName)) { - SharedPreferences sharedPreferences = context.getSharedPreferences(sharedPreferenceName, Context.MODE_PRIVATE); - if (sharedPreferences != null) { - sharedPreferences.edit() - .clear() - .commit(); + if (files != null && files.length > 0) { + for (File file : files) { + String sharedPreferenceName = file.getPath().replace(sharedPrefsDirectory, "").replace(".xml", ""); + // it is going to be difficult/impossible to come up with a finite list of Kit SharedPreference files, with the custom kits + // coming, so we will look for any kit shared preference files by their prefix "mp::kit::" + if (sharedPreferenceName.startsWith("mp::kit::") + || sharedPreferenceName.startsWith(ConfigManager.PREFERENCES_FILE + ":") + || prefFiles.contains(sharedPreferenceName)) { + SharedPreferences sharedPreferences = context.getSharedPreferences(sharedPreferenceName, Context.MODE_PRIVATE); + if (sharedPreferences != null) { + sharedPreferences.edit() + .clear() + .commit(); + } + file.delete(); } - file.delete(); } } if (deleteDatabase) { @@ -1181,18 +1183,15 @@ static void reset(@NonNull Context context, boolean deleteDatabase) { public static void reset(@NonNull final Context context, @Nullable final ResetListener callback) { final HandlerThread handlerThread = new HandlerThread("mParticleShutdownHandler"); handlerThread.start(); - new Handler(handlerThread.getLooper()).post(new Runnable() { - @Override - public void run() { - reset(context); - if (callback != null) { - try { - callback.onReset(); - } catch (Exception ignored) { - } + new Handler(handlerThread.getLooper()).post(() -> { + reset(context); + if (callback != null) { + try { + callback.onReset(); + } catch (Exception ignored) { } - handlerThread.quit(); } + handlerThread.quit(); }); } 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 a22131d9b..7978009d7 100644 --- a/android-core/src/main/java/com/mparticle/internal/MessageManager.java +++ b/android-core/src/main/java/com/mparticle/internal/MessageManager.java @@ -16,15 +16,14 @@ import android.os.HandlerThread; import android.os.Message; import android.os.Process; -import androidx.annotation.Nullable; import android.telephony.TelephonyManager; +import androidx.annotation.Nullable; + import com.mparticle.InstallReferrerHelper; import com.mparticle.MPEvent; import com.mparticle.MParticle; import com.mparticle.MParticleOptions; -import com.mparticle.UserAttributeListener; -import com.mparticle.UserAttributeListenerType; import com.mparticle.commerce.CommerceEvent; import com.mparticle.identity.AliasRequest; import com.mparticle.identity.UserAttributeListenerWrapper; diff --git a/testutils/src/main/java/com/mparticle/AccessUtils.java b/testutils/src/main/java/com/mparticle/AccessUtils.java index 995681464..75f775240 100644 --- a/testutils/src/main/java/com/mparticle/AccessUtils.java +++ b/testutils/src/main/java/com/mparticle/AccessUtils.java @@ -3,7 +3,6 @@ import android.content.Context; import android.os.Build; import android.os.Message; -import android.os.MessageQueue; import androidx.annotation.RequiresApi; @@ -12,9 +11,6 @@ import com.mparticle.internal.MPUtility; import com.mparticle.internal.MessageManager; -import java.lang.reflect.Field; -import java.util.LinkedList; -import java.util.List; import java.util.Set; public class AccessUtils {