diff --git a/android-core/src/androidTest/AndroidManifest.xml b/android-core/src/androidTest/AndroidManifest.xml index 53a1b887b..80ab2a7ef 100644 --- a/android-core/src/androidTest/AndroidManifest.xml +++ b/android-core/src/androidTest/AndroidManifest.xml @@ -14,7 +14,7 @@ - + diff --git a/android-core/src/androidTest/java/com/mparticle/DataplanTest.java b/android-core/src/androidTest/java/com/mparticle/DataplanTest.java deleted file mode 100644 index 850ca6912..000000000 --- a/android-core/src/androidTest/java/com/mparticle/DataplanTest.java +++ /dev/null @@ -1,236 +0,0 @@ -package com.mparticle; - -import com.mparticle.internal.Constants; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.BaseCleanInstallEachTest; -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 static junit.framework.TestCase.assertNull; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -public class DataplanTest extends BaseCleanInstallEachTest { - TestingUtils testingUtils = TestingUtils.getInstance(); - - - @Test - public void noDataPlanTest() throws InterruptedException { - startMParticle(MParticleOptions.builder(mContext) - .dataplan(null, null)); - - final AndroidUtils.Mutable messageCount = new AndroidUtils.Mutable(0); - final MPLatch latch = new MPLatch(1); - MockServer.getInstance().waitForVerify(new Matcher().bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject bodyJson) { - try { - assertNull(bodyJson.optJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT)); - messageCount.value += getMessageCount(bodyJson); - if (messageCount.value == 3) { - latch.countDown(); - return true; - } - } catch (JSONException ex) {} - return false; - } - }), latch); - - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().upload(); - - latch.await(); - assertEquals(3, messageCount.value.intValue()); - } - - @Test - public void dataplanPartialTest() throws InterruptedException { - startMParticle(MParticleOptions.builder(mContext) - .dataplan("plan1", null)); - - final AndroidUtils.Mutable messageCount = new AndroidUtils.Mutable(0); - final MPLatch latch = new MPLatch(1); - MockServer.getInstance().waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject bodyJson) { - try { - assertNotNull(bodyJson.optJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT)); - JSONObject dataplanContext = bodyJson.getJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT); - JSONObject dataplanJSON = dataplanContext.getJSONObject(Constants.MessageKey.DATA_PLAN_KEY); - assertEquals("plan1", dataplanJSON.getString(Constants.MessageKey.DATA_PLAN_ID)); - assertNull(dataplanJSON.optString(Constants.MessageKey.DATA_PLAN_VERSION, null)); - messageCount.value += getMessageCount(bodyJson); - if (messageCount.value == 3) { - latch.countDown(); - return true; - } - } catch (JSONException ex) {} - return false; - } - }), latch); - - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().upload(); - - latch.await(); - assertEquals(3, messageCount.value.intValue()); - } - - @Test - public void noDataPlanIdTest() throws InterruptedException { - startMParticle(MParticleOptions.builder(mContext) - .dataplan(null, 1)); - - final AndroidUtils.Mutable messageCount = new AndroidUtils.Mutable(0); - final MPLatch latch = new MPLatch(1); - MockServer.getInstance().waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject bodyJson) { - try { - assertNull(bodyJson.optJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT)); - messageCount.value += getMessageCount(bodyJson); - if (messageCount.value == 3) { - latch.countDown(); - return true; - } - } catch (JSONException ex) {} - return false; - } - }), latch); - - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().upload(); - - - latch.await(); - assertEquals(3, messageCount.value.intValue()); - } - - @Test - public void dataPlanSetTest() throws InterruptedException { - startMParticle(MParticleOptions.builder(mContext) - .dataplan("dataplan1", 1)); - - final AndroidUtils.Mutable messageCount = new AndroidUtils.Mutable(0); - final MPLatch latch = new MPLatch(1); - MockServer.getInstance().waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject bodyJson) { - try { - assertNotNull(bodyJson.optJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT)); - JSONObject dataplanContext = bodyJson.getJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT); - JSONObject dataplanJSON = dataplanContext.getJSONObject(Constants.MessageKey.DATA_PLAN_KEY); - assertEquals("dataplan1", dataplanJSON.getString(Constants.MessageKey.DATA_PLAN_ID)); - assertEquals("1", dataplanJSON.optString(Constants.MessageKey.DATA_PLAN_VERSION, null)); - JSONArray messages = bodyJson.optJSONArray("msgs"); - messageCount.value += getMessageCount(bodyJson); - if (messageCount.value == 3) { - latch.countDown(); - return true; - } - } catch (Exception ex) { - fail(ex.toString()); - } - return false; - } - }), latch); - - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().upload(); - - latch.await(); - assertEquals(3, messageCount.value.intValue()); - } - - @Test - public void dataplanChanged() throws InterruptedException { - startMParticle(MParticleOptions.builder(mContext) - .dataplan("dataplan1", 1)); - - final AndroidUtils.Mutable totalMessageCount = new AndroidUtils.Mutable(0); - final AndroidUtils.Mutable dataplan1MessageCount = new AndroidUtils.Mutable(0); - final AndroidUtils.Mutable dataplan2MessageCount = new AndroidUtils.Mutable(0); - final MPLatch latch = new MPLatch(1); - MockServer.getInstance().waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject bodyJson) { - try { - assertNotNull(bodyJson.optJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT)); - JSONObject dataplanContext = bodyJson.getJSONObject(Constants.MessageKey.DATA_PLAN_CONTEXT); - JSONObject dataplanJSON = dataplanContext.getJSONObject(Constants.MessageKey.DATA_PLAN_KEY); - String dataplanId = dataplanJSON.getString(Constants.MessageKey.DATA_PLAN_ID); - Integer dataplanVersion = dataplanJSON.optInt(Constants.MessageKey.DATA_PLAN_VERSION, -1); - - int messageCount = getMessageCount(bodyJson); - if (new Integer(1).equals(dataplanVersion)) { - assertEquals("dataplan1", dataplanId); - dataplan1MessageCount.value += messageCount; - } - if (new Integer(2).equals(dataplanVersion)) { - assertEquals("dataplan1", dataplanId); - dataplan2MessageCount.value += messageCount; - } - totalMessageCount.value += messageCount; - if (totalMessageCount.value == 5) { - latch.countDown(); - } - } catch (Exception ex) { - fail(ex.toString()); - } - return false; - } - }), latch); - - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - - - MParticle.setInstance(null); - startMParticle(MParticleOptions.builder(mContext) - .dataplan("dataplan1", 2)); - - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().logEvent(testingUtils.getRandomMPEventRich()); - MParticle.getInstance().upload(); - - //not sure why it needs upload() twice, but this cuts the runtime down from 10s to .7s - MParticle.getInstance().upload(); - MParticle.getInstance().upload(); - latch.await(); - assertEquals(3, dataplan1MessageCount.value.intValue()); - assertEquals(2, dataplan2MessageCount.value.intValue()); - - assertEquals(5, totalMessageCount.value.intValue()); - } - - private int getMessageCount(JSONObject bodyJson) throws JSONException { - int count = 0; - JSONArray messages = bodyJson.optJSONArray("msgs"); - if (messages != null) { - for (int i = 0; i < messages.length(); i++) { - JSONObject messageJSON = messages.getJSONObject(i); - if (messageJSON.getString("dt").equals("e")) { - count++; - } - } - } - return count; - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/DataplanTest.kt b/android-core/src/androidTest/java/com/mparticle/DataplanTest.kt new file mode 100644 index 000000000..173a846c9 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/DataplanTest.kt @@ -0,0 +1,188 @@ +package com.mparticle + +import com.mparticle.api.Logger +import com.mparticle.messages.events.MPEventMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.Mutable +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.utils.randomMPEventRich +import com.mparticle.utils.startMParticle +import junit.framework.Assert.assertEquals +import org.junit.Test +import kotlin.test.assertNull +import kotlin.test.junit.JUnitAsserter.fail + +class DataplanTest : BaseTest() { + @Test + @Throws(InterruptedException::class) + fun noDataPlanTest() { + startMParticle( + MParticleOptions.builder(context) + .dataplan(null, null) + ) + val messageCount: Mutable = Mutable(0) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + assertNull(it.body.dataplanContext) + it.body.messages + .filterIsInstance().let { + messageCount.value += it.size + messageCount.value == 3 + } + } + .after { + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.upload() + } + .blockUntilFinished() + assertEquals(3, messageCount.value) + Logger.error("finished") + } + + @Test + @Throws(InterruptedException::class) + fun dataplanPartialTest() { + startMParticle( + MParticleOptions.builder(context) + .dataplan("plan1", null) + ) + val messageCount: Mutable = Mutable(0) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + assertEquals("plan1", it.body.dataplanContext?.dataplan?.dataplanId) + assertNull(it.body.dataplanContext?.dataplan?.dataplanVersion) + it.body.messages + .filterIsInstance().let { + messageCount.value += it.size + messageCount.value == 3 + } + } + .after { + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.upload() + } + .blockUntilFinished() + assertEquals(3, messageCount.value) + } + + @Test + @Throws(InterruptedException::class) + fun noDataPlanIdTest() { + startMParticle( + MParticleOptions.builder(context) + .dataplan(null, 1) + ) + val messageCount: Mutable = Mutable(0) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + Logger.error("CALLBACK!!") + assertNull(it.body.dataplanContext) + it.body.messages + .filterIsInstance().let { + messageCount.value += it.size + messageCount.value == 3 + } + } + .after { + MParticle.getInstance()?.apply { + logEvent(randomMPEventRich()) + logEvent(randomMPEventRich()) + logEvent(randomMPEventRich()) + upload() + } + } + .blockUntilFinished() + assertEquals(3, messageCount.value) + } + + @Test + @Throws(InterruptedException::class) + fun dataPlanSetTest() { + startMParticle( + MParticleOptions.builder(context) + .dataplan("dataplan1", 1) + ) + val messageCount: Mutable = Mutable(0) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + assertEquals("dataplan1", it.body.dataplanContext?.dataplan?.dataplanId) + assertEquals(1, it.body.dataplanContext?.dataplan?.dataplanVersion) + it.body.messages + .filterIsInstance().let { + messageCount.value += it.size + messageCount.value == 3 + } + } + .after { + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.logEvent(randomMPEventRich()) + MParticle.getInstance()!!.upload() + } + .blockUntilFinished() + assertEquals(3, messageCount.value) + } + + @Test + @Throws(InterruptedException::class) + fun dataplanChanged() { + startMParticle( + MParticleOptions.builder(context) + .dataplan("dataplan1", 1) + ) + val totalMessageCount: Mutable = Mutable(0) + val dataplan1MessageCount: Mutable = Mutable(0) + val dataplan2MessageCount: Mutable = Mutable(0) + + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + assertEquals("dataplan1", it.body.dataplanContext?.dataplan?.dataplanId) + when (it.body.dataplanContext?.dataplan?.dataplanVersion) { + 1 -> dataplan1MessageCount.value += it.body.messages.filterIsInstance().size + 2 -> dataplan2MessageCount.value += it.body.messages.filterIsInstance().size + else -> fail("Unknown dataplan version: ${it.body.dataplanContext?.dataplan?.dataplanVersion}") + } + it.body.messages + .filterIsInstance().let { + totalMessageCount.value += it.size + totalMessageCount.value == 5 + } + } + .after { + MParticle.getInstance()?.apply { + logEvent(randomMPEventRich()) + logEvent(randomMPEventRich()) + logEvent(randomMPEventRich()) + } + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(context) + .dataplan("dataplan1", 2) + ) + MParticle.getInstance()?.apply { + logEvent(randomMPEventRich()) + logEvent(randomMPEventRich()) + upload() + } + } + .blockUntilFinished() + + // not sure why it needs upload() twice, but this cuts the runtime down from 10s to .7s + MParticle.getInstance()!!.upload() + MParticle.getInstance()!!.upload() + assertEquals(3, dataplan1MessageCount.value) + assertEquals(2, dataplan2MessageCount.value) + assertEquals(5, totalMessageCount.value) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/MParticleITest.kt b/android-core/src/androidTest/java/com/mparticle/MParticleITest.kt new file mode 100644 index 000000000..d7a638735 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/MParticleITest.kt @@ -0,0 +1,400 @@ +package com.mparticle + +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.api.events.toMPEvent +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.identity.IdentityStateListener +import com.mparticle.identity.MParticleUser +import com.mparticle.internal.KitFrameworkWrapper +import com.mparticle.internal.MParticleJSInterface +import com.mparticle.internal.MessageManager +import com.mparticle.internal.PushRegistrationHelper.PushRegistration +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.messages.DTO +import com.mparticle.messages.IdentityResponseMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.TestingUtils +import com.mparticle.testing.Utils.setStrictMode +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse +import com.mparticle.testing.orThrow +import junit.framework.TestCase +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import java.io.File +import java.util.Arrays +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class MParticleITest : BaseStartedTest() { + 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 }""" + .let { + DTO.from(it) + } + @Test + fun testEnsureSessionActive() { + MParticle.getInstance()!!.mAppStateManager.ensureActiveSession() + ensureSessionActive() + } + + @Test + fun testEnsureSessionActiveAtStart() { + Assert.assertFalse(MParticle.getInstance()!!.isSessionActive) + } + + @Test + fun testSessionEndsOnOptOut() { + MParticle.getInstance()!!.mAppStateManager.ensureActiveSession() + 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" + junit.framework.Assert.assertEquals( + "foo install referrer", + MParticle.getInstance()!! + .installReferrer + ) + } + + @Test + fun testInstallReferrerUpdate() { + val randomName: String = RandomUtils.getAlphaNumericString(RandomUtils.randomInt(4, 64)) + MParticle.getInstance()!!.installReferrer = randomName + 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(context, null, null, null, true, null) { + override fun installReferrerUpdated() { + called[1] = true + } + } + + // Test when the InstallReferrer is set directly on the InstallReferrerHelper. + var installReferrer: String = RandomUtils.getAlphaNumericString(10) + InstallReferrerHelper.setInstallReferrer(context, 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 = RandomUtils.getAlphaNumericString(10) + MParticle.getInstance()!!.installReferrer = installReferrer + assertTrue(called[0]) + assertTrue(called[1]) + Arrays.fill(called, false) + } + + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testRegisterWebView() { + MParticle.setInstance(null) + val token: String = RandomUtils.getAlphaNumericString(15) + val setupConfigResponse = Server.endpoint(EndpointType.Config).nextResponse { + SuccessResponse { responseObject = ConfigResponseMessage(workspaceToken = token) } + } + startMParticle() + val jsInterfaces: MutableMap = HashMap() + val latch = FailureLatch() + Handler(Looper.getMainLooper()).post( + Runnable { + val webView: WebView = object : WebView(context) { + override fun addJavascriptInterface(`object`: Any, name: String) { + jsInterfaces[name] = `object` + } + } + MParticle.getInstance()!!.registerWebView(webView) + assertTrue(jsInterfaces[MParticleJSInterface.INTERFACE_BASE_NAME + "_" + token + "_v2"] is MParticleJSInterface) + val clientToken: String = RandomUtils.getAlphaNumericString(15) + MParticle.getInstance()!!.registerWebView(webView, clientToken) + assertTrue(jsInterfaces[MParticleJSInterface.INTERFACE_BASE_NAME + "_" + clientToken + "_v2"] is MParticleJSInterface) + latch.countDown() + } + ) + latch.await() + Assert.assertEquals(2, jsInterfaces.size.toLong()) + } + + private fun ensureSessionActive() { + MParticle.getInstance().orThrow().apply { + if (!isSessionActive) { + logEvent(TestingUtils.randomMPEventRich.toMPEvent()) + assertTrue(isSessionActive) + } + } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetSync() { + testReset { MParticle.reset(context) } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetAsync() { + testReset { + val latch: CountDownLatch = FailureLatch() + MParticle.reset( + context, + object : MParticle.ResetListener { + override fun onReset() { + latch.countDown() + } + } + ) + try { + latch.await() + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetIdentitySync() { + testResetIdentityCall { MParticle.reset(context) } + } + + @OrchestratorOnly + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testResetIdentityAsync() { + testResetIdentityCall { + val latch: CountDownLatch = FailureLatch() + MParticle.reset( + context, + object : MParticle.ResetListener { + override fun onReset() { + latch.countDown() + } + } + ) + try { + latch.await() + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + } + + @OrchestratorOnly + @Test + @Throws(InterruptedException::class) + fun testResetConfigCall() { + Server + .endpoint(EndpointType.Config) + .nextResponse { + SuccessResponse { responseObject = configResponse } + } + MParticle.getInstance()!!.refreshConfiguration() + MParticle.reset(context) + // This sleep is here just to make sure + 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 = object : IdentityStateListener { + override fun onUserIdentified(user: MParticleUser, previousUser: MParticleUser?) { + assertTrue(called[0]) + throw IllegalStateException("Should not be getting callbacks after reset") + } + } + Server.endpoint(EndpointType.Identity_Identify).nextResponse { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid = Random.Default.nextLong()) + } + } + MParticle.getInstance()!!.Identity().addIdentityStateListener(crashListener) + + Server + .endpoint(EndpointType.Identity_Identify) + .assertWillReceive { true } + .after { + MParticle.getInstance()!! + .Identity().identify(IdentityApiRequest.withEmptyUser().build()) + } + .blockUntilFinished() + resetRunnable.run() + assertSDKGone() + } + + @Test + @Throws(InterruptedException::class) + fun testPushEnabledApi() { + val senderId = "senderId" + startMParticle() + MParticle.getInstance()!!.Messaging().enablePushNotifications(senderId) + var fetchedSenderId: String? = + MParticle.getInstance().orThrow().Internal().configManager.pushSenderId + assertTrue(MParticle.getInstance().orThrow().Internal().configManager.isPushEnabled) + Assert.assertEquals(senderId, fetchedSenderId) + val otherSenderId = "senderIdLogPushRegistration" + MParticle.getInstance()!!.logPushRegistration("instanceId", otherSenderId) + fetchedSenderId = MParticle.getInstance().orThrow().Internal().configManager.pushSenderId + Assert.assertEquals(otherSenderId, fetchedSenderId) + MParticle.getInstance()!!.Messaging().disablePushNotifications() + fetchedSenderId = MParticle.getInstance().orThrow().Internal().configManager.pushSenderId + Assert.assertFalse(MParticle.getInstance().orThrow().Internal().configManager.isPushEnabled) + TestCase.assertNull(fetchedSenderId) + } + + @Test + @Throws(InterruptedException::class) + fun testLogPushRegistrationModifyMessages() { + val pushRegistrationTest = PushRegistrationTest() + pushRegistrationTest.localContext = context + for (setPush in pushRegistrationTest.setPushes) { + val oldRegistration = PushRegistration( + RandomUtils.getAlphaNumericString(10), + RandomUtils.getAlphaNumericString(15) + ) + setPush.setPushRegistration(oldRegistration) + val newPushRegistration = PushRegistration( + RandomUtils.getAlphaNumericString(10), + RandomUtils.getAlphaNumericString(15) + ) + Server + .endpoint(EndpointType.Identity_Modify) + .assertNextRequest { + it.body.identityChanges?.let { + it.size == 1 && + it[0].newValue == newPushRegistration.instanceId && + it[0].oldValue == oldRegistration.instanceId && + it[0].identityType == "push_token" + } ?: false + } + .after { + MParticle.getInstance()!! + .logPushRegistration(newPushRegistration.instanceId, newPushRegistration.senderId) + } + .blockUntilFinished() + } + } + + @Test + fun testSetLocation() { + val location = Location("") + MParticle.getInstance()!!.setLocation(location) + Assert.assertEquals(location, MParticle.getInstance()!!.mMessageManager.location) + MParticle.getInstance()!!.setLocation(null) + TestCase.assertNull(MParticle.getInstance()!!.mMessageManager.location) + } + + @Throws(JSONException::class, InterruptedException::class) + private fun testReset(resetRunnable: Runnable) { + for (i in 0..9) { + MParticle.getInstance()!!.logEvent(TestingUtils.randomMPEventRich.toMPEvent()) + } + for (i in 0..9) { + MParticle.getInstance().orThrow().Internal().configManager + .setMpid(Random.Default.nextLong(), Random.Default.nextBoolean()) + } + val databaseJson = mockingPlatforms.getDatabaseContents(listOf("messages")) + assertTrue((databaseJson["messages"] as List).size > 0) + assertEquals(6, mockingPlatforms.getDatabaseContents().entries.size) + assertTrue( + 10 < MParticle.getInstance().orThrow().Internal().configManager.mpids.size + ) + + // Set strict mode, so if we get any warning or error messages during the reset/restart phase, + // it will throw an exception. + 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. + setStrictMode( + MParticle.LogLevel.WARNING, + "Failed to get MParticle instance, getInstance() called prior to start()." + ) + beforeAll() + } + + 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: String = + context.filesDir.path.replace("files", "shared_prefs/") + val files = File(sharedPrefsDirectory).listFiles() + for (file in files) { + val sharedPreferenceName = + file.path.replace(sharedPrefsDirectory, "").replace(".xml", "") + if (sharedPreferenceName != "WebViewChromiumPrefs" && sharedPreferenceName != "com.mparticle.test_preferences") { + junit.framework.Assert.fail( + """ + SharedPreference file failed to clear: + ${getSharedPrefsContents(sharedPreferenceName)} + """.trimIndent() + ) + } + } + assertEquals(0, context.databaseList().size) + try { + val databaseJson = mockingPlatforms.getDatabaseContents() + databaseJson.entries.forEach { assertEquals(it.key, 0, (it.value as Collection<*>).size) } + } catch (e: JSONException) { + junit.framework.Assert.fail(e.message) + } + } + + private fun getSharedPrefsContents(name: String): String { + return try { + val prefs: SharedPreferences = context.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/java/com/mparticle/MParticleOptionsTest.java b/android-core/src/androidTest/java/com/mparticle/MParticleOptionsTest.java deleted file mode 100644 index d16544329..000000000 --- a/android-core/src/androidTest/java/com/mparticle/MParticleOptionsTest.java +++ /dev/null @@ -1,561 +0,0 @@ -package com.mparticle; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Looper; - -import androidx.annotation.NonNull; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.rule.GrantPermissionRule; - -import com.mparticle.internal.AccessUtils; -import com.mparticle.internal.ConfigManager; -import com.mparticle.internal.Constants; -import com.mparticle.internal.Logger; -import com.mparticle.internal.MPUtility; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.AndroidUtils.Mutable; -import com.mparticle.testutils.BaseAbstractTest; -import com.mparticle.testutils.MPLatch; - -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.Assert.assertFalse; - -public class MParticleOptionsTest extends BaseAbstractTest { - Context mContext; - Context mProductionContext; - - @Before - public void before() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - mContext = InstrumentationRegistry.getInstrumentation().getContext(); - mProductionContext = new AndroidUtils().getProductionContext(mContext); - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - } - - @Test - public void testCrashOnNoCredentials() throws Exception { - boolean thrown = false; - clearStoredPreferences(); - try { - MParticleOptions.builder(mContext).build(); - } - catch (IllegalArgumentException ex) { - thrown = true; - } - assertTrue(thrown); - - clearStoredPreferences(); - thrown = false; - try { - MParticleOptions.builder(mContext) - .credentials(null, null) - .build(); - } - catch (IllegalArgumentException ex) { - thrown = true; - } - assertTrue(thrown); - - clearStoredPreferences(); - thrown = false; - try { - MParticleOptions.builder(mContext) - .credentials("key", null) - .build(); - } - catch (IllegalArgumentException ex) { - thrown = true; - } - assertTrue(thrown); - - clearStoredPreferences(); - thrown = false; - try { - MParticleOptions.builder(mContext) - .credentials(null, "key") - .build(); - } - catch (IllegalArgumentException ex) { - thrown = true; - } - assertTrue(thrown); - - setStoredPreference("key", "secret"); - try { - MParticleOptions.builder(mContext).buildForInternalRestart(); - } - catch (IllegalArgumentException ex) { - fail("MParticleOptions should build without credentials if the internal build function is used"); - } - - try { - MParticleOptions.builder(mProductionContext).build(); - } - catch (IllegalArgumentException ex) { - fail("MParticleOptions should build without credentials in a Production environment"); - } - try { - MParticleOptions.builder(mProductionContext) - .credentials(null, null) - .build(); - } - catch (IllegalArgumentException ex) { - fail("MParticleOptions should build without credentials in a Production environment"); - } - } - - private void clearStoredPreferences() { - getCredentialsPreferences() - .edit() - .remove(Constants.PrefKeys.API_KEY) - .remove(Constants.PrefKeys.API_SECRET) - .commit(); - } - - private void setStoredPreference(String apiKey, String apiSecret) { - getCredentialsPreferences() - .edit() - .putString(Constants.PrefKeys.API_KEY, apiKey) - .putString(Constants.PrefKeys.API_SECRET, apiSecret) - .commit(); - } - - private SharedPreferences getCredentialsPreferences() { - return mContext.getSharedPreferences("mp_preferences", Context.MODE_PRIVATE); - } - - @Test - public void testSetCredentials() throws Exception { - String key = UUID.randomUUID().toString(); - String secret = UUID.randomUUID().toString(); - startMParticle(MParticleOptions.builder(mProductionContext) - .credentials(key, secret)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getApiKey(), key); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getApiSecret(), secret); - } - - @Test - public void testAndroidIdDisabled() throws Exception { - //test defaults - assertFalse(MParticle.isAndroidIdEnabled()); - assertTrue(MParticle.isAndroidIdDisabled()); - MParticle.setInstance(null); - startMParticle(MParticleOptions.builder(mContext)); - assertFalse(MParticle.isAndroidIdEnabled()); - assertTrue(MParticle.isAndroidIdDisabled()); - - //test androidIdDisabled == true - MParticle.setInstance(null); - startMParticle( - MParticleOptions.builder(mContext) - .androidIdDisabled(true) - ); - assertFalse(MParticle.isAndroidIdEnabled()); - assertTrue(MParticle.isAndroidIdDisabled()); - MParticle.setInstance(null); - - //test androidIdEnabled == false - MParticle.setInstance(null); - startMParticle( - MParticleOptions.builder(mContext) - .androidIdEnabled(false) - ); - assertFalse(MParticle.isAndroidIdEnabled()); - assertTrue(MParticle.isAndroidIdDisabled()); - MParticle.setInstance(null); - - //test androidIdDisabled == false - startMParticle( - MParticleOptions.builder(mContext) - .androidIdDisabled(false) - ); - assertTrue(MParticle.isAndroidIdEnabled()); - assertFalse(MParticle.isAndroidIdDisabled()); - - //test androidIdEnabled == true - startMParticle( - MParticleOptions.builder(mContext) - .androidIdEnabled(true) - ); - assertTrue(MParticle.isAndroidIdEnabled()); - assertFalse(MParticle.isAndroidIdDisabled()); - } - - @Test - public void testDevicePerformanceMetricsDisabled() throws Exception { - startMParticle(); - assertFalse(MParticle.getInstance().isDevicePerformanceMetricsDisabled()); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mContext) - .devicePerformanceMetricsDisabled(false)); - assertFalse(MParticle.getInstance().isDevicePerformanceMetricsDisabled()); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mContext) - .devicePerformanceMetricsDisabled(true)); - assertTrue(MParticle.getInstance().isDevicePerformanceMetricsDisabled()); - MParticle.setInstance(null); - - - } - - @Test - public void testLogLevel() throws Exception { - startMParticle(); - assertEquals(Logger.getMinLogLevel(), Logger.DEFAULT_MIN_LOG_LEVEL); - - startMParticle(MParticleOptions.builder(mProductionContext) - .logLevel(MParticle.LogLevel.VERBOSE)); - assertEquals(Logger.getMinLogLevel(), MParticle.LogLevel.VERBOSE); - - startMParticle(MParticleOptions.builder(mProductionContext).logLevel(MParticle.LogLevel.ERROR)); - - assertEquals(Logger.getMinLogLevel(), MParticle.LogLevel.ERROR); - } - - @Test - public void testEnvironment() throws Exception { - startMParticle(); - assertEquals(MParticle.getInstance().getEnvironment(), MParticle.Environment.Development); - - startMParticle(MParticleOptions.builder(mProductionContext).environment(MParticle.Environment.Production)); - assertEquals(MParticle.getInstance().getEnvironment(), MParticle.Environment.Production); - MParticle.setInstance(null); - - - Context productionContext = mProductionContext; - - - Boolean debuggable = MPUtility.isAppDebuggable(productionContext); - assertFalse(debuggable); - - startMParticle(MParticleOptions.builder(productionContext) - .environment(MParticle.Environment.AutoDetect)); - - assertEquals(MParticle.getInstance().getEnvironment(), MParticle.Environment.Production); - MParticle.setInstance(null); - } - - @Test - public void testEnableUncaughtExceptionLogging() throws Exception { - MParticleOptions options = MParticleOptions.builder(mProductionContext) - .credentials("key", "secret") - .build(); - MParticle.start(options); - assertFalse(MParticle.getInstance().Internal().getConfigManager().getLogUnhandledExceptions()); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext) - .enableUncaughtExceptionLogging(true)); - assertTrue(MParticle.getInstance().Internal().getConfigManager().getLogUnhandledExceptions()); - - startMParticle(MParticleOptions.builder(mProductionContext) - .enableUncaughtExceptionLogging(false)); - assertFalse(MParticle.getInstance().Internal().getConfigManager().getLogUnhandledExceptions()); - MParticle.setInstance(null); - } - - @Test - public void testSessionTimeout() throws Exception { - startMParticle(); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getSessionTimeout(), 60000); - - startMParticle(MParticleOptions.builder(mProductionContext) - .sessionTimeout(-123)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getSessionTimeout(), 60000); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext) - .sessionTimeout(123)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getSessionTimeout(), 123000); - - //make sure it resets if the session timeout is not specified - startMParticle(); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getSessionTimeout(), 60000); - MParticle.setInstance(null); - - } - - @Test - public void testInstallType() throws Exception { - startMParticle(); - assertEquals(AccessUtils.getInstallType(MParticle.getInstance().mMessageManager), MParticle.InstallType.AutoDetect); - MParticle.setInstance(null); - startMParticle(MParticleOptions.builder(mProductionContext) - .installType(MParticle.InstallType.KnownInstall)); - assertEquals(AccessUtils.getInstallType(MParticle.getInstance().mMessageManager), MParticle.InstallType.KnownInstall); - startMParticle(MParticleOptions.builder(mProductionContext) - .installType(MParticle.InstallType.KnownUpgrade)); - assertEquals(AccessUtils.getInstallType(MParticle.getInstance().mMessageManager), MParticle.InstallType.KnownUpgrade); - startMParticle(MParticleOptions.builder(mProductionContext) - .installType(MParticle.InstallType.AutoDetect)); - assertEquals(AccessUtils.getInstallType(MParticle.getInstance().mMessageManager), MParticle.InstallType.AutoDetect); - MParticle.setInstance(null); - } - - @Test - public void testUploadInterval() throws Exception { - //default upload interval for production - startMParticle(); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getUploadInterval(), 10000); - MParticle.setInstance(null); - - - //default upload interval for production - startMParticle(MParticleOptions.builder(mProductionContext)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getUploadInterval(), 600000); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext) - .uploadInterval(123)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getUploadInterval(), 123000); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext) - .uploadInterval(-123)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getUploadInterval(), 600000); - MParticle.setInstance(null); - } - - @Test - public void testAttributionListener() throws Exception { - startMParticle(); - assertNull(MParticle.getInstance().getAttributionListener()); - - startMParticle(MParticleOptions.builder(mContext) - .attributionListener(new AttributionListener() { - @Override - public void onResult(AttributionResult result) { - - } - - @Override - public void onError(AttributionError error) { - - } - })); - assertNotNull(MParticle.getInstance().getAttributionListener()); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mContext) - .attributionListener(null)); - assertNull(MParticle.getInstance().getAttributionListener()); - } - - @Test - public void setOperatingSystemTest() throws InterruptedException { - final Mutable called = new Mutable(false); - final CountDownLatch latch = new MPLatch(1); - startMParticle(MParticleOptions.builder(mContext) - .operatingSystem(MParticle.OperatingSystem.FIRE_OS)); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - assertEquals("FireTV", request.getBodyJson().optJSONObject("di").optString("dp")); - called.value = true; - latch.countDown(); - } - }); - - MParticle.getInstance().logEvent(new MPEvent.Builder("event name", MParticle.EventType.Location).build()); - MParticle.getInstance().upload(); - - latch.await(); - assertTrue(called.value); - } - @Test - public void setOperatingSystemDefault() throws InterruptedException { - final Mutable called = new Mutable(false); - final CountDownLatch latch1 = new MPLatch(1); - - startMParticle(MParticleOptions.builder(mContext)); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - assertEquals("Android", request.getBodyJson().optJSONObject("di").optString("dp")); - called.value = true; - latch1.countDown(); - } - }); - - MParticle.getInstance().logEvent(new MPEvent.Builder("event name", MParticle.EventType.Location).build()); - MParticle.getInstance().upload(); - - latch1.await(); - assertTrue(called.value); - } - - @Rule - public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION); - - @Test - public void testLocationTracking() throws InterruptedException { - startMParticle(MParticleOptions.builder(mContext) - .locationTrackingDisabled()); - assertFalse(MParticle.getInstance().isLocationTrackingEnabled()); - - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - - - startMParticle(MParticleOptions.builder(mContext) - .locationTrackingEnabled("passive", 100, 20)); - assertTrue(MParticle.getInstance().isLocationTrackingEnabled()); - - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - - startMParticle(); - assertFalse(MParticle.getInstance().isLocationTrackingEnabled()); - } - - @Test - public void testTimeout() throws InterruptedException { - - startMParticle(MParticleOptions.builder(mProductionContext) - .identityConnectionTimeout(-123)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getIdentityConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext) - .identityConnectionTimeout(0)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getIdentityConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext) - .identityConnectionTimeout(123)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getIdentityConnectionTimeout(), 123000); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - MParticle.setInstance(null); - - startMParticle(MParticleOptions.builder(mProductionContext)); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getIdentityConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - assertEquals(MParticle.getInstance().Internal().getConfigManager().getConnectionTimeout(), ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000); - } - - @Test - public void testNetworkOptions() { - MParticleOptions options = MParticleOptions.builder(mProductionContext) - .credentials("key", "secret") - .build(); - assertTrue(com.mparticle.networking.AccessUtils.equals(options.getNetworkOptions(), com.mparticle.networking.AccessUtils.getDefaultNetworkOptions())); - } - - @Test - public void testConfigStaleness() { - //nothing set, should return null - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials("key", "secret") - .build(); - assertNull(options.getConfigMaxAge()); - - //0 should return 0 - options = MParticleOptions.builder(mContext) - .credentials("key", "secret") - .configMaxAgeSeconds(0) - .build(); - assertEquals(0, options.getConfigMaxAge().intValue()); - - //positive number should return positive number - int testValue = Math.abs(ran.nextInt()); - options = MParticleOptions.builder(mContext) - .credentials("key", "secret") - .configMaxAgeSeconds(testValue) - .build(); - assertEquals(testValue, options.getConfigMaxAge().intValue()); - - //negative number should get thrown out and return null - options = MParticleOptions.builder(mContext) - .credentials("key", "secret") - .configMaxAgeSeconds(-5) - .build(); - assertNull(options.getConfigMaxAge()); - } - - @Test - public void testAndroidIdLogMessage() { - List infoLogs = new ArrayList(); - Logger.setLogHandler(new Logger.DefaultLogHandler() { - @Override - public void log(MParticle.LogLevel priority, Throwable error, String messages) { - super.log(priority, error, messages); - if (priority == MParticle.LogLevel.INFO) { - infoLogs.add(messages); - } - } - }); - MParticleOptions.builder(mContext) - .credentials("this", "that") - .androidIdDisabled(true) - .build(); - assertTrue(infoLogs.contains("ANDROID_ID will not be collected based on MParticleOptions settings")); - infoLogs.clear(); - - MParticleOptions.builder(mContext) - .credentials("this", "that") - .androidIdDisabled(false) - .build(); - assertTrue(infoLogs.contains("ANDROID_ID will be collected based on MParticleOptions settings")); - infoLogs.clear(); - - //test default - MParticleOptions.builder(mContext) - .credentials("this", "that") - .build(); - - assertTrue(infoLogs.contains("ANDROID_ID will not be collected based on default settings")); - infoLogs.clear(); - } - - @Test - public void testBatchCreationCallback() throws InterruptedException { - MParticleOptions.BatchCreationListener listener = new MParticleOptions.BatchCreationListener() { - @NonNull - @Override - public JSONObject onBatchCreated(@NonNull JSONObject batch) { - return batch; - } - }; - MParticleOptions options = MParticleOptions.builder(mProductionContext) - .batchCreationListener(listener) - .credentials("this", "that") - .build(); - assertEquals(listener, options.getBatchCreationListener()); - - options = MParticleOptions.builder(mProductionContext) - .credentials("this", "that") - .batchCreationListener(listener) - .batchCreationListener(null) - .build(); - assertNull(options.getBatchCreationListener()); - - options = MParticleOptions.builder(mProductionContext) - .credentials("this", "that") - .build(); - assertNull(options.getBatchCreationListener()); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/MParticleOptionsTest.kt b/android-core/src/androidTest/java/com/mparticle/MParticleOptionsTest.kt new file mode 100644 index 000000000..6b4034595 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/MParticleOptionsTest.kt @@ -0,0 +1,586 @@ +package com.mparticle + +import android.Manifest +import android.content.Context +import android.content.SharedPreferences +import android.os.Looper +import androidx.test.rule.GrantPermissionRule +import com.mparticle.internal.AccessUtils +import com.mparticle.internal.ConfigManager +import com.mparticle.internal.Constants +import com.mparticle.internal.Logger +import com.mparticle.internal.MPUtility +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.orThrow +import com.mparticle.testing.productionContext +import com.mparticle.utils.getInstallType +import com.mparticle.utils.startMParticle +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.util.UUID +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class MParticleOptionsTest : BaseTest() { + @Before + fun before() { + if (Looper.myLooper() == null) { + Looper.prepare() + } + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + } + + @Test + @Throws(Exception::class) + fun testCrashOnNoCredentials() { + var thrown = false + clearStoredPreferences() + try { + MParticleOptions.builder(context).build() + } catch (ex: IllegalArgumentException) { + thrown = true + } + Assert.assertTrue(thrown) + clearStoredPreferences() + thrown = false + try { + MParticleOptions.builder(context).apply { + apiKey = "key" + build() + } + } catch (ex: IllegalArgumentException) { + thrown = true + } + Assert.assertTrue(thrown) + clearStoredPreferences() + thrown = false + try { + MParticleOptions.builder(context).apply { + apiSecret = "secret" + build() + } + } catch (ex: IllegalArgumentException) { + thrown = true + } + Assert.assertTrue(thrown) + try { + MParticleOptions.builder(context).buildForInternalRestart() + } catch (ex: IllegalArgumentException) { + Assert.fail("MParticleOptions should build without credentials if the internal build function is used") + } + try { + MParticleOptions.builder(productionContext).build() + } catch (ex: IllegalArgumentException) { + Assert.fail("MParticleOptions should build without credentials in a Production environment") + } + } + + private fun clearStoredPreferences() { + credentialsPreferences + .edit() + .remove(Constants.PrefKeys.API_KEY) + .remove(Constants.PrefKeys.API_SECRET) + .commit() + } + + private fun setStoredPreference(apiKey: String, apiSecret: String) { + credentialsPreferences + .edit() + .putString(Constants.PrefKeys.API_KEY, apiKey) + .putString(Constants.PrefKeys.API_SECRET, apiSecret) + .commit() + } + + private val credentialsPreferences: SharedPreferences + private get() = context.getSharedPreferences("mp_preferences", Context.MODE_PRIVATE) + + @Test + @Throws(Exception::class) + fun testSetCredentials() { + val key = UUID.randomUUID().toString() + val secret = UUID.randomUUID().toString() + startMParticle( + MParticleOptions.builder(productionContext) + .credentials(key, secret) + ) + assertEquals(MParticle.getInstance()?.Internal()?.configManager?.apiKey, key) + assertEquals( + MParticle.getInstance()?.Internal()?.configManager?.apiSecret, + secret + ) + } + + @Test + @Throws(Exception::class) + fun testAndroidIdDisabled() { + // test defaults + Assert.assertFalse(MParticle.isAndroidIdEnabled()) + Assert.assertTrue(MParticle.isAndroidIdDisabled()) + MParticle.setInstance(null) + startMParticle(MParticleOptions.builder(context)) + Assert.assertFalse(MParticle.isAndroidIdEnabled()) + Assert.assertTrue(MParticle.isAndroidIdDisabled()) + + // test androidIdDisabled == true + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(context) + .androidIdDisabled(true) + ) + Assert.assertFalse(MParticle.isAndroidIdEnabled()) + Assert.assertTrue(MParticle.isAndroidIdDisabled()) + MParticle.setInstance(null) + + // test androidIdEnabled == false + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(context) + .androidIdEnabled(false) + ) + Assert.assertFalse(MParticle.isAndroidIdEnabled()) + Assert.assertTrue(MParticle.isAndroidIdDisabled()) + MParticle.setInstance(null) + + // test androidIdDisabled == false + startMParticle( + MParticleOptions.builder(context) + .androidIdDisabled(false) + ) + Assert.assertTrue(MParticle.isAndroidIdEnabled()) + Assert.assertFalse(MParticle.isAndroidIdDisabled()) + + // test androidIdEnabled == true + startMParticle( + MParticleOptions.builder(context) + .androidIdEnabled(true) + ) + Assert.assertTrue(MParticle.isAndroidIdEnabled()) + Assert.assertFalse(MParticle.isAndroidIdDisabled()) + } + + @Test + @Throws(Exception::class) + fun testDevicePerformanceMetricsDisabled() { +// startMParticle() +// Assert.assertFalse(MParticle.getInstance().orThrow().isDevicePerformanceMetricsDisabled) +// MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(context) + .devicePerformanceMetricsDisabled(false) + ) + Assert.assertFalse(MParticle.getInstance().orThrow().isDevicePerformanceMetricsDisabled) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(context) + .devicePerformanceMetricsDisabled(true) + ) + Assert.assertTrue(MParticle.getInstance().orThrow().isDevicePerformanceMetricsDisabled) + MParticle.setInstance(null) + } + + @Test + @Throws(Exception::class) + fun testLogLevel() { + startMParticle() + assertEquals(Logger.DEFAULT_MIN_LOG_LEVEL, Logger.getMinLogLevel()) + startMParticle( + MParticleOptions.builder(productionContext) + .logLevel(MParticle.LogLevel.VERBOSE) + ) + assertEquals(MParticle.LogLevel.VERBOSE, Logger.getMinLogLevel()) + startMParticle( + MParticleOptions.builder(productionContext).logLevel(MParticle.LogLevel.ERROR) + ) + assertEquals(Logger.getMinLogLevel(), MParticle.LogLevel.ERROR) + } + + @Test + @Throws(Exception::class) + fun testEnvironment() { + startMParticle() + assertEquals( + MParticle.getInstance().orThrow().environment, + MParticle.Environment.Development + ) + startMParticle( + MParticleOptions.builder(productionContext) + .environment(MParticle.Environment.Production) + ) + assertEquals(MParticle.getInstance()?.environment, MParticle.Environment.Production) + MParticle.setInstance(null) + val productionContext = productionContext + val debuggable: Boolean = MPUtility.isAppDebuggable(productionContext) + Assert.assertFalse(debuggable) + startMParticle( + MParticleOptions.builder(productionContext) + .environment(MParticle.Environment.AutoDetect) + ) + assertEquals(MParticle.getInstance()?.environment, MParticle.Environment.Production) + MParticle.setInstance(null) + } + + @Test + @Throws(Exception::class) + fun testEnableUncaughtExceptionLogging() { + val options = MParticleOptions.builder(productionContext) + .credentials("key", "secret") + .build() + MParticle.start(options) + Assert.assertFalse( + MParticle.getInstance().orThrow().Internal().configManager.logUnhandledExceptions + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .enableUncaughtExceptionLogging(true) + ) + Assert.assertTrue( + MParticle.getInstance().orThrow().Internal().configManager.logUnhandledExceptions + ) + startMParticle( + MParticleOptions.builder(productionContext) + .enableUncaughtExceptionLogging(false) + ) + Assert.assertFalse( + MParticle.getInstance().orThrow().Internal().configManager.logUnhandledExceptions + ) + MParticle.setInstance(null) + } + + @Test + @Throws(Exception::class) + fun testSessionTimeout() { + startMParticle() + assertEquals( + 60000, + MParticle.getInstance().orThrow().Internal().configManager.sessionTimeout.toLong() + ) + startMParticle( + MParticleOptions.builder(productionContext) + .sessionTimeout(-123) + ) + assertEquals( + 60000, + MParticle.getInstance().orThrow().Internal().configManager.sessionTimeout.toLong() + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .sessionTimeout(123) + ) + assertEquals(MParticle.Environment.Production, MParticle.getInstance()?.environment) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.sessionTimeout.toLong(), + 123000 + ) + + // make sure it resets if the session timeout is not specified + startMParticle() + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.sessionTimeout.toLong(), + 60000 + ) + MParticle.setInstance(null) + } + + @Test + @Throws(Exception::class) + fun testInstallType() { + startMParticle() + assertEquals( + getInstallType(MParticle.getInstance().orThrow().mMessageManager), + MParticle.InstallType.AutoDetect + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .installType(MParticle.InstallType.KnownInstall) + ) + assertEquals( + getInstallType(MParticle.getInstance().orThrow().mMessageManager), + MParticle.InstallType.KnownInstall + ) + startMParticle( + MParticleOptions.builder(productionContext) + .installType(MParticle.InstallType.KnownUpgrade) + ) + assertEquals( + getInstallType(MParticle.getInstance().orThrow().mMessageManager), + MParticle.InstallType.KnownUpgrade + ) + startMParticle( + MParticleOptions.builder(productionContext) + .installType(MParticle.InstallType.AutoDetect) + ) + assertEquals( + getInstallType(MParticle.getInstance().orThrow().mMessageManager), + MParticle.InstallType.AutoDetect + ) + MParticle.setInstance(null) + } + + @Test + @Throws(Exception::class) + fun testUploadInterval() { + // default upload interval for production + startMParticle() + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.uploadInterval, 10000 + ) + MParticle.setInstance(null) + + // default upload interval for production + startMParticle(MParticleOptions.builder(productionContext)) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.uploadInterval, 600000 + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .uploadInterval(123) + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.uploadInterval, 123000 + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .uploadInterval(-123) + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.uploadInterval, 600000 + ) + MParticle.setInstance(null) + } + + @Test + @Throws(Exception::class) + fun testAttributionListener() { + startMParticle() + Assert.assertNull(MParticle.getInstance().orThrow().attributionListener) + startMParticle( + MParticleOptions.builder(context) + .attributionListener(object : AttributionListener { + override fun onResult(result: AttributionResult) {} + override fun onError(error: AttributionError) {} + }) + ) + Assert.assertNotNull(MParticle.getInstance().orThrow().attributionListener) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(context) + .attributionListener(null) + ) + Assert.assertNull(MParticle.getInstance().orThrow().attributionListener) + } + + @Test + @Throws(InterruptedException::class) + fun setOperatingSystemTest() { + val called: Mutable = Mutable(false) + val latch: CountDownLatch = FailureLatch() + startMParticle( + MParticleOptions.builder(context) + .operatingSystem(MParticle.OperatingSystem.FIRE_OS) + ) + Server + .endpoint(EndpointType.Events) + .assertNextRequest { + "FireTV" == it.body.deviceInfo?.platform + } + .after { + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("event name", MParticle.EventType.Location).build()) + upload() + } + } + .blockUntilFinished() + } + + @Test + @Throws(InterruptedException::class) + fun setOperatingSystemDefault() { + startMParticle(MParticleOptions.builder(context)) + Server + .endpoint(EndpointType.Events) + .assertNextRequest { + "Android" == it.body.deviceInfo?.platform + } + .after { + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("event name", MParticle.EventType.Location).build()) + upload() + } + } + .blockUntilFinished() + } + + @Rule + @JvmField + var mRuntimePermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.ACCESS_FINE_LOCATION) + + @Test + @Throws(InterruptedException::class) + fun testLocationTracking() { + startMParticle( + MParticleOptions.builder(context) + .locationTrackingDisabled() + ) + Assert.assertFalse(MParticle.getInstance().orThrow().isLocationTrackingEnabled) + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + startMParticle( + MParticleOptions.builder(context) + .locationTrackingEnabled("passive", 100, 20) + ) + Assert.assertTrue(MParticle.getInstance().orThrow().isLocationTrackingEnabled) + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + startMParticle() + Assert.assertFalse(MParticle.getInstance().orThrow().isLocationTrackingEnabled) + } + + @Test + @Throws(InterruptedException::class) + fun testTimeout() { + startMParticle( + MParticleOptions.builder(productionContext) + .credentials("this", "that") + .identityConnectionTimeout(-123) + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.identityConnectionTimeout + .toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.connectionTimeout.toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .identityConnectionTimeout(0) + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.identityConnectionTimeout + .toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.connectionTimeout.toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + MParticle.setInstance(null) + startMParticle( + MParticleOptions.builder(productionContext) + .identityConnectionTimeout(123) + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.identityConnectionTimeout + .toLong(), + 123000 + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.connectionTimeout.toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + MParticle.setInstance(null) + startMParticle(MParticleOptions.builder(productionContext)) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.identityConnectionTimeout + .toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + assertEquals( + MParticle.getInstance().orThrow().Internal().configManager.connectionTimeout.toLong(), + (ConfigManager.DEFAULT_CONNECTION_TIMEOUT_SECONDS * 1000).toLong() + ) + } + + @Test + fun testNetworkOptions() { + val options = MParticleOptions.builder(productionContext) + .credentials("key", "secret") + .build() + Assert.assertTrue( + com.mparticle.networking.AccessUtils.equals( + options.networkOptions, + com.mparticle.networking.NetworkOptionsManager.defaultNetworkOptions() + ) + ) + } + + @Test + fun testConfigStaleness() { + // nothing set, should return null + var options = MParticleOptions.builder(context) + .credentials("key", "secret") + .build() + Assert.assertNull(options.configMaxAge) + + // 0 should return 0 + options = MParticleOptions.builder(context) + .credentials("key", "secret") + .configMaxAgeSeconds(0) + .build() + assertEquals(0, options.configMaxAge.toLong()) + + // positive number should return positive number + val testValue: Int = Math.abs(Random.Default.nextInt()) + options = MParticleOptions.builder(context) + .credentials("key", "secret") + .configMaxAgeSeconds(testValue) + .build() + assertEquals(testValue.toLong(), options.configMaxAge.toLong()) + + // negative number should get thrown out and return null + options = MParticleOptions.builder(context) + .credentials("key", "secret") + .configMaxAgeSeconds(-5) + .build() + Assert.assertNull(options.configMaxAge) + } + + @Test + fun testAndroidIdLogMessage() { + val infoLogs = mutableListOf() + Logger.setLogHandler(object : Logger.DefaultLogHandler() { + override fun log(priority: MParticle.LogLevel, error: Throwable?, messages: String?) { + super.log(priority, error, messages) + if (priority == MParticle.LogLevel.INFO) { + infoLogs.add(messages) + } + } + }) + MParticleOptions.builder(context) + .credentials("this", "that") + .androidIdDisabled(true) + .build() + Assert.assertTrue(infoLogs.contains("ANDROID_ID will not be collected based on MParticleOptions settings")) + infoLogs.clear() + MParticleOptions.builder(context) + .credentials("this", "that") + .androidIdDisabled(false) + .build() + Assert.assertTrue(infoLogs.contains("ANDROID_ID will be collected based on MParticleOptions settings")) + infoLogs.clear() + + // test default + MParticleOptions.builder(context) + .credentials("this", "that") + .build() + Assert.assertTrue(infoLogs.contains("ANDROID_ID will not be collected based on default settings")) + infoLogs.clear() + } +} 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 fef360cb3..000000000 --- a/android-core/src/androidTest/java/com/mparticle/MParticleTest.java +++ /dev/null @@ -1,417 +0,0 @@ -package com.mparticle; - -import android.content.Context; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -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.internal.database.MPDatabase; -import com.mparticle.internal.database.services.MParticleDBManager; -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 junit.framework.Assert; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static junit.framework.Assert.fail; -import static junit.framework.TestCase.assertNull; - -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/java/com/mparticle/PushRegistrationTest.java b/android-core/src/androidTest/java/com/mparticle/PushRegistrationTest.java deleted file mode 100644 index b25b7b7b6..000000000 --- a/android-core/src/androidTest/java/com/mparticle/PushRegistrationTest.java +++ /dev/null @@ -1,342 +0,0 @@ -package com.mparticle; - -import android.content.Context; - -import com.mparticle.internal.ConfigManager; -import com.mparticle.internal.PushRegistrationHelper; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -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 java.util.List; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -public class PushRegistrationTest extends BaseCleanStartedEachTest { - - //So other classes can use the test fields - public void setContext(Context context) { - mContext = context; - } - - @Test - public void testPushEnabledOnStartup() throws InterruptedException { - MParticle.reset(mContext); - final String newToken = mRandomUtils.getAlphaNumericString(30); - startMParticle(); - TestingUtils.setFirebasePresent(true, newToken); - final CountDownLatch latch = new MPLatch(1); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getModifyUrl(mStartingMpid)), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - List identitChanges = request.asIdentityRequest().getBody().identity_changes; - assertEquals(1, identitChanges.size()); - try { - assertEquals(newToken, identitChanges.get(0).getString("new_value")); - latch.countDown(); - } catch (JSONException e) { - new RuntimeException(e); - } - } - }); - MParticle.getInstance().Messaging().enablePushNotifications("12345"); - latch.await(); - TestingUtils.setFirebasePresent(false, null); - - } - - @Test - public void testPushRegistrationSet() { - assertEquals(mStartingMpid.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - for (SetPush setPush : setPushes) { - PushRegistrationHelper.PushRegistration pushRegistration = new PushRegistrationHelper.PushRegistration(mRandomUtils.getAlphaNumericString(10), mRandomUtils.getAlphaNumericString(15)); - setPush.setPushRegistration(pushRegistration); - - for (GetPush getPush : getPushes) { - PushRegistrationHelper.PushRegistration fetchedPushValue = getPush.getPushRegistration(); - String fetchedSenderId = fetchedPushValue.senderId; - String fetchedInstanceId = fetchedPushValue.instanceId; - if (!pushRegistration.senderId.equals(fetchedSenderId)) { - fail("Mismatch! When push value of \"" + pushRegistration.senderId + "\" is set with: " + setPush.getName() + ". A different value \"" + fetchedSenderId + "\" is returned with:" + getPush.getName()); - } - if (!pushRegistration.instanceId.equals(fetchedInstanceId)) { - fail("Mismatch! When push value of \"" + pushRegistration.instanceId + "\" is set with: " + setPush.getName() + ". A different value \"" + fetchedInstanceId + "\" is returned with:" + getPush.getName()); - } - } - } - } - - @Test - public void testPushRegistrationCleared() { - for (SetPush setPush : setPushes) { - PushRegistrationHelper.PushRegistration pushRegistration = new PushRegistrationHelper.PushRegistration(mRandomUtils.getAlphaNumericString(10), mRandomUtils.getAlphaNumericString(15)); - setPush.setPushRegistration(pushRegistration); - - for (ClearPush clearPush : clearPushes) { - clearPush.clearPush(); - - for (GetPush getPush : getPushes) { - PushRegistrationHelper.PushRegistration fetchedPushRegistration = getPush.getPushRegistration(); - if (fetchedPushRegistration != null && fetchedPushRegistration.instanceId != null && fetchedPushRegistration.senderId != null) { - fail("Mismatch! When push value of \"" + pushRegistration + "\" is set with: " + setPush.getName() + ", and cleared with: " + clearPush.getName() + ", the value is not null when fetched with:" + getPush.getName()); - } - } - } - } - } - - @Test - public void testPushRegistrationEnabledDisabled() { - - for (SetPush setPush: setPushes) { - PushRegistrationHelper.PushRegistration pushRegistration = new PushRegistrationHelper.PushRegistration(mRandomUtils.getAlphaNumericString(10), mRandomUtils.getAlphaNumericString(15)); - setPush.setPushRegistration(pushRegistration); - - for (PushEnabled pushEnabled: pushEnableds) { - if (!pushEnabled.isPushEnabled()) { - fail("Mismatch! When push value of \"" + pushRegistration + "\" is set with: " + setPush.getName() + ", push IS NOT enabled with:" + pushEnabled.getName()); - } - } - - for (ClearPush clearPush: clearPushes) { - clearPush.clearPush(); - - for (PushEnabled pushEnabled: pushEnableds) { - if (pushEnabled.isPushEnabled()) { - fail("Mismatch! When push value of \"" + pushRegistration + "\" is set with: " + setPush.getName() + ", and cleared with: " + clearPush.getName() + ", push IS enabled with:" + pushEnabled.getName()); - } - } - } - } - - - } - - public SetPush[] setPushes = new SetPush[]{ - new SetPush() { - @Override - public void setPushRegistration(PushRegistrationHelper.PushRegistration pushRegistration) { - MParticle.getInstance().logPushRegistration(pushRegistration.instanceId, pushRegistration.senderId); - } - - @Override - public String getName() { - return "MParticle.getInstance().logPushRegistration(senderId, instanceId)"; - } - }, - new SetPush() { - @Override - public void setPushRegistration(PushRegistrationHelper.PushRegistration pushRegistration) { - MParticle.getInstance().Internal().getConfigManager().setPushRegistration(pushRegistration); - } - - @Override - public String getName() { - return "ConfigManager.setPushRegistration(pushRegistration())"; - } - }, - new SetPush() { - @Override - public void setPushRegistration(PushRegistrationHelper.PushRegistration pushRegistration) { - MParticle.getInstance().Internal().getConfigManager().setPushSenderId(pushRegistration.senderId); - MParticle.getInstance().Internal().getConfigManager().setPushInstanceId(pushRegistration.instanceId); - } - - @Override - public String getName() { - return "ConfigManager.setPushSenderId(senderId) + ConfigManager.setPushRegistration(instanceId)"; - } - }, - new SetPush() { - @Override - public void setPushRegistration(PushRegistrationHelper.PushRegistration pushRegistration) { - //For enablePushNotifications() to set the push registration, we need to mimic - //the Firebase dependency, and clear the push-fetched flags - TestingUtils.setFirebasePresent(true, pushRegistration.instanceId); - MParticle.getInstance().Messaging().enablePushNotifications(pushRegistration.senderId); - //this method setting push is async, so wait for confirmation before continuing - ConfigManager configManager = ConfigManager.getInstance(mContext); - while (!configManager.isPushEnabled()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - TestingUtils.setFirebasePresent(false, null); - } - - @Override - public String getName() { - return "MessagingApi.enablePushNotification(senderId)"; - } - }, - new SetPush() { - @Override - public void setPushRegistration(PushRegistrationHelper.PushRegistration pushRegistration) { - MParticle.setInstance(null); - try { - startMParticle(MParticleOptions.builder(mContext).pushRegistration(pushRegistration.instanceId, pushRegistration.senderId)); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - } - - @Override - public String getName() { - return "MParticleOptions.pushRegistration(instanceId, senderId)"; - } - } - }; - - public ClearPush[] clearPushes = new ClearPush[] { - new ClearPush() { - @Override - public void clearPush() { - MParticle.getInstance().Messaging().disablePushNotifications(); - } - - @Override - public String getName() { - return "MessagingApi.disablePushNotifications"; - } - }, - new ClearPush() { - @Override - public void clearPush() { - MParticle.getInstance().Internal().getConfigManager().setPushSenderId(null); - } - - @Override - public String getName() { - return "ConfigManager.setPushSenderId(null)"; - } - }, - new ClearPush() { - @Override - public void clearPush() { - MParticle.getInstance().Internal().getConfigManager().setPushRegistration(null); - } - - @Override - public String getName() { - return "ConfigManager.setPushRegistration(null)"; - } - }, - new ClearPush() { - @Override - public void clearPush() { - MParticle.getInstance().Internal().getConfigManager().setPushRegistration(new PushRegistrationHelper.PushRegistration("instanceId", null)); - } - - @Override - public String getName() { - return "ConfigManager.setPushRegistration(PushRegistration(\"instanceId\", null))"; - } - }, - new ClearPush() { - @Override - public void clearPush() { - MParticle.setInstance(null); - try { - startMParticle(MParticleOptions.builder(mContext).pushRegistration(null, null)); - } catch (InterruptedException e) { - fail(e.getMessage()); - } - } - - @Override - public String getName() { - return "startMParticle(MParticleOptions.builder(mContext).pushRegistration(null, null))"; - } - } - }; - - public GetPush[] getPushes = new GetPush[] { - new GetPush() { - @Override - public PushRegistrationHelper.PushRegistration getPushRegistration() { - String senderId = MParticle.getInstance().Internal().getConfigManager().getPushSenderId(); - String instanceId = MParticle.getInstance().Internal().getConfigManager().getPushInstanceId(); - return new PushRegistrationHelper.PushRegistration(instanceId, senderId); - } - - @Override - public String getName() { - return "ConfigManager.getPushSenderId() + ConfigManager.getPushInstanceId()"; - } - }, - new GetPush() { - @Override - public PushRegistrationHelper.PushRegistration getPushRegistration() { - return PushRegistrationHelper.getLatestPushRegistration(mContext); - } - - @Override - public String getName() { - return "PushRegistrationHelper.getLatestPushRegistration(context)"; - } - }, - new GetPush() { - @Override - public PushRegistrationHelper.PushRegistration getPushRegistration() { - return MParticle.getInstance().Internal().getConfigManager().getPushRegistration(); - } - - @Override - public String getName() { - return "ConfigManager.getPushRegistration()"; - } - } - }; - - public PushEnabled[] pushEnableds = new PushEnabled[] { - new PushEnabled() { - @Override - public Boolean isPushEnabled() { - return MParticle.getInstance().Internal().getConfigManager().isPushEnabled(); - } - - @Override - public String getName() { - return "ConfigManager.isPushEnabled()"; - } - } - }; - - - public interface SynonymousMethod { - String getName(); - } - - public interface SetPush extends SynonymousMethod { - void setPushRegistration(PushRegistrationHelper.PushRegistration pushRegistration); - } - - public interface ClearPush extends SynonymousMethod { - void clearPush(); - } - - public interface GetPush extends SynonymousMethod { - PushRegistrationHelper.PushRegistration getPushRegistration(); - } - - public interface PushEnabled extends SynonymousMethod { - Boolean isPushEnabled(); - } - - PushRegistrationTest setServer(MockServer server) { - mServer = server; - return this; - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/PushRegistrationTest.kt b/android-core/src/androidTest/java/com/mparticle/PushRegistrationTest.kt new file mode 100644 index 000000000..50850b354 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/PushRegistrationTest.kt @@ -0,0 +1,275 @@ +package com.mparticle + +import com.mparticle.internal.ConfigManager +import com.mparticle.internal.PushRegistrationHelper +import com.mparticle.internal.PushRegistrationHelper.PushRegistration +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.Utils.setFirebasePresent +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.orThrow +import com.mparticle.utils.startMParticle +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test + +class PushRegistrationTest : BaseStartedTest() { + var localContext = context + // So other classes can use the test fields + + @Test + @Throws(InterruptedException::class) + fun testPushEnabledOnStartup() { + MParticle.reset(localContext) + val newToken: String = RandomUtils.getAlphaNumericString(30) + startMParticle() + setFirebasePresent(true, newToken) + Server + .endpoint(EndpointType.Identity_Modify) + .assertNextRequest { + it.body.identityChanges?.let { + it.size == 1 && + it.first().newValue == newToken + } ?: false + } + .after { + MParticle.getInstance()!!.Messaging().enablePushNotifications("12345") + } + .blockUntilFinished() + setFirebasePresent(false, null) + } + + @Test + fun testPushRegistrationSet() { + assertEquals( + mStartingMpid, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + for (setPush in setPushes) { + val pushRegistration = PushRegistration( + RandomUtils.getAlphaNumericString(10), + RandomUtils.getAlphaNumericString(15) + ) + setPush.setPushRegistration(pushRegistration) + for (getPush in getPushes) { + val fetchedPushValue: PushRegistration = getPush.pushRegistration + val fetchedSenderId = fetchedPushValue.senderId + val fetchedInstanceId = fetchedPushValue.instanceId + if (pushRegistration.senderId != fetchedSenderId) { + Assert.fail("Mismatch! When push value of \"" + pushRegistration.senderId + "\" is set with: " + setPush.name + ". A different value \"" + fetchedSenderId + "\" is returned with:" + getPush.name) + } + if (pushRegistration.instanceId != fetchedInstanceId) { + Assert.fail("Mismatch! When push value of \"" + pushRegistration.instanceId + "\" is set with: " + setPush.name + ". A different value \"" + fetchedInstanceId + "\" is returned with:" + getPush.name) + } + } + } + } + + @Test + fun testPushRegistrationCleared() { + for (setPush in setPushes) { + val pushRegistration = PushRegistration( + RandomUtils.getAlphaNumericString(10), + RandomUtils.getAlphaNumericString(15) + ) + setPush.setPushRegistration(pushRegistration) + for (clearPush in clearPushes) { + clearPush.clearPush() + for (getPush in getPushes) { + val fetchedPushRegistration: PushRegistration = getPush.pushRegistration + if (fetchedPushRegistration != null && fetchedPushRegistration.instanceId != null && fetchedPushRegistration.senderId != null) { + Assert.fail("Mismatch! When push value of \"" + pushRegistration + "\" is set with: " + setPush.name + ", and cleared with: " + clearPush.name + ", the value is not null when fetched with:" + getPush.name) + } + } + } + } + } + + @Test + fun testPushRegistrationEnabledDisabled() { + for (setPush in setPushes) { + val pushRegistration = PushRegistration( + RandomUtils.getAlphaNumericString(10), + RandomUtils.getAlphaNumericString(15) + ) + setPush.setPushRegistration(pushRegistration) + for (pushEnabled in pushEnableds) { + if (!pushEnabled.isPushEnabled) { + Assert.fail("Mismatch! When push value of \"" + pushRegistration + "\" is set with: " + setPush.name + ", push IS NOT enabled with:" + pushEnabled.name) + } + } + for (clearPush in clearPushes) { + clearPush.clearPush() + for (pushEnabled in pushEnableds) { + if (pushEnabled.isPushEnabled) { + Assert.fail("Mismatch! When push value of \"" + pushRegistration + "\" is set with: " + setPush.name + ", and cleared with: " + clearPush.name + ", push IS enabled with:" + pushEnabled.name) + } + } + } + } + } + + var setPushes = arrayOf( + object : SetPush { + override fun setPushRegistration(pushRegistration: PushRegistration) { + MParticle.getInstance()!! + .logPushRegistration(pushRegistration.instanceId, pushRegistration.senderId) + } + + override val name: String + get() = "MParticle.getInstance().logPushRegistration(senderId, instanceId)" + }, + object : SetPush { + override fun setPushRegistration(pushRegistration: PushRegistration) { + MParticle.getInstance().orThrow().Internal().configManager.pushRegistration = + pushRegistration + } + + override val name: String + get() = "ConfigManager.setPushRegistration(pushRegistration())" + }, + object : SetPush { + override fun setPushRegistration(pushRegistration: PushRegistration) { + MParticle.getInstance().orThrow().Internal().configManager.pushSenderId = + pushRegistration.senderId + MParticle.getInstance().orThrow().Internal().configManager.pushInstanceId = + pushRegistration.instanceId + } + + override val name: String + get() = "ConfigManager.setPushSenderId(senderId) + ConfigManager.setPushRegistration(instanceId)" + }, + object : SetPush { + override fun setPushRegistration(pushRegistration: PushRegistration) { + // For enablePushNotifications() to set the push registration, we need to mimic + // the Firebase dependency, and clear the push-fetched flags + setFirebasePresent(true, pushRegistration.instanceId) + MParticle.getInstance()!!.Messaging() + .enablePushNotifications(pushRegistration.senderId!!) + // this method setting push is async, so wait for confirmation before continuing + val configManager: ConfigManager = ConfigManager.getInstance(localContext) + while (!configManager.isPushEnabled) { + try { + Thread.sleep(10) + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + setFirebasePresent(false, null) + } + + override val name: String + get() = "MessagingApi.enablePushNotification(senderId)" + }, + object : SetPush { + override fun setPushRegistration(pushRegistration: PushRegistration) { + MParticle.setInstance(null) + try { + startMParticle( + MParticleOptions.builder(localContext).pushRegistration( + pushRegistration.instanceId!!, + pushRegistration.senderId!! + ) + ) + } catch (e: InterruptedException) { + Assert.fail(e.message) + } + } + + override val name: String + get() = "MParticleOptions.pushRegistration(instanceId, senderId)" + } + ) + var clearPushes = arrayOf( + object : ClearPush { + override fun clearPush() { + MParticle.getInstance()!!.Messaging().disablePushNotifications() + } + + override val name: String + get() = "MessagingApi.disablePushNotifications" + }, + object : ClearPush { + override fun clearPush() { + MParticle.getInstance().orThrow().Internal().configManager.pushSenderId = null + } + + override val name: String + get() = "ConfigManager.setPushSenderId(null)" + }, + object : ClearPush { + override fun clearPush() { + MParticle.getInstance().orThrow().Internal().configManager.pushRegistration = null + } + + override val name: String + get() = "ConfigManager.setPushRegistration(null)" + }, + object : ClearPush { + override fun clearPush() { + MParticle.getInstance().orThrow().Internal().configManager.pushRegistration = + PushRegistration("instanceId", null) + } + + override val name: String + get() = "ConfigManager.setPushRegistration(PushRegistration(\"instanceId\", null))" + } + ) + var getPushes = arrayOf( + object : GetPush { + override val pushRegistration: PushRegistration + get() { + val senderId: String? = + MParticle.getInstance().orThrow().Internal().configManager.pushSenderId + val instanceId: String? = + MParticle.getInstance().orThrow().Internal().configManager.pushInstanceId + return PushRegistration(instanceId, senderId) + } + override val name: String + get() = "ConfigManager.getPushSenderId() + ConfigManager.getPushInstanceId()" + }, + object : GetPush { + override val pushRegistration: PushRegistration + get() = PushRegistrationHelper.getLatestPushRegistration(localContext) + override val name: String + get() = "PushRegistrationHelper.getLatestPushRegistration(localContext)" + }, + object : GetPush { + override val pushRegistration: PushRegistration + get() = MParticle.getInstance().orThrow().Internal().configManager.pushRegistration + override val name: String + get() = "ConfigManager.getPushRegistration()" + } + ) + var pushEnableds = arrayOf( + object : PushEnabled { + override val isPushEnabled: Boolean + get() = MParticle.getInstance().orThrow().Internal().configManager.isPushEnabled + override val name: String + get() = "ConfigManager.isPushEnabled()" + } + ) + + interface SynonymousMethod { + val name: String + } + + interface SetPush : SynonymousMethod { + fun setPushRegistration(pushRegistration: PushRegistration) + } + + interface ClearPush : SynonymousMethod { + fun clearPush() + } + + interface GetPush : SynonymousMethod { + val pushRegistration: PushRegistration + } + + interface PushEnabled : SynonymousMethod { + val isPushEnabled: Boolean + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/SessionMessagesTest.java b/android-core/src/androidTest/java/com/mparticle/SessionMessagesTest.java deleted file mode 100644 index bb1d54bee..000000000 --- a/android-core/src/androidTest/java/com/mparticle/SessionMessagesTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.mparticle; - -import android.os.Handler; -import android.os.Looper; - -import com.mparticle.internal.AccessUtils; -import com.mparticle.internal.AppStateManager; -import com.mparticle.internal.Constants; -import com.mparticle.internal.MParticleApiClientImpl; -import com.mparticle.internal.database.services.MParticleDBManager; -import com.mparticle.internal.database.services.MessageService; -import com.mparticle.internal.database.services.SessionService; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import junit.framework.Assert; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static junit.framework.Assert.fail; - - -public final class SessionMessagesTest extends BaseCleanStartedEachTest { - AppStateManager mAppStateManager; - Handler mHandler; - - @Before - public void before() { - mAppStateManager = MParticle.getInstance().Internal().getAppStateManager(); - mHandler = new Handler(Looper.getMainLooper()); - } - - @Test - public void testSessionStartMessage() throws Exception { - final boolean[] sessionStartReceived = new boolean[1]; - sessionStartReceived[0] = false; - assertFalse(mAppStateManager.getSession().isActive()); - final CountDownLatch latch = new MPLatch(1); - final AndroidUtils.Mutable sessionId = new AndroidUtils.Mutable(null); - mAppStateManager.ensureActiveSession(); - sessionId.value = mAppStateManager.getSession().mSessionID; - - AccessUtils.awaitMessageHandler(); - MParticle.getInstance().upload(); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject jsonObject) { - try { - JSONArray jsonArray = jsonObject.optJSONArray(Constants.MessageKey.MESSAGES); - if (jsonArray == null) { - return false; - } - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject eventObject = jsonArray.getJSONObject(i); - if (eventObject.getString("dt").equals(Constants.MessageType.SESSION_START)) { - assertEquals(eventObject.getLong("ct"), mAppStateManager.getSession().mSessionStartTime, 1000); - assertEquals("started sessionID = " + sessionId.value + " \ncurrent sessionId = " + mAppStateManager.getSession().mSessionID + " \nsent sessionId = " + eventObject.getString("id"), - mAppStateManager.getSession().mSessionID, eventObject.getString("id")); - sessionStartReceived[0] = true; - return true; - } - } - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); - } - return false; - }; - })); - - Assert.assertTrue(sessionStartReceived[0]); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/SessionMessagesTest.kt b/android-core/src/androidTest/java/com/mparticle/SessionMessagesTest.kt new file mode 100644 index 000000000..d88cad3a0 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/SessionMessagesTest.kt @@ -0,0 +1,53 @@ +package com.mparticle + +import android.os.Handler +import android.os.Looper +import com.mparticle.internal.AccessUtils +import com.mparticle.internal.AppStateManager +import com.mparticle.messages.events.SessionStartMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.Mutable +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.orThrow +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +class SessionMessagesTest : BaseStartedTest() { + lateinit var mAppStateManager: AppStateManager + lateinit var mHandler: Handler + + @Before + fun before() { + mAppStateManager = MParticle.getInstance().orThrow().Internal().getAppStateManager() + mHandler = Handler(Looper.getMainLooper()) + } + + @Test + @Throws(Exception::class) + fun testSessionStartMessage() { + Assert.assertFalse(mAppStateManager.getSession().isActive()) + val sessionId: Mutable = Mutable(null) + + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .let { + assertEquals(1, it.size) + assertEquals(mAppStateManager.session.mSessionStartTime.toDouble(), it[0].timeStamp?.toDouble() ?: 0.0, 1000.0) + true + } + } + .after { + mAppStateManager.ensureActiveSession() + sessionId.value = mAppStateManager.getSession().mSessionID + AccessUtils.awaitMessageHandler() + MParticle.getInstance()!!.upload() + } + .blockUntilFinished() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/UploadMessageTest.java b/android-core/src/androidTest/java/com/mparticle/UploadMessageTest.java deleted file mode 100644 index 34c78ad73..000000000 --- a/android-core/src/androidTest/java/com/mparticle/UploadMessageTest.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.mparticle; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.os.Handler; -import android.os.Looper; - -import com.mparticle.internal.Constants; -import com.mparticle.internal.MPUtility; -import com.mparticle.internal.MParticleApiClientImpl; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -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 java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - - -public final class UploadMessageTest extends BaseCleanStartedEachTest { - - /** - * set MPID, log between 0 and 20 random MPEvents, and check to make sure each one is properly - * attributed to the correct MPID, and there are no duplicates - */ - @Test - public void testCorrectlyAttributeEventsToMpid() throws Exception { - int numberOfEvents = 3; - final Handler handler = new Handler(Looper.getMainLooper()); - long mpid = ran.nextLong(); - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid, ran.nextBoolean()); - final Map events = new HashMap(); - final CountDownLatch latch = new MPLatch(numberOfEvents); - - final Map> matchingJSONEvents = new HashMap>(); - com.mparticle.internal.AccessUtils.setMParticleApiClient(new com.mparticle.internal.AccessUtils.EmptyMParticleApiClient() { - @Override - public int sendMessageBatch(final String message) throws IOException, MParticleApiClientImpl.MPThrottleException, MParticleApiClientImpl.MPRampException { - handler.post(new Runnable() { - @Override - public void run() { - try { - JSONObject jsonObject = new JSONObject(message); - JSONArray jsonArray = jsonObject.optJSONArray(Constants.MessageKey.MESSAGES); - - long mpid = Long.valueOf(jsonObject.getString("mpid")); - Map matchingMpidJSONEvents = matchingJSONEvents.get(mpid); - if (matchingMpidJSONEvents == null) { - matchingJSONEvents.put(mpid, matchingMpidJSONEvents = new HashMap()); - } - if (!MPUtility.isEmpty(jsonArray)) { - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject eventObject = jsonArray.getJSONObject(i); - if (eventObject.getString("dt").equals(Constants.MessageType.EVENT)) { - String eventName = eventObject.getString("n"); - MPEvent matchingEvent = events.get(eventName); - if (matchingEvent != null) { - String eventType = eventObject.getString("et"); - if (matchingEvent.getEventType().toString().equals(eventType)) { - if (matchingMpidJSONEvents.containsKey(eventName)) { - fail("Duplicate Event Message Sent"); - } else { - matchingMpidJSONEvents.put(eventName, eventObject); - } - } else { - fail("Unknown Event"); - } - } else { - fail("Unknown Event"); - } - latch.countDown(); - } - } - } - - } catch (Exception e) { - e.printStackTrace(); - fail(e.toString()); - } - } - }); - return 202; - } - }); - - for (int j = 0; j < 3; j++) { - MPEvent event = TestingUtils.getInstance().getRandomMPEventRich(); - if (events.containsKey(event.getEventName())) { - j--; - } else { - events.put(event.getEventName(), event); - MParticle.getInstance().logEvent(event); - } - } - - MParticle.getInstance().upload(); - latch.await(); - - Map jsonMap = matchingJSONEvents.get(mpid); - if (events.size() > 0) { - assertNotNull(jsonMap); - } - if (events != null && events.size() != 0 && events.size() != jsonMap.size()) { - assertEquals(events.size(), jsonMap.size()); - } - } - - @Test - public void testEventAccuracy() throws Exception { - final Handler handler = new Handler(Looper.getMainLooper()); - final Map receivedEvents = new HashMap(); - final Map sentEvents = new HashMap(); - final CountDownLatch latch = new MPLatch(1); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - try { - JSONObject jsonObject = request.getBodyJson(); - JSONArray jsonArray = jsonObject.optJSONArray(Constants.MessageKey.MESSAGES); - if (!MPUtility.isEmpty(jsonArray)) { - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject eventObject = jsonArray.getJSONObject(i); - if (eventObject.getString("dt").equals(Constants.MessageType.EVENT)) { - String eventName = eventObject.getString("n"); - if (sentEvents.containsKey(eventName)) { - fail("Duplicate Event"); - } else { - sentEvents.put(eventName, eventObject); - } - } - } - } - - } catch (Exception e) { - e.printStackTrace(); - fail(e.toString()); - } - if (sentEvents.size() == receivedEvents.size()) - latch.countDown(); - } - }); - - for (int j = 0; j < 3; j++) { - MPEvent event = TestingUtils.getInstance().getRandomMPEventRich(); - if (receivedEvents.containsKey(event.getEventName())) { - j--; - } else { - receivedEvents.put(event.getEventName(), event); - MParticle.getInstance().logEvent(event); - } - } - - MParticle.getInstance().upload(); - latch.await(); - for (Map.Entry entry : receivedEvents.entrySet()) { - if (!sentEvents.containsKey(entry.getKey())) { - assertNull(entry.getValue()); - } else { - assertTrue(sentEvents.containsKey(entry.getKey())); - JSONObject jsonObject = sentEvents.get(entry.getKey()); - assertEventEquals(entry.getValue(), jsonObject); - } - } - } - - void assertEventEquals(MPEvent mpEvent, JSONObject jsonObject) throws JSONException { - if (jsonObject.optString("n") != mpEvent.getEventName()) { - assertTrue(mpEvent.getEventName().equals(jsonObject.getString("n"))); - } - if (mpEvent.getLength() != null || jsonObject.has("el")) { - assertEquals(mpEvent.getLength(), jsonObject.getDouble("el"), .1); - } - if (!mpEvent.getEventType().toString().equals(jsonObject.optString("et"))) { - assertTrue(mpEvent.getEventType().toString().equals(jsonObject.getString("et"))); - } - - Map customAttributesTarget = mpEvent.getCustomAttributeStrings() == null ? new HashMap() : mpEvent.getCustomAttributeStrings(); - JSONObject customAttributes = jsonObject.optJSONObject("attrs"); - if (customAttributes != null) { - Iterator keysIterator = customAttributes.keys(); - while (customAttributes != null && keysIterator.hasNext()) { - String key = customAttributes.keys().next(); - String jsonVal = keysIterator.next(); - String objVal = customAttributesTarget.get(key); - if (jsonVal != objVal) { - String val = customAttributes.getString(key); - if (!val.equals(customAttributesTarget.get(key)) && !key.equals("EventLength") && !(val.equals("null") && objVal == null)) { - assertTrue(customAttributes.getString(key).equals(customAttributesTarget.get(key))); - } - } - } - } - - Map> customFlagTarget = mpEvent.getCustomFlags(); - JSONObject customFlags = jsonObject.optJSONObject("flags"); - if (customFlags != null) { - Iterator flagsIterator = customFlags.keys(); - while (flagsIterator.hasNext()) { - String key = flagsIterator.next(); - JSONArray values = customFlags.getJSONArray(key); - List flags = customFlagTarget.get(key); - assertArraysEqual(values, flags); - } - } - } - - - void assertArraysEqual(JSONArray jsonArray, List list) throws JSONException { - List jsonArrayList = new ArrayList(); - for (int i = 0; i < jsonArray.length(); i++) { - jsonArrayList.add(jsonArray.getString(i)); - } - assertEquals(list.size(), jsonArrayList.size()); - Collections.sort(list); - Collections.sort(jsonArrayList); - for (int i = 0; i < list.size(); i++) { - String a = list.get(i); - String b = jsonArrayList.get(i); - if (a == null) { - assertTrue(b.equals("null")); - } else { - assertTrue(a.equals(b)); - } - } - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/java/com/mparticle/UploadMessageTest.kt b/android-core/src/androidTest/java/com/mparticle/UploadMessageTest.kt new file mode 100644 index 000000000..4fc5f4072 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/UploadMessageTest.kt @@ -0,0 +1,207 @@ +package com.mparticle + +import android.os.Handler +import android.os.Looper +import com.mparticle.internal.Constants +import com.mparticle.internal.EmptyApiClient +import com.mparticle.internal.MPUtility +import com.mparticle.messages.events.MPEventMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.orThrow +import com.mparticle.utils.randomMPEventRich +import com.mparticle.utils.setMParticleApiClient +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Test +import java.util.Collections +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class UploadMessageTest : BaseStartedTest() { + /** + * set MPID, log between 0 and 20 random MPEvents, and check to make sure each one is properly + * attributed to the correct MPID, and there are no duplicates + */ + @Test + @Throws(Exception::class) + fun testCorrectlyAttributeEventsToMpid() { + val numberOfEvents = 3 + val handler: Handler = Handler(Looper.getMainLooper()) + val mpid: Long = Random.Default.nextLong() + MParticle.getInstance().orThrow().Internal().configManager.setMpid(mpid, Random.Default.nextBoolean()) + val events: MutableMap = HashMap() + val latch: CountDownLatch = FailureLatch(count = numberOfEvents) + val matchingJSONEvents: MutableMap> = HashMap() + setMParticleApiClient(object : EmptyApiClient() { + override fun sendMessageBatch(message: String): Int { + handler.post { + try { + val jsonObject = JSONObject(message) + val jsonArray = jsonObject.optJSONArray(Constants.MessageKey.MESSAGES) + val mpid = java.lang.Long.valueOf(jsonObject.getString("mpid")) + var matchingMpidJSONEvents = matchingJSONEvents[mpid] + if (matchingMpidJSONEvents == null) { + matchingJSONEvents[mpid] = + HashMap().also { matchingMpidJSONEvents = it } + } + if (!MPUtility.isEmpty(jsonArray)) { + for (i in 0 until jsonArray.length()) { + val eventObject = jsonArray.getJSONObject(i) + if (eventObject.getString("dt") == Constants.MessageType.EVENT) { + val eventName = eventObject.getString("n") + val matchingEvent = events[eventName] + if (matchingEvent != null) { + val eventType = eventObject.getString("et") + if (matchingEvent.eventType.toString() == eventType) { + if (matchingMpidJSONEvents!!.containsKey(eventName)) { + Assert.fail("Duplicate Event Message Sent") + } else { + matchingMpidJSONEvents!![eventName] = eventObject + } + } else { + Assert.fail("Unknown Event") + } + } else { + Assert.fail("Unknown Event") + } + latch.countDown() + } + } + } + } catch (e: Exception) { + e.printStackTrace() + Assert.fail(e.toString()) + } + } + return 202 + } + }) + var j = 0 + while (j < 3) { + val event: MPEvent = randomMPEventRich() + if (events.containsKey(event.eventName)) { + j-- + } else { + events[event.eventName] = event + MParticle.getInstance()!!.logEvent(event) + } + j++ + } + MParticle.getInstance()!!.upload() + latch.await() + val jsonMap: Map = matchingJSONEvents[mpid]!! + if (events.size > 0) { + Assert.assertNotNull(jsonMap) + } + if (events != null && events.size != 0 && events.size != jsonMap.size) { + assertEquals(events.size.toLong(), jsonMap.size.toLong()) + } + } + + @Test + @Throws(Exception::class) + fun testEventAccuracy() { + val receivedEvents = mutableMapOf() + val sentEvents: MutableMap = HashMap() + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .let { + it.forEach { event -> + assertNull(receivedEvents[event.name]) + receivedEvents[event.name!!] = event + } + } + receivedEvents.size == sentEvents.size + } + .after { + (0..3).forEach { + val event: MPEvent = randomMPEventRich() + if (!sentEvents.containsKey(event.eventName)) { + sentEvents[event.eventName] = event + MParticle.getInstance()!!.logEvent(event) + } + } + MParticle.getInstance()?.upload() + } + .blockUntilFinished() + + sentEvents.values.forEach { + assertEventEquals(it, receivedEvents[it.eventName]) + } + } + + @Throws(JSONException::class) + fun assertEventEquals(mpEvent: MPEvent, eventMessage: MPEventMessage?) { + if (eventMessage == null) { + assertNotNull(eventMessage) + return + } + if (eventMessage.name !== mpEvent.eventName) { + Assert.assertTrue(mpEvent.eventName == eventMessage.name) + } + if (mpEvent.length != null || eventMessage.eventDuration != null) { + assertEquals(mpEvent.length!!, eventMessage.eventDuration!!, .1) + } + if (mpEvent.eventType.name != eventMessage.eventType?.name) { + assertEquals(mpEvent.eventType.name, eventMessage.eventType?.name) + } + val customAttributesTarget = + if (mpEvent.customAttributes == null) mapOf() else mpEvent.customAttributes!! + val customAttributes = mpEvent.customAttributes ?: mapOf() + assertEquals(customAttributesTarget.size, customAttributes.size) + customAttributes + .filter { it.value != customAttributesTarget[it.key] } + .filter { it.value == "null" && customAttributesTarget[it.key] == null } + .filter { it.key != "EventLength" } + .let { + assertEquals("extra keys in message: ${it.entries.joinToString { it.toString() }}", 0, it.size) + } + customAttributesTarget + .filter { !customAttributes.containsKey(it.key) }.let { + assertEquals("missing keys in message: ${it.entries.joinToString { it.toString() }}", 0, it.size) + } + val customFlagTarget = mpEvent.customFlags ?: mapOf() + val customFlags = eventMessage.eventFlags + if (customFlags != null) { + customFlags.keys + .forEach { + with(customFlags[it]) { + when (this) { + is List<*> -> assertArraysEqual(this, customFlagTarget[it] ?: listOf()) + else -> assertEquals(this.toString(), customFlagTarget[it].toString()) + } + } + } + } + } + + @Throws(JSONException::class) + fun assertArraysEqual(messageValue: List<*>, testValue: List) { + val jsonArrayList: MutableList = ArrayList() + for (i in 0 until messageValue.size) { + jsonArrayList.add(messageValue.get(i).toString()) + } + assertEquals(testValue.size.toLong(), jsonArrayList.size.toLong()) + Collections.sort(testValue) + Collections.sort(jsonArrayList) + for (i in testValue.indices) { + val a = testValue[i] + val b = messageValue[i] + if (a == null) { + assertEquals(b, "null") + } else { + assertEquals(a, b) + } + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/WebViewActivity.java b/android-core/src/androidTest/java/com/mparticle/WebViewActivity.java deleted file mode 100644 index 1adbb3f7e..000000000 --- a/android-core/src/androidTest/java/com/mparticle/WebViewActivity.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.mparticle; - -import android.app.Activity; -import android.os.Bundle; -import androidx.annotation.Nullable; -import com.mparticle.test.R; - -public class WebViewActivity extends Activity { - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.web_view_activity); - - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/WebViewActivity.kt b/android-core/src/androidTest/java/com/mparticle/WebViewActivity.kt new file mode 100644 index 000000000..204402ebb --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/WebViewActivity.kt @@ -0,0 +1,12 @@ +package com.mparticle + +import android.app.Activity +import android.os.Bundle +import com.mparticle.test.R + +class WebViewActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.web_view_activity) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/commerce/CommerceApiTest.java b/android-core/src/androidTest/java/com/mparticle/commerce/CommerceApiTest.java deleted file mode 100644 index 41b2b49b7..000000000 --- a/android-core/src/androidTest/java/com/mparticle/commerce/CommerceApiTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.mparticle.commerce; - -import com.mparticle.MParticle; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -import com.mparticle.testutils.BaseCleanStartedEachTest; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Test; - -import static junit.framework.TestCase.assertEquals; - -public class CommerceApiTest extends BaseCleanStartedEachTest { - - - //just verify that we can log an event and it will get sent to the server. Not testing the event message - @Test - public void testCommerceProductEvent() throws InterruptedException { - Product product = new Product.Builder("name", "sku", 10.00) - .build(); - CommerceEvent commerceEvent = new CommerceEvent.Builder(Product.DETAIL, product) - .build(); - MParticle.getInstance().logEvent(commerceEvent); - MParticle.getInstance().upload(); - verifyEventSent(); - } - - //just verify that we can log an event and it will get sent to the server. Not testing the event message - @Test - public void testCommercePromotionEvent() throws InterruptedException { - Promotion promotion = new Promotion() - .setName("name") - .setId("123"); - CommerceEvent commerceEvent = new CommerceEvent.Builder(Promotion.CLICK, promotion) - .build(); - MParticle.getInstance().logEvent(commerceEvent); - MParticle.getInstance().upload(); - verifyEventSent(); - } - - //just verify that we can log an event and it will get sent to the server. Not testing the event message - @Test - public void testCommerceImpressionEvent() throws InterruptedException { - Product product = new Product.Builder("name", "sku", 10.00) - .build(); - Impression impression = new Impression("my impression", product); - CommerceEvent commerceEvent = new CommerceEvent.Builder(impression) - .build(); - MParticle.getInstance().logEvent(commerceEvent); - MParticle.getInstance().upload(); - verifyEventSent(); - } - - private void verifyEventSent() throws InterruptedException { - mServer.waitForVerify(new Matcher(mServer.Endpoints().getEventsUrl()) - .bodyMatch(new MockServer.JSONMatch() { - @Override - public boolean isMatch(JSONObject jsonObject) { - boolean found = false; - JSONArray messagesJSON = jsonObject.optJSONArray("msgs"); - if (messagesJSON != null) { - for (int i = 0; i < messagesJSON.length(); i++) { - JSONObject messageJSON = messagesJSON.optJSONObject(i); - if (messageJSON != null) { - String type = messageJSON.optString("dt"); - if ("cm".equals(type)) { - found = true; - } - } - } - } - return found; - } - })); - } - -} diff --git a/android-core/src/androidTest/java/com/mparticle/commerce/CommerceApiTest.kt b/android-core/src/androidTest/java/com/mparticle/commerce/CommerceApiTest.kt new file mode 100644 index 000000000..cb3966294 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/commerce/CommerceApiTest.kt @@ -0,0 +1,85 @@ +package com.mparticle.commerce + +import com.mparticle.MParticle +import com.mparticle.messages.events.CommerceEventMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import org.junit.Test + +class CommerceApiTest : BaseStartedTest() { + // just verify that we can log an event and it will get sent to the server. Not testing the event message + @Test + @Throws(InterruptedException::class) + fun testCommerceProductEvent() { + val product = Product.Builder("name", "sku", 10.00) + .build() + val commerceEvent = CommerceEvent.Builder(Product.DETAIL, product) + .build() + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .any { it.productActionObject?.action == Product.DETAIL } + } + .after { + MParticle.getInstance()?.apply { + logEvent(commerceEvent) + upload() + } + } + .blockUntilFinished() + } + + // just verify that we can log an event and it will get sent to the server. Not testing the event message + @Test + @Throws(InterruptedException::class) + fun testCommercePromotionEvent() { + val promotion = Promotion() + .setName("name") + .setId("123") + val commerceEvent = CommerceEvent.Builder(Promotion.CLICK, promotion) + .build() + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .any { it.promotionActionObject?.action == Promotion.CLICK } + } + .after { + MParticle.getInstance()?.apply { + logEvent(commerceEvent) + upload() + } + } + .blockUntilFinished() + } + + // just verify that we can log an event and it will get sent to the server. Not testing the event message + @Test + @Throws(InterruptedException::class) + fun testCommerceImpressionEvent() { + val product = Product.Builder("name", "sku", 10.00) + .build() + val impression = Impression("my impression", product) + val commerceEvent = CommerceEvent.Builder(impression) + .build() + + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .any { it.impressionObject?.firstOrNull()?.name == "my impression" } + } + .after { + MParticle.getInstance()?.apply { + logEvent(commerceEvent) + upload() + } + } + .blockUntilFinished() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiITest.kt b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiITest.kt new file mode 100644 index 000000000..f0e58c678 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiITest.kt @@ -0,0 +1,698 @@ +package com.mparticle.identity + +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import com.mparticle.MParticle +import com.mparticle.MParticleTask +import com.mparticle.internal.ConfigManager +import com.mparticle.messages.IdentityResponseMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse +import com.mparticle.utils.randomIdentities +import com.mparticle.utils.setUserIdentity +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.fail +import org.junit.Before +import org.junit.Test +import java.util.UUID +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class IdentityApiITest : BaseStartedTest() { + var mConfigManager: ConfigManager? = null + var handler: Handler? = null + var mpid1: Long = 0 + var mpid2: Long = 0 + var mpid3: Long = 0 + @Before + fun before() { + mConfigManager = MParticle.getInstance()!!.Internal().configManager + handler = Handler() + mpid1 = Random.Default.nextLong() + mpid2 = Random.Default.nextLong() + mpid3 = Random.Default.nextLong() + } + + /** + * test that when we receive a new MParticleUser from and IdentityApi server call, the correct + * MParticleUser object is passed to all the possible callbacks + * - IdentityStateListener + * - MParticleTask + * - MParticle.getInstance().Identity().getCurrentUser() + */ + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testUserChangeCallbackAccuracy() { + val identities: MutableMap = HashMap() + identities[MParticle.IdentityType.Facebook] = "facebooker.me" + identities[MParticle.IdentityType.Email] = "tester@mparticle.gov" + identities[MParticle.IdentityType.Google] = "hello@googlemail.com" + val identities2: MutableMap = HashMap() + identities2[MParticle.IdentityType.CustomerId] = "12345" + identities2[MParticle.IdentityType.Microsoft] = "microsoftUser" + val userAttributes: MutableMap = HashMap() + userAttributes["field1"] = JSONObject("{jsonField1:\"value\", json2:3}") + userAttributes["number2"] = "HelloWorld" + userAttributes["third"] = 123 + val isLoggedIn: Boolean = Random.Default.nextBoolean() + Server.endpoint(EndpointType.Identity_Login).addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + this.responseObject = IdentityResponseMessage(mpid1, isLoggedIn = isLoggedIn) + } + } + val latch: CountDownLatch = FailureLatch() + var count = 0 + MParticle.getInstance()!!.Identity().addIdentityStateListener { user, previousUser -> + if (user.id == mpid1) { + try { + com.mparticle.internal.AccessUtils.awaitMessageHandler() + } catch (e: InterruptedException) { + e.printStackTrace() + } + assertMParticleUserEquals(user, mpid1, identities, null, isLoggedIn) + count++ + if (count == 2) + latch.countDown() + } + } + val request = IdentityApiRequest.withEmptyUser().userIdentities(identities).build() + val result: MParticleTask = + MParticle.getInstance()!!.Identity().login(request) + + // test that change actually took place + result.addSuccessListener { identityApiResult -> + assertMParticleUserEquals(identityApiResult.user, mpid1, identities, null, isLoggedIn) + assertEquals(identityApiResult.previousUser!!.id, mStartingMpid) + latch.countDown() + } + latch.await() + } + + /** + * happy case, tests that IdentityChangedListener works when added, and stays there + * + * @throws Exception + */ + @Test + @Throws(Exception::class) + fun testIdentityChangedListenerAdd() { + Server + .endpoint(EndpointType.Identity_Identify) + .addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid1, isLoggedIn = false) + } + } + .addResponseLogic({ it.body.previousMpid == mpid1 }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid2, isLoggedIn = true) + } + } + val user1Called: Mutable = Mutable(false) + val user2Called: Mutable = Mutable(false) + val user3Called: Mutable = Mutable(false) + var count = 0 + val latch: CountDownLatch = FailureLatch() + MParticle.getInstance()!!.Identity().addIdentityStateListener { user, previousUser -> + if (user.id == mpid1) { + user1Called.value = true + count++ + } + if (user1Called.value && user.id == mpid2) { + user2Called.value = true + count++ + } + if (count == 3) { + latch.countDown() + } + } + var request = IdentityApiRequest.withEmptyUser().build() + var result: MParticleTask = + MParticle.getInstance()!!.Identity().identify(request) + + // test that change actually took place + result.addSuccessListener( + TaskSuccessListener { identityApiResult -> + assertEquals(identityApiResult.user.id, mpid1) + assertEquals(identityApiResult.previousUser!!.id, mStartingMpid) + } + ) + com.mparticle.internal.AccessUtils.awaitUploadHandler() + request = IdentityApiRequest.withEmptyUser().build() + result = MParticle.getInstance()!!.Identity().identify(request) + result.addSuccessListener( + TaskSuccessListener { identityApiResult -> + assertEquals(identityApiResult.user.id, mpid2) + assertEquals( + identityApiResult.user.id, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + assertEquals(identityApiResult.previousUser!!.id, mpid1) + latch.countDown() + user3Called.value = true + } + ) + latch.await() + Assert.assertTrue(user1Called.value) + Assert.assertTrue(user2Called.value) + } + + @Test + @Throws(Exception::class) + fun testAddMultipleIdentityStateListeners() { + Server + .endpoint(EndpointType.Identity_Identify) + .addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid1) + } + } + var count = 0 + val latch: CountDownLatch = FailureLatch() + fun countDown() { + count++ + if (count == 6) { + latch.countDown() + } + } + MParticle.getInstance()!!.Identity() + .addIdentityStateListener { user, previousUser -> countDown() } + MParticle.getInstance()!!.Identity() + .addIdentityStateListener { user, previousUser -> countDown() } + MParticle.getInstance()!!.Identity() + .addIdentityStateListener { user, previousUser -> countDown() } + val request = IdentityApiRequest.withUser( + MParticle.getInstance()!!.Identity().getUser(mpid1) + ).build() + val result: MParticleTask = + MParticle.getInstance()!!.Identity().identify(request) + result + .addSuccessListener { countDown() } + .addSuccessListener { countDown() } + .addSuccessListener { countDown() } + latch.await() + } + + @Test + @Throws(Exception::class) + fun testRemoveIdentityStateListeners() { + Server.endpoint(EndpointType.Identity_Identify) + .addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid1) + } + } + .addResponseLogic({ it.body.previousMpid == mpid1 }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid2) + } + } + val mpid1Latch: CountDownLatch = FailureLatch() + val mpid2Latch: CountDownLatch = FailureLatch() + val keptIdStateListener = IdentityStateListener { user, previousUser -> + if (user.id == mpid1 && previousUser!!.id == mStartingMpid) { + mpid1Latch.countDown() + } + if (user.id == mpid2 && previousUser!!.id == mpid1) { + mpid2Latch.countDown() + } + } + val removeIdStateListener1 = IdentityStateListener { user, previousUser -> + if (user.id != mpid1 || previousUser!!.id != mStartingMpid) { + fail("IdentityStateListener failed to be removed") + } + } + val removeIdStateListener2 = IdentityStateListener { user, previousUser -> + if (user.id != mpid1 || previousUser!!.id != mStartingMpid) { + fail("IdentityStateListener failed to be removed") + } + } + val removeIdStateListener3 = IdentityStateListener { user, previousUser -> + if (user.id != mpid1 || previousUser!!.id != mStartingMpid) { + junit.framework.Assert.fail("IdentityStateListener failed to be removed") + } + } + MParticle.getInstance()!!.Identity().addIdentityStateListener(keptIdStateListener) + MParticle.getInstance()!!.Identity().addIdentityStateListener(removeIdStateListener1) + MParticle.getInstance()!!.Identity().addIdentityStateListener(removeIdStateListener2) + MParticle.getInstance()!!.Identity().addIdentityStateListener(removeIdStateListener3) + MParticle.getInstance()!! + .Identity().identify(IdentityApiRequest.withEmptyUser().build()) + mpid1Latch.await() + MParticle.getInstance()!!.Identity().removeIdentityStateListener(removeIdStateListener1) + MParticle.getInstance()!!.Identity().removeIdentityStateListener(removeIdStateListener2) + MParticle.getInstance()!!.Identity().removeIdentityStateListener(removeIdStateListener3) + MParticle.getInstance()!! + .Identity().identify(IdentityApiRequest.withEmptyUser().build()) + mpid2Latch.await() + } + + /** + * Make sure that the [IdentityStateListener] callbacks are occuring on the Main Thread. + * This is important so that the KitManagerImpl, which will only instantiate kits on the MainThread, + * will instantiate kits synchronously + * @throws InterruptedException + */ + @Test + @Throws(InterruptedException::class) + fun testIdentityStateListenerThread() { + val called: Mutable = Mutable(false) + val latch: CountDownLatch = FailureLatch() + val backgroundThread = HandlerThread(RandomUtils.getAlphaNumericString(8)) + backgroundThread.start() + Handler(backgroundThread.getLooper()).post( + Runnable { + MParticle.getInstance()!!.Identity().addIdentityStateListener { user, previousUser -> + assertEquals(Looper.getMainLooper(), Looper.myLooper()) + assertEquals( + user.id, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + called.value = true + latch.countDown() + } + MParticle.getInstance()!! + .Internal().configManager.setMpid(mpid1, Random.Default.nextBoolean()) + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(InterruptedException::class) + fun testIdentityTransitionListener() { + Server + .endpoint(EndpointType.Identity_Login) + .addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid1) + } + } + val latch: CountDownLatch = FailureLatch() + val called: Mutable = Mutable(false) + MParticle.getInstance()!!.Identity().addIdentityStateListener { newUser, previousUser -> + assertEquals(mStartingMpid, previousUser!!.id) + assertEquals(mpid1, newUser.id) + called.value = true + latch.countDown() + } + MParticle.getInstance()!!.Identity().login() + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(InterruptedException::class) + fun testCallbacksVsCurrentUser() { + Server + .endpoint(EndpointType.Identity_Login) + .addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mpid1) + } + } + var count = 0 + val latch: CountDownLatch = FailureLatch() + val called1: Mutable = Mutable(false) + val called2: Mutable = Mutable(false) + MParticle.getInstance()!!.Identity().addIdentityStateListener { user, previousUser -> + assertEquals( + mpid1, + MParticle.getInstance()!!.Identity().currentUser!! + .id + ) + assertEquals(mpid1, user.id) + assertEquals(mStartingMpid, previousUser!!.id) + called1.value = true + count++ + if (count == 2) { + latch.countDown() + } + } + MParticle.getInstance()!!.Identity().login() + .addSuccessListener { result -> + assertEquals( + mpid1, + MParticle.getInstance()!!.Identity().currentUser!! + .id + ) + assertEquals(mpid1, result.user.id) + assertEquals(mStartingMpid, result.previousUser!!.id) + called2.value = true + count++ + if (count == 2) { + latch.countDown() + } + } + latch.await() + Assert.assertTrue(called1.value) + Assert.assertTrue(called2.value) + } + + private fun assertMParticleUserEquals( + dto1: MParticleUser?, + mpid: Long, + identityTypes: Map, + userAttributes: Map?, + isLoggedIn: Boolean + ) { + Assert.assertTrue(dto1!!.id == mpid) + if (userAttributes != null) { + if (dto1.userAttributes != null) { + assertEquals(dto1.userAttributes.size.toLong(), userAttributes.size.toLong()) + for ((key, value) in dto1.userAttributes) { + if (value == null) { + Assert.assertNull(userAttributes[key]) + } else { + assertEquals(value.toString(), userAttributes[key].toString()) + } + } + } + } else { + assertEquals(dto1.userAttributes.size.toLong(), 0) + } + assertEquals(dto1.userIdentities.size.toLong(), identityTypes.size.toLong()) + for ((key, value) in dto1.userIdentities) { + assertEquals(value, identityTypes[key]) + } + assertEquals(isLoggedIn, dto1.isLoggedIn) + } + + @Test + @Throws(Exception::class) + fun testGetUser() { + val identity = MParticle.getInstance()!! + .Identity() + Assert.assertNotNull(identity.currentUser) + MParticle.getInstance()!!.Internal().configManager.setMpid(mpid1, true) + assertEquals(identity.currentUser!!.id, mpid1) + val mpid1UserAttributes = + RandomUtils.getRandomAttributes(3).toMutableMap() + val mpid1UserIdentites: Map = + randomIdentities(2) + identity.currentUser!!.userAttributes = mpid1UserAttributes.toMap() + AccessUtils.setUserIdentities(mpid1UserIdentites.toMap(), identity.currentUser!!.id) + MParticle.getInstance()!!.Internal().configManager.setMpid(mpid2, false) + val mpid2UserAttributes = + RandomUtils.getRandomAttributes(3).toMutableMap() + val mpid2UserIdentites: Map = + randomIdentities(3) + identity.currentUser!!.userAttributes = mpid2UserAttributes.toMap() + AccessUtils.setUserIdentities(mpid2UserIdentites.toMap(), identity.currentUser!!.id) + MParticle.getInstance()!!.Internal().configManager.setMpid(mpid3, true) + val mpid3UserAttributes = + RandomUtils.getRandomAttributes(3).toMutableMap() + val mpid3UserIdentities: Map = + randomIdentities(2) + identity.currentUser!!.userAttributes = mpid3UserAttributes.toMap() + AccessUtils.setUserIdentities(mpid3UserIdentities.toMap(), identity.currentUser!!.id) + mpid1UserAttributes.remove(null) + mpid2UserAttributes.remove(null) + mpid3UserAttributes.remove(null) + com.mparticle.internal.AccessUtils.awaitMessageHandler() + + // should return null for mpid = 0 + Assert.assertNull(identity.getUser(0L)) + + // should return an MParticleUser with the correct mpid, userIdentities, and userAttributes for + // previously seen users + assertMParticleUserEquals( + identity.getUser(mpid1), + mpid1, + mpid1UserIdentites, + mpid1UserAttributes, + true + ) + assertMParticleUserEquals( + identity.getUser(mpid2), + mpid2, + mpid2UserIdentites, + mpid2UserAttributes, + false + ) + assertMParticleUserEquals( + identity.getUser(mpid3), + mpid3, + mpid3UserIdentities, + mpid3UserAttributes, + true + ) + + // should return null for unseen mpid's + Assert.assertNull(identity.getUser(RandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE))) + Assert.assertNull(identity.getUser(RandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE))) + Assert.assertNull(identity.getUser(RandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE))) + } + + /** + * this simulates the scenerio in which you make a modify() call, but the current MParticleUser + * changes between the time you build the request and the time you make the call + */ + @Test + @Throws(Exception::class) + fun testModifyConcurrentCalls() { + assertEquals( + mStartingMpid, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + val userIdentities: Map = + randomIdentities() + for (identity in userIdentities.keys) { + setUserIdentity(userIdentities[identity], identity, mStartingMpid) + } + val request = IdentityApiRequest.withUser( + MParticle.getInstance()!!.Identity().currentUser + ).customerId(RandomUtils.getAlphaNumericString(24)).build() + Server.endpoint(EndpointType.Identity_Modify) + .assertWillReceive { it.body.identityChanges?.size == 1 } + .after { MParticle.getInstance()!!.Identity().modify(request) } + .blockUntilFinished() + + // change the mpid; + // behind the scenes, this call will take place before the (above) modify request goes out, since + // the modify request will be passed to a background thread before it is executed + MParticle.getInstance()!!.Internal().configManager.setMpid(mpid2, Random.Default.nextBoolean()) + } + + @Test + fun testGetUsersApi() { + // test that by default there is only the starting user + assertEquals(MParticle.getInstance()!!.Identity().users.size.toLong(), 1) + assertEquals(MParticle.getInstance()!!.Identity().users[0].id, mStartingMpid) + + // add 5 Users + val mpids: MutableList = ArrayList() + mpids.add(mStartingMpid) + for (i in 0..4) { + mpids.add(Random.Default.nextLong()) + } + for (mpid in mpids) { + MParticle.getInstance()!! + .Internal().configManager.setMpid(mpid, Random.Default.nextBoolean()) + } + + // test that there are now 6 users present in the getUsers() endpoint + assertEquals( + MParticle.getInstance()!!.Identity().users.size.toLong(), + mpids.size.toLong() + ) + + // test that they are the same users we added before + for ( + mParticleUser in MParticle.getInstance()!! + .Identity().users + ) { + Assert.assertTrue(mpids.contains(mParticleUser.id)) + } + + // remove 2 users + for (i in 0..1) { + MParticle.getInstance()!!.Internal().configManager.deleteUserStorage(mpids.removeAt(i)) + } + + // test that there are now 4 remaining users + assertEquals(MParticle.getInstance()!!.Identity().users.size.toLong(), 4) + + // test that they are the correct users + for ( + mParticleUser in MParticle.getInstance()!! + .Identity().users + ) { + Assert.assertTrue(mpids.contains(mParticleUser.id)) + } + } + + /** + * make sure that there is no way for an MParticleUser with MPID == 0 to be returned from the + * IdentityAPI + */ + @Test + fun testNoZeroMpidUser() { + Assert.assertNull(MParticle.getInstance()!!.Identity().getUser(0L)) + for ( + user in MParticle.getInstance()!! + .Identity().users + ) { + junit.framework.Assert.assertNotSame(0, user.id) + } + MParticle.getInstance()!!.Internal().configManager.setMpid(0L, Random.Default.nextBoolean()) + Assert.assertNull(MParticle.getInstance()!!.Identity().getUser(0L)) + for ( + user in MParticle.getInstance()!! + .Identity().users + ) { + junit.framework.Assert.assertNotSame(0, user.id) + } + } + + @Test + @Throws(InterruptedException::class) + fun testGetDeviceApplicationStamp() { + val dasLength = UUID.randomUUID().toString().length + val currentDas = MParticle.getInstance()!!.Identity().deviceApplicationStamp + assertEquals(dasLength.toLong(), currentDas.length.toLong()) + assertEquals(currentDas, MParticle.getInstance()!!.Identity().deviceApplicationStamp) + MParticle.reset(context) + startMParticle() + val newDas = MParticle.getInstance()!!.Identity().deviceApplicationStamp + Assert.assertNotNull(newDas) + junit.framework.Assert.assertNotSame(currentDas, newDas) + } + + @Test + @Throws(InterruptedException::class) + fun testModifyWhenIdentityAddedConcurrently() { + val latch: CountDownLatch = FailureLatch() + val currentUser = MParticle.getInstance()!! + .Identity().currentUser + val identityApi = MParticle.getInstance()!! + .Identity() + val modifyRequest = IdentityApiRequest.withUser(currentUser) + .pushToken("new push", "old_push") + .build() + val taskSuccessListener = TaskSuccessListener { + + Server + .endpoint(EndpointType.Identity_Modify) + .assertWillReceive { + it.body.identityChanges?.let { + assertEquals(1, it.size) + it[0].apply { + identityType == "push_token" + } + true + } ?: false + } + .after { + identityApi.modify(modifyRequest) + } + .blockUntilFinished() + latch.countDown() + } + val loginRequest = IdentityApiRequest.withUser(currentUser) + .customerId("my Id") + .build() + identityApi + .login(loginRequest) + .addSuccessListener(taskSuccessListener) + latch.await() + } + + @Test + @Throws(InterruptedException::class) + fun testModifyWhenIdentityChangesConcurrently() { + val latch: CountDownLatch = FailureLatch() + val currentUser = MParticle.getInstance()!! + .Identity().currentUser + val identityApi = MParticle.getInstance()!! + .Identity() + val modifyRequest = IdentityApiRequest.withUser(currentUser) + .customerId("new customer ID") + .build() + val taskSuccessListener = TaskSuccessListener { + identityApi.modify(modifyRequest) + Server + .endpoint(EndpointType.Identity_Modify) + .assertWillReceive { + it.body.identityChanges?.let { + assertEquals(1, it.size) + it[0].apply { + assertEquals("customerid", identityType) + assertEquals("new customer ID", newValue) + assertEquals("old customer ID", oldValue) + } + true + } ?: false + } + .blockUntilFinished() + latch.countDown() + } + val loginRequest = IdentityApiRequest.withUser(currentUser) + .customerId("old customer ID") + .build() + identityApi + .login(loginRequest) + .addSuccessListener(taskSuccessListener) + latch.await() + } + + @Test + @Throws(InterruptedException::class) + fun testModifyDoesntMissIdentitiesSetNull() { + setUserIdentity("customer Id", MParticle.IdentityType.CustomerId, mStartingMpid) + setUserIdentity("facebook Id", MParticle.IdentityType.Facebook, mStartingMpid) + setUserIdentity("other Id", MParticle.IdentityType.Other2, mStartingMpid) + + Server + .endpoint(EndpointType.Identity_Modify) + .assertWillReceive { + it.body.identityChanges?.let { + assertEquals(3, it.size) + it + .first { it.identityType == "customerid" } + .apply { + assertEquals("customer Id", oldValue) + assertEquals(null, newValue) + } + it + .first { it.identityType == "facebook" } + .apply { + assertEquals("facebook Id", oldValue) + assertEquals(null, newValue) + } + it + .first { it.identityType == "other2" } + .apply { + assertEquals("other Id", oldValue) + assertEquals(null, newValue) + } + true + } ?: false + } + .after { + val request = IdentityApiRequest.withUser( + MParticle.getInstance()!!.Identity().currentUser + ) + .customerId(null) + .userIdentity(MParticle.IdentityType.Facebook, null) + .userIdentity(MParticle.IdentityType.Other2, null) + .build() + MParticle.getInstance()!!.Identity().modify(request) + } + .blockUntilFinished() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiOutgoingTest.java b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiOutgoingTest.java deleted file mode 100644 index 68fafbd1c..000000000 --- a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiOutgoingTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.mparticle.identity; - -import com.mparticle.MParticle; -import com.mparticle.networking.IdentityRequest; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.MockServer.IdentityMatcher; -import com.mparticle.testutils.BaseCleanStartedEachTest; - -import org.junit.Test; - -public final class IdentityApiOutgoingTest extends BaseCleanStartedEachTest { - - @Test - public void testLogin() throws Exception { - MParticle.getInstance().Identity().login(); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getLoginUrl()).bodyMatch(new IdentityMatcher() { - @Override - protected boolean isIdentityMatch(IdentityRequest.IdentityRequestBody identityRequest) { - return mStartingMpid.equals(identityRequest.previousMpid); - } - })); - } - - @Test - public void testLoginNonEmpty() throws Exception { - MParticle.getInstance().Identity().login(IdentityApiRequest.withEmptyUser().build()); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getLoginUrl()).bodyMatch(new IdentityMatcher() { - @Override - protected boolean isIdentityMatch(IdentityRequest.IdentityRequestBody identityRequest) { - return mStartingMpid.equals(identityRequest.previousMpid); - } - })); - } - - @Test - public void testLogout() throws Exception { - MParticle.getInstance().Identity().logout(); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getLogoutUrl()).bodyMatch(new IdentityMatcher() { - @Override - protected boolean isIdentityMatch(IdentityRequest.IdentityRequestBody identityRequest) { - return mStartingMpid.equals(identityRequest.previousMpid); - } - })); - } - - @Test - public void testLogoutNonEmpty() throws Exception { - MParticle.getInstance().Identity().logout(IdentityApiRequest.withEmptyUser().build()); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getLogoutUrl()).bodyMatch(new IdentityMatcher() { - @Override - protected boolean isIdentityMatch(IdentityRequest.IdentityRequestBody identityRequest) { - return mStartingMpid.equals(identityRequest.previousMpid); - } - })); - } - - @Test - public void testModify() throws Exception { - MParticle.getInstance().Identity().modify(IdentityApiRequest.withEmptyUser().customerId(ran.nextLong() + "").build()); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getModifyUrl(mStartingMpid))); - } - - @Test - public void testIdentify() throws Exception { - MParticle.getInstance().Identity().identify(IdentityApiRequest.withEmptyUser().build()); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getIdentifyUrl()).bodyMatch(new IdentityMatcher() { - @Override - protected boolean isIdentityMatch(IdentityRequest.IdentityRequestBody identityRequest) { - return mStartingMpid.equals(identityRequest.previousMpid); - } - })); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiOutgoingTest.kt b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiOutgoingTest.kt new file mode 100644 index 000000000..81dd13fb2 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiOutgoingTest.kt @@ -0,0 +1,85 @@ +package com.mparticle.identity + +import com.mparticle.MParticle +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import org.junit.Test +import kotlin.random.Random + +class IdentityApiOutgoingTest : BaseStartedTest() { + @Test + @Throws(Exception::class) + fun testLogin() { + Server.endpoint(EndpointType.Identity_Login) + .assertWillReceive { it.body.previousMpid == mStartingMpid } + .after { + MParticle.getInstance()?.Identity()?.login() + } + .blockUntilFinished() + } + + @Test + @Throws(Exception::class) + fun testLoginNonEmpty() { + Server + .endpoint(EndpointType.Identity_Login) + .assertWillReceive { it.body.previousMpid == mStartingMpid } + .after { MParticle.getInstance()?.Identity()?.login() } + .blockUntilFinished() + } + + @Test + @Throws(Exception::class) + fun testLogout() { + Server + .endpoint(EndpointType.Identity_Logout) + .assertWillReceive { it.body.previousMpid == mStartingMpid } + .after { MParticle.getInstance()?.Identity()?.logout() } + .blockUntilFinished() + } + + @Test + @Throws(Exception::class) + fun testLogoutNonEmpty() { + Server + .endpoint(EndpointType.Identity_Logout) + .assertWillReceive { it.body.previousMpid == mStartingMpid } + .after { MParticle.getInstance()?.Identity()?.logout(IdentityApiRequest.withEmptyUser().build()) } + .blockUntilFinished() + } + + @Test + @Throws(Exception::class) + fun testModify() { + val customerId = Random.Default.nextLong().toString() + Server + .endpoint(EndpointType.Identity_Modify) + .assertWillReceive { request -> + request.body.identityChanges?.let { + it.size == 1 && + it[0].identityType == "customerid" && + it[0].newValue == customerId && + it[0].oldValue == null + } ?: false + } + .after { + MParticle.getInstance()?.Identity()?.modify( + IdentityApiRequest.withEmptyUser() + .customerId(customerId) + .build() + ) + } + .blockUntilFinished() + } + + @Test + @Throws(Exception::class) + fun testIdentify() { + Server + .endpoint(EndpointType.Identity_Identify) + .assertWillReceive { it.body.previousMpid == mStartingMpid } + .after { MParticle.getInstance()?.Identity()?.identify(IdentityApiRequest.withEmptyUser().build()) } + .blockUntilFinished() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiStartTest.java b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiStartTest.java deleted file mode 100644 index 6ccce72bc..000000000 --- a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiStartTest.java +++ /dev/null @@ -1,314 +0,0 @@ -package com.mparticle.identity; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.internal.ConfigManager; -import com.mparticle.internal.MPUtility; -import com.mparticle.networking.IdentityRequest; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -import com.mparticle.testutils.AndroidUtils.Mutable; -import com.mparticle.testutils.BaseCleanInstallEachTest; -import com.mparticle.testutils.MPLatch; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static junit.framework.Assert.fail; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertNull; - -public final class IdentityApiStartTest extends BaseCleanInstallEachTest { - - @Test - public void testInitialIdentitiesPresentWithAndroidId() throws Exception { - final Map identities = mRandomUtils.getRandomUserIdentities(); - - IdentityApiRequest request = IdentityApiRequest.withEmptyUser() - .userIdentities(identities) - .build(); - startMParticle(MParticleOptions.builder(mContext) - .androidIdEnabled(true) - .identify(request)); - - assertTrue(mServer.Requests().getIdentify().size() == 1); - assertIdentitiesMatch(mServer.Requests().getIdentify().get(0), identities, true); - } - - @Test - public void testInitialIdentitiesPresentWithoutAndroidId() throws Exception { - final Map identities = mRandomUtils.getRandomUserIdentities(); - - IdentityApiRequest request = IdentityApiRequest.withEmptyUser() - .userIdentities(identities) - .build(); - startMParticle(MParticleOptions.builder(mContext) - .androidIdEnabled(false) - .identify(request)); - - assertTrue(mServer.Requests().getIdentify().size() == 1); - assertIdentitiesMatch(mServer.Requests().getIdentify().get(0), identities, false); - } - - - @Test - public void testNoInitialIdentityNoStoredIdentity() throws Exception { - startMParticle(); - - assertEquals(mServer.Requests().getIdentify().size(), 1); - assertIdentitiesMatch(mServer.Requests().getIdentify().get(0), new HashMap<>(), false); - } - - @Test - public void testNoInitialIdentity() throws Exception { - - final Long currentMpid = ran.nextLong(); - final Map identities = mRandomUtils.getRandomUserIdentities(); - - startMParticle(); - - MParticle.getInstance().Internal().getConfigManager().setMpid(currentMpid, ran.nextBoolean()); - - for (Map.Entry entry : identities.entrySet()) { - AccessUtils.setUserIdentity(entry.getValue(), entry.getKey(), currentMpid); - } - com.mparticle.internal.AccessUtils.awaitMessageHandler(); - - mServer = MockServer.getNewInstance(mContext); - startMParticle(); - - assertEquals(mServer.Requests().getIdentify().size(), 1); - assertIdentitiesMatch(mServer.Requests().getIdentify().get(0), identities, false); - } - - /** - * This asserts that when the SDK receives a new Push InstanceId in the background, it will send - * a modify request with the background change when the SDK starts up, unless there is a pushRegistration - * included in the startup object. Make sure the Push InstanceId logged in the background is deleted - * after it is used in the modify() request - */ - @Test - public void testLogNotificationBackgroundTest() throws InterruptedException { - assertNull(ConfigManager.getInstance(mContext).getPushInstanceId()); - final String instanceId = mRandomUtils.getAlphaNumericString(10); - com.mparticle.internal.AccessUtils.setPushInPushRegistrationHelper(mContext, instanceId, mRandomUtils.getAlphaNumericString(15)); - - final Mutable called = new Mutable(false); - CountDownLatch latch = new MPLatch(1); - /** - * This tests that a modify request is sent when the previous Push InstanceId is empty, with the value of "null" - */ - 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); - - assertEquals("null", identityChange.getString("old_value")); - assertEquals(instanceId, identityChange.getString("new_value")); - assertEquals("push_token", identityChange.getString("identity_type")); - called.value = true; - } catch (JSONException jse) { - jse.toString(); - } - return true; - } - return false; - } - }), latch); - - startMParticle(); - latch.await(); - assertTrue(called.value); - - MParticle.setInstance(null); - called.value = false; - - final String newInstanceId = mRandomUtils.getAlphaNumericString(15); - com.mparticle.internal.AccessUtils.setPushInPushRegistrationHelper(mContext, newInstanceId, mRandomUtils.getAlphaNumericString(15)); - - - latch = new CountDownLatch(1); - /** - * tests that the modify request was made with the correct value for the instanceId set while - * the SDK was stopped - */ - 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); - - assertEquals(instanceId, identityChange.getString("old_value")); - assertEquals(newInstanceId, identityChange.getString("new_value")); - assertEquals("push_token", identityChange.getString("identity_type")); - called.value = true; - } catch (JSONException jse) { - jse.toString(); - } - return true; - } - return false; - } - }), latch); - - startMParticle(); - latch.await(); - assertTrue(called.value); - } - - private void assertIdentitiesMatch(Request request, Map identities, boolean androidIdEnabled) throws Exception { - assertTrue(request instanceof IdentityRequest); - IdentityRequest identityRequest = request.asIdentityRequest(); - assertNotNull(identityRequest); - - JSONObject knownIdentities = identityRequest.getBody().known_identities; - assertNotNull(knownIdentities); - - if (androidIdEnabled) { - assertNotNull(knownIdentities.remove("android_uuid")); - } else { - assertFalse(knownIdentities.has("android_uuid")); - } - assertNotNull(knownIdentities.remove("device_application_stamp")); - - assertEquals(knownIdentities.length(), identities.size()); - - Iterator keys = knownIdentities.keys(); - Map copy = new HashMap(identities); - - while (keys.hasNext()) { - String key = keys.next(); - assertEquals(copy.get(MParticleIdentityClientImpl.getIdentityType(key)), knownIdentities.getString(key)); - } - } - - /** - * In this scenario, a logPushRegistration's modify request is made when the current MPID is 0. Previously - * the method's modify request would failed when a valid MPID wasn't present, but currently we will - * defer the request until a valid MPID is present. - * - * Additionally, this tests that if the logPushRegistration method is called multiple times (for whatever reason) - * before a valid MPID is present, we will ignore the previous values, and only send the most recent request. - * This would be good in a case where the device is offline for a period of time, and logPushNotification - * request back up. - * @throws InterruptedException - */ - @Test - public void testPushRegistrationModifyRequest() throws InterruptedException, JSONException { - final Long startingMpid = ran.nextLong(); - mServer.setupHappyIdentify(startingMpid, 200); - final Mutable logPushRegistrationCalled = new Mutable(false); - final CountDownLatch identifyLatch = new MPLatch(1); - final CountDownLatch modifyLatch = new MPLatch(1); - - MParticle.start(MParticleOptions.builder(mContext).credentials("key", "value").build()); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(MParticleUser user, MParticleUser previousUser) { - assertTrue(logPushRegistrationCalled.value); - identifyLatch.countDown(); - MParticle.getInstance().Identity().removeIdentityStateListener(this); - } - }); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getModifyUrl(startingMpid)), modifyLatch); - - String pushRegistration = null; - for (int i = 0; i < 5; i++) { - MParticle.getInstance().logPushRegistration(pushRegistration = mRandomUtils.getAlphaString(12), "senderId"); - } - logPushRegistrationCalled.value = true; - - identifyLatch.await(); - modifyLatch.await(); - - List modifyRequests = mServer.Requests().getModify(); - assertEquals(1, modifyRequests.size()); - JSONObject body = modifyRequests.get(0).getBodyJson(); - JSONArray identityChanges = body.getJSONArray("identity_changes"); - assertEquals(1, identityChanges.length()); - JSONObject identityChange = identityChanges.getJSONObject(0); - assertEquals(pushRegistration, identityChange.getString("new_value")); - assertEquals("push_token", identityChange.getString("identity_type")); - - //make sure the mDeferredModifyPushRegistrationListener was successfully removed from the IdentityApi - assertEquals(0, AccessUtils.getIdentityStateListeners().size()); - } - - @Test - public void testOperatingSystemSetProperly() throws InterruptedException { - final Mutable called = new Mutable(false); - final CountDownLatch latch = new MPLatch(1); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getIdentifyUrl()), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - assertEquals("fire", request.asIdentityRequest().getBody().clientSdk.platform); - called.value = true; - latch.countDown(); - } - }); - MParticle.start(MParticleOptions.builder(mContext) - .credentials("key", "secret") - .operatingSystem(MParticle.OperatingSystem.FIRE_OS) - .build()); - latch.await(); - assertTrue(called.value); - - MParticle.setInstance(null); - called.value = false; - final CountDownLatch latch1 = new MPLatch(1); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getIdentifyUrl()), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - assertEquals("fire", request.asIdentityRequest().getBody().clientSdk.platform); - called.value = true; - latch1.countDown(); - } - }); - MParticle.start(MParticleOptions.builder(mContext) - .credentials("key", "secret") - .operatingSystem(MParticle.OperatingSystem.FIRE_OS) - .build()); - latch1.await(); - assertTrue(called.value); - } - - /** - * This builds on the previous test. The common scenario where we send a modify() request - * when a valid MPID is not present, is when a client sets a pushRegistration in MParticleOptions - * on the applications initial install - */ - @Test - public void testPushRegistrationInMParticleOptions() { - Exception ex = null; - try { - startMParticle(MParticleOptions - .builder(mContext) - .pushRegistration("instanceId", "senderId") - .environment(MParticle.Environment.Development)); - assertTrue(MPUtility.isDevEnv()); - } catch (Exception e) { - ex = e; - } - assertNull(ex); - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiStartTest.kt b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiStartTest.kt new file mode 100644 index 000000000..8f37ce276 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiStartTest.kt @@ -0,0 +1,266 @@ +package com.mparticle.identity + +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.internal.ConfigManager +import com.mparticle.internal.MPUtility +import com.mparticle.testing.BaseTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.utils.randomIdentities +import com.mparticle.utils.setUserIdentity +import com.mparticle.utils.startMParticle +import junit.framework.TestCase +import org.json.JSONException +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Test +import kotlin.random.Random + +class IdentityApiStartTest : BaseTest() { + + @Test + @Throws(Exception::class) + fun testInitialIdentitiesPresentWithAndroidId() { + val identities: Map = randomIdentities() + val request = IdentityApiRequest.withEmptyUser() + .userIdentities(identities) + .build() + startMParticle( + MParticleOptions.builder(context) + .androidIdEnabled(true) + .identify(request) + ) + Server.endpoint(EndpointType.Identity_Identify).requests.let { + assertEquals(1, it.size) + assertIdentitiesMatch(it[0].request.body.knownIdentities, identities, true) + } + } + + @Test + @Throws(Exception::class) + fun testInitialIdentitiesPresentWithoutAndroidId() { + val identities: Map = randomIdentities() + val request = IdentityApiRequest.withEmptyUser() + .userIdentities(identities) + .build() + startMParticle( + MParticleOptions.builder(context) + .androidIdEnabled(false) + .identify(request) + ) + Server.endpoint(EndpointType.Identity_Identify).requests.let { + assertEquals(1, it.size) + assertIdentitiesMatch(it[0].request.body.knownIdentities, identities, false) + } + } + + @Test + @Throws(Exception::class) + fun testNoInitialIdentityNoStoredIdentity() { + startMParticle() + Server.endpoint(EndpointType.Identity_Identify).requests.let { + assertEquals(1, it.size) + assertIdentitiesMatch(it[0].request.body.knownIdentities, mapOf(), false) + } + } + + @Test + @Throws(Exception::class) + fun testNoInitialIdentity() { + val currentMpid: Long = Random.Default.nextLong() + val identities: Map = randomIdentities() + startMParticle() + MParticle.getInstance()!! + .Internal().configManager.setMpid(currentMpid, Random.Default.nextBoolean()) + for ((key, value) in identities) { + setUserIdentity(value, key, currentMpid) + } + com.mparticle.internal.AccessUtils.awaitMessageHandler() + startMParticle() + Server.endpoint(EndpointType.Identity_Identify).requests.let { + assertEquals(2, it.size) + assertIdentitiesMatch(it[1].request.body.knownIdentities, identities, false) + } + } + + /** + * This asserts that when the SDK receives a new Push InstanceId in the background, it will send + * a modify request with the background change when the SDK starts up, unless there is a pushRegistration + * included in the startup object. Make sure the Push InstanceId logged in the background is deleted + * after it is used in the modify() request + */ + @Test + @Throws(InterruptedException::class) + fun testLogNotificationBackgroundTest() { + TestCase.assertNull(ConfigManager.getInstance(context).getPushInstanceId()) + val instanceId: String = RandomUtils.getAlphaNumericString(10) + com.mparticle.internal.AccessUtils.setPushInPushRegistrationHelper( + context, + instanceId, + RandomUtils.getAlphaNumericString(15) + ) + /** + * This tests that a modify request is sent when the previous Push InstanceId is empty, with the value of "null" + */ + Server + .endpoint(EndpointType.Identity_Modify) + .assertWillReceive { + it.body.identityChanges?.let { + assertEquals(1, it.size) + it[0].apply { + assertEquals(instanceId, newValue) + assertNull(oldValue) + assertEquals("push_token", identityType) + } + true + } ?: false + } + .after { startMParticle() } + .blockUntilFinished() + + MParticle.setInstance(null) + val newInstanceId: String = RandomUtils.getAlphaNumericString(15) + com.mparticle.internal.AccessUtils.setPushInPushRegistrationHelper( + context, + newInstanceId, + RandomUtils.getAlphaNumericString(15) + ) + /** + * tests that the modify request was made with the correct value for the instanceId set while + * the SDK was stopped + */ + Server + .endpoint(EndpointType.Identity_Modify) + .assertWillReceive { + it.body.identityChanges?.let { + assertEquals(1, it.size) + it[0].apply { + assertEquals(instanceId, oldValue) + assertEquals(newInstanceId, newValue) + assertEquals("push_token", identityType) + } + true + } ?: false + } + .after { startMParticle() } + .blockUntilFinished() + } + + @Throws(Exception::class) + private fun assertIdentitiesMatch( + receivedIdentities: Map?, + testIdentities: Map, + androidIdEnabled: Boolean + ) { + val knownIdentitiesCopy = receivedIdentities!!.toMutableMap() + if (androidIdEnabled) { + assertNotNull(knownIdentitiesCopy.remove("android_uuid")) + } else { + assertFalse(knownIdentitiesCopy.containsKey("android_uuid")) + } + assertNotNull(knownIdentitiesCopy.remove("device_application_stamp")) + assertEquals(testIdentities.size, knownIdentitiesCopy.size) + receivedIdentities.forEach { + assertEquals("${it.key} identity type does not match", knownIdentitiesCopy[it.key], testIdentities[MParticleIdentityClientImpl.getIdentityType(it.key)]) + } + } + + /** + * In this scenario, a logPushRegistration's modify request is made when the current MPID is 0. Previously + * the method's modify request would failed when a valid MPID wasn't present, but currently we will + * defer the request until a valid MPID is present. + * + * Additionally, this tests that if the logPushRegistration method is called multiple times (for whatever reason) + * before a valid MPID is present, we will ignore the previous values, and only send the most recent request. + * This would be good in a case where the device is offline for a period of time, and logPushNotification + * request back up. + * @throws InterruptedException + */ + @Test + @Throws(InterruptedException::class, JSONException::class) + fun testPushRegistrationModifyRequest() { + var pushRegistration: String? = null + MParticle.start(MParticleOptions.builder(context).credentials("key", "secret").build()) + (0 until 4).forEach { + MParticle.getInstance()!! + .logPushRegistration( + RandomUtils.getAlphaString(12).also { pushRegistration = it }, + "senderId" + ) + } + MParticle.getInstance()?.Identity()!!.let { + assertNull(it.currentUser) + it.addIdentityStateListener { _, _ -> + Server + .endpoint(EndpointType.Identity_Modify) + .assertNextRequest { + it.url.contains(mStartingMpid.toString()) && + it.body.identityChanges?.let { changes -> + changes.size == 0 && + changes[0].identityType == "push_token" && + changes[0].newValue == pushRegistration + } ?: false + } + .after {} + .blockUntilFinished() + } + } + } + + @Test + @Throws(InterruptedException::class) + fun testOperatingSystemSetProperly() { + Server + .endpoint(EndpointType.Identity_Identify) + .assertWillReceive { it.body.clientSdk?.platform == "fire" } + .after { + MParticle.start( + MParticleOptions.builder(context) + .credentials("key", "secret") + .operatingSystem(MParticle.OperatingSystem.FIRE_OS) + .build() + ) + } + .blockUntilFinished() + MParticle.setInstance(null) + Server + .endpoint(EndpointType.Identity_Identify) + .assertWillReceive { it.body.clientSdk?.platform == "fire" } + .after { + MParticle.start( + MParticleOptions.builder(context) + .credentials("key", "secret") + .operatingSystem(MParticle.OperatingSystem.FIRE_OS) + .build() + ) + } + } + + /** + * This builds on the previous test. The common scenario where we send a modify() request + * when a valid MPID is not present, is when a client sets a pushRegistration in MParticleOptions + * on the applications initial install + */ + @Test + fun testPushRegistrationInMParticleOptions() { + var ex: Exception? = null + try { + startMParticle( + MParticleOptions + .builder(context) + .pushRegistration("instanceId", "senderId") + .environment(MParticle.Environment.Development) + ) + Assert.assertTrue(MPUtility.isDevEnv()) + } catch (e: Exception) { + ex = e + } + TestCase.assertNull(ex) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiTest.java b/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiTest.java deleted file mode 100644 index 8c320928d..000000000 --- a/android-core/src/androidTest/java/com/mparticle/identity/IdentityApiTest.java +++ /dev/null @@ -1,669 +0,0 @@ -package com.mparticle.identity; - -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.mparticle.MParticle; -import com.mparticle.MParticleTask; -import com.mparticle.internal.ConfigManager; -import com.mparticle.networking.Matcher; -import com.mparticle.networking.MockServer; -import com.mparticle.networking.Request; -import com.mparticle.testutils.AndroidUtils.Mutable; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static junit.framework.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static junit.framework.Assert.fail; - -public final class IdentityApiTest extends BaseCleanStartedEachTest { - ConfigManager mConfigManager; - Handler handler; - long mpid1, mpid2, mpid3; - - @Before - public void before() { - mConfigManager = MParticle.getInstance().Internal().getConfigManager(); - handler = new Handler(); - mpid1 = ran.nextLong(); - mpid2 = ran.nextLong(); - mpid3 = ran.nextLong(); - } - - /** - * test that when we receive a new MParticleUser from and IdentityApi server call, the correct - * MParticleUser object is passed to all the possible callbacks - * - IdentityStateListener - * - MParticleTask - * - MParticle.getInstance().Identity().getCurrentUser() - */ - @Test - public void testUserChangeCallbackAccuracy() throws JSONException, InterruptedException { - final Map identities = new HashMap(); - identities.put(MParticle.IdentityType.Facebook, "facebooker.me"); - identities.put(MParticle.IdentityType.Email, "tester@mparticle.gov"); - identities.put(MParticle.IdentityType.Google, "hello@googlemail.com"); - final Map identities2 = new HashMap(); - identities2.put(MParticle.IdentityType.CustomerId, "12345"); - identities2.put(MParticle.IdentityType.Microsoft, "microsoftUser"); - final Map userAttributes = new HashMap(); - userAttributes.put("field1", new JSONObject("{jsonField1:\"value\", json2:3}")); - userAttributes.put("number2", "HelloWorld"); - userAttributes.put("third", 123); - - final boolean isLoggedIn = ran.nextBoolean(); - - mServer.addConditionalLoginResponse(mStartingMpid, mpid1, isLoggedIn); - - final CountDownLatch latch = new MPLatch(2); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(MParticleUser user, MParticleUser previousUser) { - if (user.getId() == mpid1) { - try { - com.mparticle.internal.AccessUtils.awaitMessageHandler(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - assertMParticleUserEquals(user, mpid1, identities, null, isLoggedIn); - latch.countDown(); - } - } - }); - - IdentityApiRequest request = IdentityApiRequest.withEmptyUser().userIdentities(identities).build(); - MParticleTask result = MParticle.getInstance().Identity().login(request); - - //test that change actually took place - result.addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult identityApiResult) { - assertMParticleUserEquals(identityApiResult.getUser(), mpid1, identities, null, isLoggedIn); - assertEquals(identityApiResult.getPreviousUser().getId(), mStartingMpid.longValue()); - latch.countDown(); - } - }); - latch.await(); - } - - - /** - * happy case, tests that IdentityChangedListener works when added, and stays there - * - * @throws Exception - */ - @Test - public void testIdentityChangedListenerAdd() throws Exception { - mServer - .addConditionalIdentityResponse(mStartingMpid, mpid1, false) - .addConditionalIdentityResponse(mpid1, mpid2, true); - - final Mutable user1Called = new Mutable(false); - final Mutable user2Called = new Mutable(false); - final Mutable user3Called = new Mutable(false); - final CountDownLatch latch = new MPLatch(3); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - if (user != null && user.getId() == mpid1) { - user1Called.value = true; - latch.countDown(); - } - if (user1Called.value && user.getId() == mpid2) { - user2Called.value = true; - latch.countDown(); - } - } - }); - - IdentityApiRequest request = IdentityApiRequest.withEmptyUser().build(); - MParticleTask result = MParticle.getInstance().Identity().identify(request); - - //test that change actually took place - result.addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult identityApiResult) { - assertEquals(identityApiResult.getUser().getId(), mpid1); - assertEquals(identityApiResult.getPreviousUser().getId(), mStartingMpid.longValue()); - } - }); - - com.mparticle.internal.AccessUtils.awaitUploadHandler(); - - request = IdentityApiRequest.withEmptyUser().build(); - result = MParticle.getInstance().Identity().identify(request); - - result.addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult identityApiResult) { - assertEquals(identityApiResult.getUser().getId(), mpid2); - assertEquals(identityApiResult.getUser().getId(), MParticle.getInstance().Identity().getCurrentUser().getId()); - assertEquals(identityApiResult.getPreviousUser().getId(), mpid1); - latch.countDown(); - user3Called.value = true; - } - }); - - latch.await(); - assertTrue(user1Called.value); - assertTrue(user2Called.value); - } - - @Test - public void testAddMultipleIdentityStateListeners() throws Exception { - mServer.addConditionalIdentityResponse(mStartingMpid, mpid1); - - final CountDownLatch latch = new MPLatch(6); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - latch.countDown(); - } - }); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - latch.countDown(); - } - }); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(MParticleUser user, MParticleUser previousUser) { - latch.countDown(); - } - }); - - IdentityApiRequest request = IdentityApiRequest.withUser(MParticle.getInstance().Identity().getUser(mpid1)).build(); - MParticleTask result = MParticle.getInstance().Identity().identify(request); - - result.addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult identityApiResult) { - latch.countDown(); - } - }).addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult result) { - latch.countDown(); - } - }).addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult result) { - latch.countDown(); - } - }); - - latch.await(); - } - - @Test - public void testRemoveIdentityStateListeners() throws Exception { - mServer.addConditionalIdentityResponse(mStartingMpid, mpid1) - .addConditionalIdentityResponse(mpid1, mpid2); - - final CountDownLatch mpid1Latch = new MPLatch(1); - final CountDownLatch mpid2Latch = new MPLatch(1); - - IdentityStateListener keptIdStateListener = new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - if (user.getId() == mpid1 && previousUser.getId() == mStartingMpid) { - mpid1Latch.countDown(); - } - if (user.getId() == mpid2 && previousUser.getId() == mpid1) { - mpid2Latch.countDown(); - } - } - }; - - IdentityStateListener removeIdStateListener1 = new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - if (user.getId() != mpid1 || previousUser.getId() != mStartingMpid) { - fail("IdentityStateListener failed to be removed"); - } - } - }; - IdentityStateListener removeIdStateListener2 = new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - if (user.getId() != mpid1 || previousUser.getId() != mStartingMpid) { - fail("IdentityStateListener failed to be removed"); - } } - }; - IdentityStateListener removeIdStateListener3 = new IdentityStateListener() { - @Override - public void onUserIdentified(final MParticleUser user, MParticleUser previousUser) { - if (user.getId() != mpid1 || previousUser.getId() != mStartingMpid) { - fail("IdentityStateListener failed to be removed"); - } - } - }; - MParticle.getInstance().Identity().addIdentityStateListener(keptIdStateListener); - MParticle.getInstance().Identity().addIdentityStateListener(removeIdStateListener1); - MParticle.getInstance().Identity().addIdentityStateListener(removeIdStateListener2); - MParticle.getInstance().Identity().addIdentityStateListener(removeIdStateListener3); - - MParticle.getInstance().Identity().identify(IdentityApiRequest.withEmptyUser().build()); - - mpid1Latch.await(); - - MParticle.getInstance().Identity().removeIdentityStateListener(removeIdStateListener1); - MParticle.getInstance().Identity().removeIdentityStateListener(removeIdStateListener2); - MParticle.getInstance().Identity().removeIdentityStateListener(removeIdStateListener3); - - MParticle.getInstance().Identity().identify(IdentityApiRequest.withEmptyUser().build()); - - mpid2Latch.await(); - } - - /** - * Make sure that the {@link IdentityStateListener} callbacks are occuring on the Main Thread. - * This is important so that the KitManagerImpl, which will only instantiate kits on the MainThread, - * will instantiate kits synchronously - * @throws InterruptedException - */ - @Test - public void testIdentityStateListenerThread() throws InterruptedException { - final Mutable called = new Mutable(false); - final CountDownLatch latch = new MPLatch(1); - - HandlerThread backgroundThread = new HandlerThread(mRandomUtils.getAlphaNumericString(8)); - backgroundThread.start(); - new Handler(backgroundThread.getLooper()).post(new Runnable() { - @Override - public void run() { - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(MParticleUser user, MParticleUser previousUser) { - assertEquals(Looper.getMainLooper(), Looper.myLooper()); - assertEquals(user.getId(), MParticle.getInstance().Identity().getCurrentUser().getId()); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid1, ran.nextBoolean()); - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testIdentityTransitionListener() throws InterruptedException { - mServer.addConditionalLoginResponse(mStartingMpid, mpid1); - final CountDownLatch latch = new MPLatch(1); - final Mutable called = new Mutable(false); - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(@NonNull MParticleUser newUser, @Nullable MParticleUser previousUser) { - assertEquals(mStartingMpid.longValue(), previousUser.getId()); - assertEquals(mpid1, newUser.getId()); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().login(); - latch.await(); - assertTrue(called.value); - } - - - @Test - public void testCallbacksVsCurrentUser() throws InterruptedException { - mServer.addConditionalLoginResponse(mStartingMpid, mpid1); - - final CountDownLatch latch = new MPLatch(2); - final Mutable called1 = new Mutable(false); - final Mutable called2 = new Mutable(false); - - MParticle.getInstance().Identity().addIdentityStateListener(new IdentityStateListener() { - @Override - public void onUserIdentified(MParticleUser user, MParticleUser previousUser) { - assertEquals(mpid1, MParticle.getInstance().Identity().getCurrentUser().getId()); - assertEquals(mpid1, user.getId()); - assertEquals(mStartingMpid.longValue(), previousUser.getId()); - called1.value = true; - latch.countDown(); - } - }); - - MParticle.getInstance().Identity().login() - .addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult result) { - assertEquals(mpid1, MParticle.getInstance().Identity().getCurrentUser().getId()); - assertEquals(mpid1, result.getUser().getId()); - assertEquals(mStartingMpid.longValue(), result.getPreviousUser().getId()); - called2.value = true; - latch.countDown(); - } - }); - latch.await(); - assertTrue(called1.value); - assertTrue(called2.value); - } - - - private void assertMParticleUserEquals(MParticleUser dto1, Long mpid, Map identityTypes, Map userAttributes, boolean isLoggedIn) { - assertTrue(dto1.getId() == mpid); - if (userAttributes != null) { - if (dto1.getUserAttributes() != null) { - assertEquals(dto1.getUserAttributes().size(), userAttributes.size()); - for (Map.Entry entry : dto1.getUserAttributes().entrySet()) { - if (entry.getValue() == null) { - assertNull(userAttributes.get(entry.getKey())); - } else { - assertEquals(entry.getValue().toString(), userAttributes.get(entry.getKey()).toString()); - } - } - } - } else { - assertEquals(dto1.getUserAttributes().size(), 0); - } - assertEquals(dto1.getUserIdentities().size(), identityTypes.size()); - for (Map.Entry entry : dto1.getUserIdentities().entrySet()) { - assertEquals(entry.getValue(), identityTypes.get(entry.getKey())); - } - assertEquals(isLoggedIn, dto1.isLoggedIn()); - } - - @Test - public void testGetUser() throws Exception { - IdentityApi identity = MParticle.getInstance().Identity(); - assertNotNull(identity.getCurrentUser()); - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid1, true); - assertEquals(identity.getCurrentUser().getId(), mpid1); - Map mpid1UserAttributes = new HashMap(mRandomUtils.getRandomAttributes(3)); - Map mpid1UserIdentites = mRandomUtils.getRandomUserIdentities(2); - identity.getCurrentUser().setUserAttributes(mpid1UserAttributes); - AccessUtils.setUserIdentities(mpid1UserIdentites, identity.getCurrentUser().getId()); - - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid2, false); - Map mpid2UserAttributes = new HashMap(mRandomUtils.getRandomAttributes(3)); - Map mpid2UserIdentites = mRandomUtils.getRandomUserIdentities(3); - identity.getCurrentUser().setUserAttributes(mpid2UserAttributes); - AccessUtils.setUserIdentities(mpid2UserIdentites, identity.getCurrentUser().getId()); - - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid3, true); - Map mpid3UserAttributes = new HashMap(mRandomUtils.getRandomAttributes(3)); - Map mpid3UserIdentities = mRandomUtils.getRandomUserIdentities(2); - identity.getCurrentUser().setUserAttributes(mpid3UserAttributes); - AccessUtils.setUserIdentities(mpid3UserIdentities, identity.getCurrentUser().getId()); - - mpid1UserAttributes.remove(null); - mpid2UserAttributes.remove(null); - mpid3UserAttributes.remove(null); - - com.mparticle.internal.AccessUtils.awaitMessageHandler(); - - //should return null for mpid = 0 - assertNull(identity.getUser(0L)); - - //should return an MParticleUser with the correct mpid, userIdentities, and userAttributes for - //previously seen users - assertMParticleUserEquals(identity.getUser(mpid1), mpid1, mpid1UserIdentites, mpid1UserAttributes, true); - assertMParticleUserEquals(identity.getUser(mpid2), mpid2, mpid2UserIdentites, mpid2UserAttributes, false); - assertMParticleUserEquals(identity.getUser(mpid3), mpid3, mpid3UserIdentities, mpid3UserAttributes, true); - - //should return null for unseen mpid's - assertNull(identity.getUser(mRandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE))); - assertNull(identity.getUser(mRandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE))); - assertNull(identity.getUser(mRandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE))); - } - - /** - * this simulates the scenerio in which you make a modify() call, but the current MParticleUser - * changes between the time you build the request and the time you make the call - */ - @Test - public void testModifyConcurrentCalls() throws Exception { - assertEquals(mStartingMpid, MParticle.getInstance().Identity().getCurrentUser().getId(), 0); - Map userIdentities = mRandomUtils.getRandomUserIdentities(); - for (MParticle.IdentityType identity : userIdentities.keySet()) { - AccessUtils.setUserIdentity(userIdentities.get(identity), identity, mStartingMpid); - } - - IdentityApiRequest request = IdentityApiRequest.withUser(MParticle.getInstance().Identity().getCurrentUser()).customerId(mRandomUtils.getAlphaNumericString(24)).build(); - - final CountDownLatch latch = new MPLatch(1); - - mServer.waitForVerify(new Matcher(mServer.Endpoints().getModifyUrl(mStartingMpid)), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - assertEquals(1, request.asIdentityRequest().getBody().identity_changes.size()); - latch.countDown(); - } - }); - MParticle.getInstance().Identity().modify(request); - //change the mpid; - //behind the scenes, this call will take place before the (above) modify request goes out, since - //the modify request will be passed to a background thread before it is executed - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid2, ran.nextBoolean()); - latch.await(); - } - - @Test - public void testGetUsersApi() { - //test that by default there is only the starting user - assertEquals(MParticle.getInstance().Identity().getUsers().size(), 1); - assertEquals((Long)MParticle.getInstance().Identity().getUsers().get(0).getId(), mStartingMpid); - - //add 5 Users - List mpids = new ArrayList(); - mpids.add(mStartingMpid); - for (int i = 0; i < 5; i++) { - mpids.add(ran.nextLong()); - } - - for (Long mpid: mpids) { - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid, this.ran.nextBoolean()); - } - - //test that there are now 6 users present in the getUsers() endpoint - assertEquals(MParticle.getInstance().Identity().getUsers().size(), mpids.size()); - - //test that they are the same users we added before - for (MParticleUser mParticleUser: MParticle.getInstance().Identity().getUsers()) { - assertTrue(mpids.contains(mParticleUser.getId())); - } - - //remove 2 users - for (int i = 0; i < 2; i++) { - MParticle.getInstance().Internal().getConfigManager().deleteUserStorage(mpids.remove(i)); - } - - //test that there are now 4 remaining users - assertEquals(MParticle.getInstance().Identity().getUsers().size(), 4); - - //test that they are the correct users - for (MParticleUser mParticleUser: MParticle.getInstance().Identity().getUsers()) { - assertTrue(mpids.contains(mParticleUser.getId())); - } - } - - /** - * make sure that there is no way for an MParticleUser with MPID == 0 to be returned from the - * IdentityAPI - */ - @Test - public void testNoZeroMpidUser() { - assertNull(MParticle.getInstance().Identity().getUser(0L)); - for (MParticleUser user: MParticle.getInstance().Identity().getUsers()) { - assertNotSame(0, user.getId()); - } - MParticle.getInstance().Internal().getConfigManager().setMpid(0L, ran.nextBoolean()); - assertNull(MParticle.getInstance().Identity().getUser(0L)); - for (MParticleUser user: MParticle.getInstance().Identity().getUsers()) { - assertNotSame(0, user.getId()); - } - } - - @Test - public void testGetDeviceApplicationStamp() throws InterruptedException { - int dasLength = UUID.randomUUID().toString().length(); - String currentDas = MParticle.getInstance().Identity().getDeviceApplicationStamp(); - assertEquals(dasLength, currentDas.length()); - assertEquals(currentDas, MParticle.getInstance().Identity().getDeviceApplicationStamp()); - MParticle.reset(mContext); - startMParticle(); - String newDas = MParticle.getInstance().Identity().getDeviceApplicationStamp(); - assertNotNull(newDas); - assertNotSame(currentDas, newDas); - } - - @Test - public void testModifyWhenIdentityAddedConcurrently() throws InterruptedException { - final CountDownLatch latch = new MPLatch(1); - final MParticleUser currentUser = MParticle.getInstance().Identity().getCurrentUser(); - final IdentityApi identityApi = MParticle.getInstance().Identity(); - - final IdentityApiRequest modifyRequest = IdentityApiRequest.withUser(currentUser) - .pushToken("new push", "old_push") - .build(); - - TaskSuccessListener taskSuccessListener = new TaskSuccessListener() { - @Override - public void onSuccess(@NonNull IdentityApiResult result) { - identityApi.modify(modifyRequest); - mServer.waitForVerify( - new Matcher(mServer.Endpoints().getModifyUrl(currentUser.getId())), - new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - List identityChanges = request.asIdentityRequest().getBody().identity_changes; - assertEquals(1, identityChanges.size()); - //make sure the customerId didn't change. it should not be included in the IdentityApiRequest - //since the request was built before customerId was set - assertTrue(!"customerid".equals(identityChanges.get(0).optString("identity_type"))); - assertTrue("push_token".equals(identityChanges.get(0).optString("identity_type"))); - latch.countDown(); - } - } - ); - } - }; - - IdentityApiRequest loginRequest = IdentityApiRequest.withUser(currentUser) - .customerId("my Id") - .build(); - identityApi - .login(loginRequest) - .addSuccessListener(taskSuccessListener); - - latch.await(); - } - - @Test - public void testModifyWhenIdentityChangesConcurrently() throws InterruptedException { - final CountDownLatch latch = new MPLatch(1); - final MParticleUser currentUser = MParticle.getInstance().Identity().getCurrentUser(); - final IdentityApi identityApi = MParticle.getInstance().Identity(); - - final IdentityApiRequest modifyRequest = IdentityApiRequest.withUser(currentUser) - .customerId("new customer ID") - .build(); - - TaskSuccessListener taskSuccessListener = new TaskSuccessListener() { - @Override - public void onSuccess(@NonNull IdentityApiResult result) { - identityApi.modify(modifyRequest); - mServer.waitForVerify( - new Matcher(mServer.Endpoints().getModifyUrl(currentUser.getId())), - new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - List identityChanges = request.asIdentityRequest().getBody().identity_changes; - assertEquals(1, identityChanges.size()); - //make sure the customerId used the correct "old" value - assertTrue("customerid".equals(identityChanges.get(0).optString("identity_type"))); - assertEquals("new customer ID", identityChanges.get(0).optString("new_value")); - assertEquals("old customer ID", identityChanges.get(0).optString("old_value")); - latch.countDown(); - } - } - ); - } - }; - - IdentityApiRequest loginRequest = IdentityApiRequest.withUser(currentUser) - .customerId("old customer ID") - .build(); - identityApi - .login(loginRequest) - .addSuccessListener(taskSuccessListener); - - latch.await(); - } - - @Test - public void testModifyDoesntMissIdentitiesSetNull() throws InterruptedException { - AccessUtils.setUserIdentity("customer Id", MParticle.IdentityType.CustomerId, mStartingMpid); - AccessUtils.setUserIdentity("facebook Id", MParticle.IdentityType.Facebook, mStartingMpid); - AccessUtils.setUserIdentity("other Id", MParticle.IdentityType.Other2, mStartingMpid); - final CountDownLatch latch = new MPLatch(1); - - IdentityApiRequest request = IdentityApiRequest.withUser(MParticle.getInstance().Identity().getCurrentUser()) - .customerId(null) - .userIdentity(MParticle.IdentityType.Facebook, null) - .userIdentity(MParticle.IdentityType.Other2, null) - .build(); - MParticle.getInstance().Identity().modify(request); - mServer.waitForVerify(new Matcher(mServer.Endpoints().getModifyUrl(mStartingMpid)), new MockServer.RequestReceivedCallback() { - @Override - public void onRequestReceived(Request request) { - List identityChanges = request.asIdentityRequest().getBody().identity_changes; - assertEquals(3, identityChanges.size()); - Collections.sort(identityChanges, new Comparator() { - @Override - public int compare(JSONObject jsonObject, JSONObject t1) { - return jsonObject.optString("identity_type").compareTo(t1.optString("identity_type")); - } - }); - - //make sure the existing values were set to null - assertTrue("customerid".equals(identityChanges.get(0).optString("identity_type"))); - assertEquals("customer Id", identityChanges.get(0).optString("old_value")); - assertEquals("null", identityChanges.get(0).optString("new_value")); - - assertTrue("facebook".equals(identityChanges.get(1).optString("identity_type"))); - assertEquals("facebook Id", identityChanges.get(1).optString("old_value")); - assertEquals("null", identityChanges.get(1).optString("new_value")); - - assertTrue("other2".equals(identityChanges.get(2).optString("identity_type"))); - assertEquals("other Id", identityChanges.get(2).optString("old_value")); - assertEquals("null", identityChanges.get(2).optString("new_value")); - latch.countDown(); - } - }); - - latch.await(); - } -} - diff --git a/android-core/src/androidTest/java/com/mparticle/identity/MParticleIdentityClientImplITest.kt b/android-core/src/androidTest/java/com/mparticle/identity/MParticleIdentityClientImplITest.kt new file mode 100644 index 000000000..a3fc05d76 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/identity/MParticleIdentityClientImplITest.kt @@ -0,0 +1,343 @@ +package com.mparticle.identity + +import android.os.Handler +import com.mparticle.MParticle +import com.mparticle.internal.ConfigManager +import com.mparticle.internal.MPUtility +import com.mparticle.networking.MPConnection +import com.mparticle.networking.MPConnectionMockImpl +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.utils.randomIdentities +import junit.framework.Assert +import org.json.JSONException +import org.json.JSONObject +import org.junit.Before +import org.junit.Test +import java.io.IOException +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class MParticleIdentityClientImplITest : BaseStartedTest() { + private var mConfigManager: ConfigManager? = null + private var mApiClient: MParticleIdentityClientImpl? = null + @Before + @Throws(Exception::class) + fun before() { + mConfigManager = MParticle.getInstance()!!.Internal().configManager + } + + @Test + @Throws(Exception::class) + fun testModifySameData() { + val latch: CountDownLatch = FailureLatch(count = 2) + val handler = Handler() + handler.postDelayed({ Assert.fail("modify did not complete") }, (10 * 1000).toLong()) + val called: Mutable = Mutable(false) + MParticle.getInstance()!! + .Identity().modify(IdentityApiRequest.withEmptyUser().build()) + .addSuccessListener { + latch.countDown() + MParticle.getInstance()!! + .Identity().modify(IdentityApiRequest.withEmptyUser().build()) + .addSuccessListener { + val currentModifyRequestCount: Int = Server.endpoint(EndpointType.Identity_Modify).requests.size + // make sure we made 1 or 0 modify requests. It could go either way for the first modify request, + // it may have changes, it may not depending on state. The second request though, should not have + // changes, and therefore it should not take place, so less than 2 requests is a good condition + org.junit.Assert.assertTrue(2 > currentModifyRequestCount) + handler.removeCallbacksAndMessages(null) + called.value = true + latch.countDown() + } + .addFailureListener { Assert.fail("task failed") } + } + .addFailureListener { Assert.fail("task failed") } + latch.await() + org.junit.Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testIdentifyMessage() { + val iterations = 5 + for (i in 0 until iterations) { + val userIdentities: Map = randomIdentities().toMap() + val latch = CountDownLatch(1) + setApiClient(object : MockIdentityApiClient { + @Throws(IOException::class, JSONException::class) + override fun makeUrlRequest( + connection: MPConnection, + payload: String?, + mparticle: Boolean + ) { + if (connection.url.toString().contains("/identify")) { + val jsonObject = JSONObject(payload) + val knownIdentities = + jsonObject.getJSONObject(MParticleIdentityClientImpl.KNOWN_IDENTITIES) + org.junit.Assert.assertNotNull(knownIdentities) + checkStaticsAndRemove(knownIdentities) + if (knownIdentities.length() != userIdentities.size) { + org.junit.Assert.assertEquals( + knownIdentities.length().toLong(), + userIdentities.size.toLong() + ) + } + for ((key, value1) in userIdentities) { + val value = knownIdentities.getString( + MParticleIdentityClientImpl.getStringValue(key) + ) + org.junit.Assert.assertEquals(value, value1) + } + setApiClient(null) + latch.countDown() + } + } + }) + mApiClient!!.identify( + IdentityApiRequest.withEmptyUser() + .userIdentities(userIdentities) + .build() + ) + latch.await() + } + } + + @Test + @Throws(Exception::class) + fun testLoginMessage() { + val iterations = 5 + for (i in 0 until iterations) { + val latch: CountDownLatch = FailureLatch() + val userIdentities: Map = randomIdentities() + setApiClient(object : MockIdentityApiClient { + @Throws(IOException::class, JSONException::class) + override fun makeUrlRequest( + connection: MPConnection, + payload: String?, + mparticle: Boolean + ) { + if (connection.url.toString().contains("/login")) { + val jsonObject = JSONObject(payload) + val knownIdentities = + jsonObject.getJSONObject(MParticleIdentityClientImpl.KNOWN_IDENTITIES) + org.junit.Assert.assertNotNull(knownIdentities) + checkStaticsAndRemove(knownIdentities) + org.junit.Assert.assertEquals( + knownIdentities.length().toLong(), + userIdentities.size.toLong() + ) + for ((key, value1) in userIdentities) { + val value = knownIdentities.getString( + MParticleIdentityClientImpl.getStringValue(key) + ) + org.junit.Assert.assertEquals(value, value1) + } + latch.countDown() + } + } + }) + mApiClient!!.login( + IdentityApiRequest.withEmptyUser() + .userIdentities(userIdentities) + .build() + ) +// latch.await() + } + } + + @Test + @Throws(Exception::class) + fun testLogoutMessage() { + val iterations = 5 + for (i in 0 until iterations) { + val userIdentities: Map = randomIdentities() + val latch: CountDownLatch = FailureLatch() + val checked = Mutable(false) + setApiClient(object : MockIdentityApiClient { + @Throws(IOException::class, JSONException::class) + override fun makeUrlRequest( + connection: MPConnection, + payload: String?, + mparticle: Boolean + ) { + if (connection.url.toString().contains("/logout")) { + val jsonObject = JSONObject(payload) + val knownIdentities = + jsonObject.getJSONObject(MParticleIdentityClientImpl.KNOWN_IDENTITIES) + org.junit.Assert.assertNotNull(knownIdentities) + checkStaticsAndRemove(knownIdentities) + org.junit.Assert.assertEquals( + knownIdentities.length().toLong(), + userIdentities.size.toLong() + ) + for ((key, value1) in userIdentities) { + val value = knownIdentities.getString( + MParticleIdentityClientImpl.getStringValue(key) + ) + org.junit.Assert.assertEquals(value, value1) + } + checked.value = true + latch.countDown() + } + } + }) + mApiClient!!.logout( + IdentityApiRequest.withEmptyUser() + .userIdentities(userIdentities) + .build() + ) + latch.await() + org.junit.Assert.assertTrue(checked.value) + } + } + + @Test + @Throws(Exception::class) + fun testModifyMessage() { + val iterations = 5 + for (i in 1..iterations) { + mConfigManager?.setMpid(i.toLong(), Random.Default.nextBoolean()) + val oldUserIdentities: Map = randomIdentities() + val newUserIdentities: Map = randomIdentities() + MParticle.getInstance()?.Identity()?.currentUser + .let { it as MParticleUserImpl } + .userIdentities = oldUserIdentities + val latch: CountDownLatch = FailureLatch() + val checked = Mutable(false) + setApiClient(object : MockIdentityApiClient { + @Throws(IOException::class, JSONException::class) + override fun makeUrlRequest( + connection: MPConnection, + payload: String?, + identityRequest: Boolean + ) { + if (connection.url.toString() + .contains(MParticleIdentityClientImpl.MODIFY_PATH) + ) { + val jsonObject = JSONObject(payload) + val changedIdentities = + jsonObject.getJSONArray(MParticleIdentityClientImpl.IDENTITY_CHANGES) + for (i in 0 until changedIdentities.length()) { + val changeJson = changedIdentities.getJSONObject(i) + val newValue: Any = + changeJson.getString(MParticleIdentityClientImpl.NEW_VALUE) + val oldValue: Any = + changeJson.getString(MParticleIdentityClientImpl.OLD_VALUE) + val identityType = MParticleIdentityClientImpl.getIdentityType( + changeJson.getString(MParticleIdentityClientImpl.IDENTITY_TYPE) + ) + val nullString = JSONObject.NULL.toString() + if (oldUserIdentities[identityType] == null) { + if (oldValue != JSONObject.NULL.toString()) { + Assert.fail() + } + } else { + org.junit.Assert.assertEquals( + oldValue, + oldUserIdentities[identityType] + ) + } + if (newUserIdentities[identityType] == null) { + if (newValue != nullString) { + Assert.fail() + } + } else { + org.junit.Assert.assertEquals( + newValue, + newUserIdentities[identityType] + ) + } + } + setApiClient(null) + checked.value = true + latch.countDown() + } + } + }) + mApiClient!!.modify( + IdentityApiRequest.withEmptyUser() + .userIdentities(newUserIdentities) + .build() + ) + latch.await() + org.junit.Assert.assertTrue(checked.value) + } + } + + private fun setApiClient(identityClient: MockIdentityApiClient?) { + mApiClient = object : MParticleIdentityClientImpl( + context, + mConfigManager, + MParticle.OperatingSystem.ANDROID + ) { + @Throws(IOException::class) + override fun makeUrlRequest( + endpoint: Endpoint, + connection: MPConnection, + payload: String, + identity: Boolean + ): MPConnection { + try { + identityClient!!.makeUrlRequest(connection, payload, identity) + } catch (e: JSONException) { + e.printStackTrace() + Assert.fail(e.message) + } + (connection as MPConnectionMockImpl).connection.setResponseCode(202) + return super.makeUrlRequest(endpoint, connection, payload, identity) + } + } + MParticle.getInstance()!!.Identity().apiClient = mApiClient + } + + @Throws(JSONException::class) + private fun checkStaticsAndRemove(knowIdentites: JSONObject) { + if (knowIdentites.has(MParticleIdentityClientImpl.ANDROID_AAID)) { + org.junit.Assert.assertEquals( + MPUtility.getAdIdInfo(context).id, + knowIdentites.getString(MParticleIdentityClientImpl.ANDROID_AAID) + ) + knowIdentites.remove(MParticleIdentityClientImpl.ANDROID_AAID) + } else { + org.junit.Assert.assertTrue( + MPUtility.getAdIdInfo(context) == null || MPUtility.isEmpty( + MPUtility.getAdIdInfo(context).id + ) + ) + } + if (knowIdentites.has(MParticleIdentityClientImpl.ANDROID_UUID)) { + org.junit.Assert.assertEquals( + MPUtility.getAndroidID(context), + knowIdentites.getString(MParticleIdentityClientImpl.ANDROID_UUID) + ) + knowIdentites.remove(MParticleIdentityClientImpl.ANDROID_UUID) + } else { + org.junit.Assert.assertTrue(MPUtility.isEmpty(MPUtility.getAndroidID(context))) + } + if (knowIdentites.has(MParticleIdentityClientImpl.PUSH_TOKEN)) { + org.junit.Assert.assertEquals( + mConfigManager?.pushInstanceId, + knowIdentites.getString(MParticleIdentityClientImpl.PUSH_TOKEN) + ) + knowIdentites.remove(MParticleIdentityClientImpl.PUSH_TOKEN) + } else { + org.junit.Assert.assertNull(mConfigManager?.pushInstanceId) + } + org.junit.Assert.assertTrue(knowIdentites.has(MParticleIdentityClientImpl.DEVICE_APPLICATION_STAMP)) + org.junit.Assert.assertEquals( + mConfigManager?.deviceApplicationStamp, + knowIdentites[MParticleIdentityClientImpl.DEVICE_APPLICATION_STAMP] + ) + knowIdentites.remove(MParticleIdentityClientImpl.DEVICE_APPLICATION_STAMP) + } + + internal interface MockIdentityApiClient { + @Throws(IOException::class, JSONException::class) + fun makeUrlRequest(connection: MPConnection, payload: String?, mparticle: Boolean) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/MParticleIdentityClientImplTest.java b/android-core/src/androidTest/java/com/mparticle/identity/MParticleIdentityClientImplTest.java deleted file mode 100644 index 45ad2a584..000000000 --- a/android-core/src/androidTest/java/com/mparticle/identity/MParticleIdentityClientImplTest.java +++ /dev/null @@ -1,304 +0,0 @@ -package com.mparticle.identity; - -import android.os.Handler; -import android.util.MutableBoolean; - -import com.mparticle.MParticle; -import com.mparticle.internal.ConfigManager; -import com.mparticle.internal.MPUtility; -import com.mparticle.networking.MPConnection; -import com.mparticle.networking.MPConnectionTestImpl; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.CountDownLatch; - -import static com.mparticle.identity.MParticleIdentityClientImpl.ANDROID_AAID; -import static com.mparticle.identity.MParticleIdentityClientImpl.ANDROID_UUID; -import static com.mparticle.identity.MParticleIdentityClientImpl.DEVICE_APPLICATION_STAMP; -import static com.mparticle.identity.MParticleIdentityClientImpl.IDENTITY_CHANGES; -import static com.mparticle.identity.MParticleIdentityClientImpl.IDENTITY_TYPE; -import static com.mparticle.identity.MParticleIdentityClientImpl.NEW_VALUE; -import static com.mparticle.identity.MParticleIdentityClientImpl.OLD_VALUE; -import static com.mparticle.identity.MParticleIdentityClientImpl.PUSH_TOKEN; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static junit.framework.Assert.fail; - -public class MParticleIdentityClientImplTest extends BaseCleanStartedEachTest { - private ConfigManager mConfigManager; - private MParticleIdentityClientImpl mApiClient; - - @Before - public void before() throws Exception { - mConfigManager = MParticle.getInstance().Internal().getConfigManager(); - } - - - @Test - public void testModifySameData() throws Exception { - final CountDownLatch latch = new MPLatch(2); - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - fail("modify did not complete"); - } - }, 10 * 1000); - - final AndroidUtils.Mutable called = new AndroidUtils.Mutable(false); - MParticle.getInstance().Identity().modify(IdentityApiRequest.withEmptyUser().build()) - .addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult result) { - latch.countDown(); - MParticle.getInstance().Identity().modify(IdentityApiRequest.withEmptyUser().build()) - .addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult result) { - int currentModifyRequestCount = mServer.Requests().getModify().size(); - //make sure we made 1 or 0 modify requests. It could go either way for the first modify request, - //it may have changes, it may not depending on state. The second request though, should not have - //changes, and therefore it should not take place, so less than 2 requests is a good condition - assertTrue(2 > currentModifyRequestCount); - handler.removeCallbacks(null); - called.value = true; - latch.countDown(); - } - }) - .addFailureListener(new TaskFailureListener() { - @Override - public void onFailure(IdentityHttpResponse result) { - fail("task failed"); - } - }); - } - }) - .addFailureListener(new TaskFailureListener() { - @Override - public void onFailure(IdentityHttpResponse result) { - fail("task failed"); - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testIdentifyMessage() throws Exception { - int iterations = 5; - for (int i = 0; i < iterations; i++) { - final Map userIdentities = mRandomUtils.getRandomUserIdentities(); - final MutableBoolean checked = new MutableBoolean(false); - final CountDownLatch latch = new CountDownLatch(1); - setApiClient(new MockIdentityApiClient() { - @Override - public void makeUrlRequest(MPConnection connection, String payload, boolean mparticle) throws IOException, JSONException { - if (connection.getURL().toString().contains("/identify")) { - JSONObject jsonObject = new JSONObject(payload); - JSONObject knownIdentities = jsonObject.getJSONObject(MParticleIdentityClientImpl.KNOWN_IDENTITIES); - assertNotNull(knownIdentities); - checkStaticsAndRemove(knownIdentities); - if (knownIdentities.length() != userIdentities.size()) { - assertEquals(knownIdentities.length(), userIdentities.size()); - } - for (Map.Entry identity : userIdentities.entrySet()) { - String value = knownIdentities.getString(mApiClient.getStringValue(identity.getKey())); - assertEquals(value, identity.getValue()); - } - checked.value = true; - setApiClient(null); - latch.countDown(); - } - } - }); - - mApiClient.identify(IdentityApiRequest.withEmptyUser() - .userIdentities(userIdentities) - .build()); - latch.await(); - assertTrue(checked.value); - } - - } - - @Test - public void testLoginMessage() throws Exception { - int iterations = 5; - for (int i = 0; i < iterations; i++) { - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean checked = new MutableBoolean(false); - final Map userIdentities = mRandomUtils.getRandomUserIdentities(); - - setApiClient(new MockIdentityApiClient() { - @Override - public void makeUrlRequest(MPConnection connection, String payload, boolean mparticle) throws IOException, JSONException { - if (connection.getURL().toString().contains("/login")) { - JSONObject jsonObject = new JSONObject(payload); - JSONObject knownIdentities = jsonObject.getJSONObject(MParticleIdentityClientImpl.KNOWN_IDENTITIES); - assertNotNull(knownIdentities); - checkStaticsAndRemove(knownIdentities); - assertEquals(knownIdentities.length(), userIdentities.size()); - for (Map.Entry identity : userIdentities.entrySet()) { - String value = knownIdentities.getString(mApiClient.getStringValue(identity.getKey())); - assertEquals(value, identity.getValue()); - } - checked.value = true; - latch.countDown(); - } - } - }); - mApiClient.login(IdentityApiRequest.withEmptyUser() - .userIdentities(userIdentities) - .build()); - latch.await(); - assertTrue(checked.value); - } - } - - @Test - public void testLogoutMessage() throws Exception { - int iterations = 5; - for (int i = 0; i < iterations; i++) { - final Map userIdentities = mRandomUtils.getRandomUserIdentities(); - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean checked = new MutableBoolean(false); - setApiClient(new MockIdentityApiClient() { - @Override - public void makeUrlRequest(MPConnection connection, String payload, boolean mparticle) throws IOException, JSONException { - if (connection.getURL().toString().contains("/logout")) { - JSONObject jsonObject = new JSONObject(payload); - JSONObject knownIdentities = jsonObject.getJSONObject(MParticleIdentityClientImpl.KNOWN_IDENTITIES); - assertNotNull(knownIdentities); - checkStaticsAndRemove(knownIdentities); - assertEquals(knownIdentities.length(), userIdentities.size()); - for (Map.Entry identity : userIdentities.entrySet()) { - String value = knownIdentities.getString(mApiClient.getStringValue(identity.getKey())); - assertEquals(value, identity.getValue()); - } - checked.value = true; - latch.countDown(); - } - } - }); - - mApiClient.logout(IdentityApiRequest.withEmptyUser() - .userIdentities(userIdentities) - .build()); - latch.await(); - assertTrue(checked.value); - } - } - - @Test - public void testModifyMessage() throws Exception { - int iterations = 5; - for (int i = 1; i <= iterations; i++) { - mConfigManager.setMpid(i, ran.nextBoolean()); - - final Map oldUserIdentities = mRandomUtils.getRandomUserIdentities(); - final Map newUserIdentities = mRandomUtils.getRandomUserIdentities(); - - ((MParticleUserImpl)MParticle.getInstance().Identity().getCurrentUser()).setUserIdentities(oldUserIdentities); - - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean checked = new MutableBoolean(false); - setApiClient(new MockIdentityApiClient() { - @Override - public void makeUrlRequest(MPConnection connection, String payload, boolean mparticle) throws IOException, JSONException { - if (connection.getURL().toString().contains(MParticleIdentityClientImpl.MODIFY_PATH)) { - JSONObject jsonObject = new JSONObject(payload); - JSONArray changedIdentities = jsonObject.getJSONArray(IDENTITY_CHANGES); - for (int i = 0; i < changedIdentities.length(); i++) { - JSONObject changeJson = changedIdentities.getJSONObject(i); - Object newValue = changeJson.getString(NEW_VALUE); - Object oldValue = changeJson.getString(OLD_VALUE); - MParticle.IdentityType identityType = mApiClient.getIdentityType(changeJson.getString(IDENTITY_TYPE)); - String nullString = JSONObject.NULL.toString(); - if (oldUserIdentities.get(identityType) == null) { - if(!oldValue.equals(JSONObject.NULL.toString())) { - fail(); - } - } else { - assertEquals(oldValue, oldUserIdentities.get(identityType)); - } - if (newUserIdentities.get(identityType) == null) { - if(!newValue.equals(nullString)) { - fail(); - } - } else { - assertEquals(newValue, newUserIdentities.get(identityType)); - } - } - setApiClient(null); - checked.value = true; - latch.countDown(); - } - } - }); - - mApiClient.modify(IdentityApiRequest.withEmptyUser() - .userIdentities(newUserIdentities) - .build()); - latch.await(); - assertTrue(checked.value); - } - } - - private void setApiClient(final MockIdentityApiClient identityClient) { - mApiClient = new MParticleIdentityClientImpl(mContext, mConfigManager, MParticle.OperatingSystem.ANDROID) { - @Override - public MPConnection makeUrlRequest(Endpoint endpoint, final MPConnection connection, String payload, boolean identity) throws IOException { - try { - identityClient.makeUrlRequest(connection, payload, identity); - } catch (JSONException e) { - e.printStackTrace(); - fail(e.getMessage()); - } - ((MPConnectionTestImpl)connection).setResponseCode(202); - return connection; - } - }; - MParticle.getInstance().Identity().setApiClient(mApiClient); - } - - private void checkStaticsAndRemove(JSONObject knowIdentites) throws JSONException { - if (knowIdentites.has(ANDROID_AAID)) { - assertEquals(MPUtility.getAdIdInfo(mContext).id, knowIdentites.getString(ANDROID_AAID)); - knowIdentites.remove(ANDROID_AAID); - } else { - assertTrue(MPUtility.getAdIdInfo(mContext) == null || MPUtility.isEmpty(MPUtility.getAdIdInfo(mContext).id)); - } - if (knowIdentites.has(ANDROID_UUID)) { - assertEquals(MPUtility.getAndroidID(mContext), knowIdentites.getString(ANDROID_UUID)); - knowIdentites.remove(ANDROID_UUID); - } else { - assertTrue(MPUtility.isEmpty(MPUtility.getAndroidID(mContext))); - } - if (knowIdentites.has(PUSH_TOKEN)) { - assertEquals(mConfigManager.getPushInstanceId(), knowIdentites.getString(PUSH_TOKEN)); - knowIdentites.remove(PUSH_TOKEN); - } else { - assertNull(mConfigManager.getPushInstanceId()); - } - assertTrue(knowIdentites.has(DEVICE_APPLICATION_STAMP)); - assertEquals(mConfigManager.getDeviceApplicationStamp(), knowIdentites.get(DEVICE_APPLICATION_STAMP)); - knowIdentites.remove(DEVICE_APPLICATION_STAMP); - } - - interface MockIdentityApiClient { - void makeUrlRequest(MPConnection connection, String payload, boolean mparticle) throws IOException, JSONException; - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserDelegateITest.java b/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserDelegateITest.java deleted file mode 100644 index c1eedc525..000000000 --- a/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserDelegateITest.java +++ /dev/null @@ -1,231 +0,0 @@ -package com.mparticle.identity; - -import android.os.Handler; -import android.os.Looper; -import androidx.annotation.Nullable; -import android.util.Log; - -import com.mparticle.MParticle; -import com.mparticle.UserAttributeListener; -import com.mparticle.consent.CCPAConsent; -import com.mparticle.consent.ConsentState; -import com.mparticle.consent.GDPRConsent; -import com.mparticle.internal.AccessUtils; -import com.mparticle.testutils.AndroidUtils.Mutable; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import org.junit.Before; -import org.junit.Test; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class MParticleUserDelegateITest extends BaseCleanStartedEachTest { - MParticleUserDelegate mUserDelegate; - - @Before - public void before() throws Exception { - mUserDelegate = MParticle.getInstance().Identity().mUserDelegate; - } - - @Test - public void testSetGetUserIdentities() throws Exception { - Map> attributes = new HashMap>(); - for (int i = 0; i < 5; i++) { - Long mpid = ran.nextLong(); - Map pairs = new HashMap(); - attributes.put(mpid, pairs); - for (int j = 0; j < 3; j++) { - MParticle.IdentityType identityType = MParticle.IdentityType.parseInt(mRandomUtils.randomInt(0, MParticle.IdentityType.values().length)); - String value = mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(1, 25)); - assertTrue(mUserDelegate.setUserIdentity(value, identityType, mpid)); - pairs.put(identityType, value); - } - } - - com.mparticle.internal.AccessUtils.awaitMessageHandler(); - - Map> storedUsersTemp = new HashMap>(); - - for (Entry> user : attributes.entrySet()) { - Map storedUserAttributes = mUserDelegate.getUserIdentities(user.getKey()); - storedUsersTemp.put(user.getKey(), storedUserAttributes); - for (Entry pairs : user.getValue().entrySet()) { - Object currentAttribute = storedUserAttributes.get(pairs.getKey()); - if (currentAttribute == null) { - Log.e("Stuff", "more stuff"); - } - assertEquals(storedUserAttributes.get(pairs.getKey()), pairs.getValue()); - } - } - } - - @Test - public void testInsertRetrieveDeleteUserAttributes() throws Exception { - // create and store - Map> attributes = new HashMap>(); - for (int i = 0; i < 5; i++) { - Long mpid = ran.nextLong(); - Map pairs = new HashMap(); - attributes.put(mpid, pairs); - for (int j = 0; j < 3; j++) { - String key = mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(1, 55)).toUpperCase(); - String value = mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(1, 55)); - assertTrue(mUserDelegate.setUserAttribute(key, value, mpid, false)); - pairs.put(key, value); - } - } - - AccessUtils.awaitMessageHandler(); - - // retrieve and compare - for (Entry> user : attributes.entrySet()) { - Map storedUserAttributes = mUserDelegate.getUserAttributes(user.getKey()); - for (Entry pairs : user.getValue().entrySet()) { - if (storedUserAttributes.get(pairs.getKey()) == null){ - assertNull(pairs.getValue()); - } else { - assertEquals(storedUserAttributes.get(pairs.getKey()).toString(), pairs.getValue()); - } - } - } - - // delete - for (Entry> userAttributes : attributes.entrySet()) { - for (Entry attribute : userAttributes.getValue().entrySet()) { - assertTrue(mUserDelegate.removeUserAttribute(attribute.getKey(), userAttributes.getKey())); - } - } - - AccessUtils.awaitMessageHandler(); - - for (Entry> userAttributes : attributes.entrySet()) { - Map storedUserAttributes = mUserDelegate.getUserAttributes(userAttributes.getKey()); - for (Entry attribute : userAttributes.getValue().entrySet()) { - assertNull(storedUserAttributes.get(attribute.getKey())); - } - } - } - - @Test - public void testSetConsentState() throws Exception { - Long mpid = ran.nextLong(); - Long mpid2 = ran.nextLong(); - ConsentState state = mUserDelegate.getConsentState(mpid); - assertNotNull(state); - assertNotNull(state.getGDPRConsentState()); - assertEquals(0, state.getGDPRConsentState().size()); - - ConsentState.Builder builder = ConsentState.builder(); - builder.addGDPRConsentState("foo", GDPRConsent.builder(true).build()); - mUserDelegate.setConsentState(builder.build(), mpid); - builder.addGDPRConsentState("foo2", GDPRConsent.builder(true).build()); - mUserDelegate.setConsentState(builder.build(), mpid2); - builder.setCCPAConsentState(CCPAConsent.builder(false).build()); - mUserDelegate.setConsentState(builder.build(), mpid2); - - assertEquals(1, mUserDelegate.getConsentState(mpid).getGDPRConsentState().size()); - assertTrue(mUserDelegate.getConsentState(mpid).getGDPRConsentState().containsKey("foo")); - assertNull(mUserDelegate.getConsentState(mpid).getCCPAConsentState()); - - assertEquals(2, mUserDelegate.getConsentState(mpid2).getGDPRConsentState().size()); - assertTrue(mUserDelegate.getConsentState(mpid2).getGDPRConsentState().containsKey("foo")); - assertTrue(mUserDelegate.getConsentState(mpid2).getGDPRConsentState().containsKey("foo2")); - assertNotNull(mUserDelegate.getConsentState(mpid2).getCCPAConsentState()); - } - - @Test - public void testRemoveConsentState() throws Exception { - Long mpid = ran.nextLong(); - ConsentState state = mUserDelegate.getConsentState(mpid); - assertNotNull(state); - assertNotNull(state.getGDPRConsentState()); - assertEquals(0, state.getGDPRConsentState().size()); - - ConsentState.Builder builder = ConsentState.builder(); - builder.addGDPRConsentState("foo", GDPRConsent.builder(true).build()); - builder.setCCPAConsentState(CCPAConsent.builder(true).build()); - mUserDelegate.setConsentState(builder.build(), mpid); - - assertEquals(1, mUserDelegate.getConsentState(mpid).getGDPRConsentState().size()); - assertNotNull(mUserDelegate.getConsentState(mpid).getCCPAConsentState()); - assertTrue(mUserDelegate.getConsentState(mpid).getGDPRConsentState().containsKey("foo")); - mUserDelegate.setConsentState(null, mpid); - assertEquals(0, mUserDelegate.getConsentState(mpid).getGDPRConsentState().size()); - assertNull(mUserDelegate.getConsentState(mpid).getCCPAConsentState()); - } - - @Test - public void testGetUserAttributesListener() throws InterruptedException { - Map attributeSingles = mRandomUtils.getRandomAttributes(5, false); - - Map> attributeLists = new HashMap>(); - for (Entry entry: attributeSingles.entrySet()) { - attributeLists.put(entry.getKey() + entry.getValue(), Collections.singletonList(entry.getValue() + entry.getKey())); - } - - for (Entry> entry: attributeLists.entrySet()) { - mUserDelegate.setUserAttributeList(entry.getKey(), entry.getValue(), mStartingMpid); - } - for (Entry entry: attributeSingles.entrySet()) { - mUserDelegate.setUserAttribute(entry.getKey(), entry.getValue(), mStartingMpid); - } - AccessUtils.awaitMessageHandler(); - - final Mutable> userAttributesResults = new Mutable>(null); - final Mutable>> userAttributeListResults = new Mutable>>(null); - - //fetch on the current (non-main) thread - mUserDelegate.getUserAttributes(new UserAttributeListener() { - @Override - public void onUserAttributesReceived(@Nullable Map userAttributes, @Nullable Map> userAttributeLists, @Nullable Long mpid) { - userAttributesResults.value = userAttributes; - userAttributeListResults.value = userAttributeLists; - } - }, mStartingMpid); - - assertMapEquals(attributeSingles, userAttributesResults.value); - assertMapEquals(attributeLists, userAttributeListResults.value); - - userAttributesResults.value = null; - userAttributeListResults.value = null; - - //fetch on the main thread (seperate code path) - final CountDownLatch latch = new MPLatch(1); - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - mUserDelegate.getUserAttributes(new UserAttributeListener() { - @Override - public void onUserAttributesReceived(@Nullable Map userAttributes, @Nullable Map> userAttributeLists, @Nullable Long mpid) { - userAttributesResults.value = userAttributes; - userAttributeListResults.value = userAttributeLists; - latch.countDown(); - } - }, mStartingMpid); - } - }); - latch.await(); - - assertMapEquals(attributeSingles, userAttributesResults.value); - assertMapEquals(attributeLists, userAttributeListResults.value); - } - - private void assertMapEquals(Map map1, Map map2) { - assertEquals(map1.toString() + "\n\nvs" + map2.toString(), map1.size(), map2.size()); - for (Object obj: map1.entrySet()) { - Entry entry = (Entry)obj; - assertEquals(entry.getValue(), map2.get(entry.getKey())); - } - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserDelegateTest.kt b/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserDelegateTest.kt new file mode 100644 index 000000000..983d92ebb --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserDelegateTest.kt @@ -0,0 +1,235 @@ +package com.mparticle.identity + +import android.os.Handler +import android.os.Looper +import android.util.Log +import com.mparticle.MParticle +import com.mparticle.TypedUserAttributeListener +import com.mparticle.consent.CCPAConsent +import com.mparticle.consent.ConsentState +import com.mparticle.consent.GDPRConsent +import com.mparticle.internal.AccessUtils +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.RandomUtils +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.util.concurrent.CountDownLatch +import kotlin.random.Random +import kotlin.test.junit.JUnitAsserter.fail + +class MParticleUserDelegateTest : BaseStartedTest() { + private var mUserDelegate: MParticleUserDelegate? = null + @Before + @Throws(Exception::class) + fun before() { + mUserDelegate = MParticle.getInstance()!!.Identity().mUserDelegate + } + + @Test + @Throws(Exception::class) + fun testSetGetUserIdentities() { + val attributes: MutableMap> = HashMap() + for (i in 0..4) { + val mpid: Long = Random.Default.nextLong() + val pairs: MutableMap = HashMap() + attributes[mpid] = pairs + for (j in 0..2) { + val identityType = MParticle.IdentityType.parseInt( + RandomUtils.randomInt( + 0, + MParticle.IdentityType.values().size + ) + ) + val value: String = + RandomUtils.getAlphaNumericString(RandomUtils.randomInt(1, 25)) + Assert.assertTrue(mUserDelegate!!.setUserIdentity(value, identityType, mpid)) + pairs[identityType] = value + } + } + AccessUtils.awaitMessageHandler() + val storedUsersTemp: MutableMap> = HashMap() + for ((key, value) in attributes) { + val storedUserAttributes = mUserDelegate!!.getUserIdentities(key) + storedUsersTemp[key] = storedUserAttributes + for ((key1, value1) in value) { + val currentAttribute: Any? = storedUserAttributes[key1] + if (currentAttribute == null) { + Log.e("Stuff", "more stuff") + } + Assert.assertEquals(storedUserAttributes[key1], value1) + } + } + } + + @Test + @Throws(Exception::class) + fun testInsertRetrieveDeleteUserAttributes() { + // create and store + val attributes: MutableMap> = HashMap() + for (i in 0..4) { + val mpid: Long = Random.Default.nextLong() + val pairs: MutableMap = HashMap() + attributes[mpid] = pairs + for (j in 0..2) { + val key: String = + RandomUtils.getAlphaNumericString(RandomUtils.randomInt(1, 55)).toUpperCase() + val value: String = + RandomUtils.getAlphaNumericString(RandomUtils.randomInt(1, 55)) + Assert.assertTrue(mUserDelegate!!.setUserAttribute(key, value, mpid, false)) + pairs[key] = value + } + } + AccessUtils.awaitMessageHandler() + + // retrieve and compare + for ((key, value) in attributes) { + val storedUserAttributes = mUserDelegate!!.getUserAttributes(key) + for ((key1, value1) in value) { + if (storedUserAttributes[key1] == null) { + Assert.assertNull(value1) + } else { + Assert.assertEquals(storedUserAttributes[key1].toString(), value1) + } + } + } + + // delete + for ((key, value) in attributes) { + for ((key1) in value) { + Assert.assertTrue(mUserDelegate!!.removeUserAttribute(key1, key)) + } + } + AccessUtils.awaitMessageHandler() + for ((key, value) in attributes) { + val storedUserAttributes = mUserDelegate!!.getUserAttributes(key) + for ((key1) in value) { + Assert.assertNull(storedUserAttributes[key1]) + } + } + } + + @Test + @Throws(Exception::class) + fun testSetConsentState() { + val mpid: Long = Random.Default.nextLong() + val mpid2: Long = Random.Default.nextLong() + val state = mUserDelegate!!.getConsentState(mpid) + Assert.assertNotNull(state) + Assert.assertNotNull(state.gdprConsentState) + Assert.assertEquals(0, state.gdprConsentState.size.toLong()) + val builder = ConsentState.builder() + builder.addGDPRConsentState("foo", GDPRConsent.builder(true).build()) + mUserDelegate!!.setConsentState(builder.build(), mpid) + builder.addGDPRConsentState("foo2", GDPRConsent.builder(true).build()) + mUserDelegate!!.setConsentState(builder.build(), mpid2) + builder.setCCPAConsentState(CCPAConsent.builder(false).build()) + mUserDelegate!!.setConsentState(builder.build(), mpid2) + Assert.assertEquals(1, mUserDelegate!!.getConsentState(mpid).gdprConsentState.size.toLong()) + Assert.assertTrue(mUserDelegate!!.getConsentState(mpid).gdprConsentState.containsKey("foo")) + Assert.assertNull(mUserDelegate!!.getConsentState(mpid).ccpaConsentState) + Assert.assertEquals( + 2, + mUserDelegate!!.getConsentState(mpid2).gdprConsentState.size.toLong() + ) + Assert.assertTrue(mUserDelegate!!.getConsentState(mpid2).gdprConsentState.containsKey("foo")) + Assert.assertTrue(mUserDelegate!!.getConsentState(mpid2).gdprConsentState.containsKey("foo2")) + Assert.assertNotNull(mUserDelegate!!.getConsentState(mpid2).ccpaConsentState) + } + + @Test + @Throws(Exception::class) + fun testRemoveConsentState() { + val mpid: Long = Random.Default.nextLong() + val state = mUserDelegate!!.getConsentState(mpid) + Assert.assertNotNull(state) + Assert.assertNotNull(state.gdprConsentState) + Assert.assertEquals(0, state.gdprConsentState.size.toLong()) + val builder = ConsentState.builder() + builder.addGDPRConsentState("foo", GDPRConsent.builder(true).build()) + builder.setCCPAConsentState(CCPAConsent.builder(true).build()) + mUserDelegate!!.setConsentState(builder.build(), mpid) + Assert.assertEquals(1, mUserDelegate!!.getConsentState(mpid).gdprConsentState.size.toLong()) + Assert.assertNotNull(mUserDelegate!!.getConsentState(mpid).ccpaConsentState) + Assert.assertTrue(mUserDelegate!!.getConsentState(mpid).gdprConsentState.containsKey("foo")) + mUserDelegate!!.setConsentState(null, mpid) + Assert.assertEquals(0, mUserDelegate!!.getConsentState(mpid).gdprConsentState.size.toLong()) + Assert.assertNull(mUserDelegate!!.getConsentState(mpid).ccpaConsentState) + } + + @Test + @Throws(InterruptedException::class) + fun testGetUserAttributesListener() { + val attributeSingles: Map = RandomUtils.getRandomAttributes(5).filter { it.key != null } + val attributeLists: MutableMap> = HashMap() + for ((key, value) in attributeSingles) { + attributeLists[key + value] = listOf(value + key) + } + for ((key, value) in attributeLists) { + mUserDelegate!!.setUserAttributeList(key, value, mStartingMpid) + } + for ((key, value) in attributeSingles) { + mUserDelegate!!.setUserAttribute(key, value, mStartingMpid) + } + AccessUtils.awaitMessageHandler() + val userAttributesResults: Mutable?> = Mutable(null) + val userAttributeListResults: Mutable?>?> = + Mutable(null) + + // fetch on the current (non-main) thread + mUserDelegate!!.getUserAttributes( + object : TypedUserAttributeListener { + override fun onUserAttributesReceived( + userAttributes: Map, + userAttributeLists: Map?>, + mpid: Long + ) { + userAttributesResults.value = userAttributes + userAttributeListResults.value = userAttributeLists + } + }, + mStartingMpid + ) + assertMapEquals(attributeSingles, userAttributesResults.value) + assertMapEquals(attributeLists, userAttributeListResults.value) + userAttributesResults.value = null + userAttributeListResults.value = null + + // fetch on the main thread (seperate code path) + val latch: CountDownLatch = FailureLatch() + Handler(Looper.getMainLooper()).post( + Runnable { + mUserDelegate!!.getUserAttributes( + object : TypedUserAttributeListener { + override fun onUserAttributesReceived( + userAttributes: Map, + userAttributeLists: Map?>, + mpid: Long + ) { + userAttributesResults.value = userAttributes + userAttributeListResults.value = userAttributeLists + latch.countDown() + } + }, + mStartingMpid + ) + } + ) + latch.await() + assertMapEquals(attributeSingles, userAttributesResults.value) + assertMapEquals(attributeLists, userAttributeListResults.value) + } + + private fun assertMapEquals(map1: Map<*, *>, map2: Map<*, *>?) { + if (map2 == null) { + fail("map is null!") + } + Assert.assertEquals("$map1\n\nvs$map2", map1.size.toLong(), map2.size.toLong()) + for (obj in map1.entries) { + val (key, value) = obj + Assert.assertEquals(value, map2[key]) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserTest.java b/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserTest.java deleted file mode 100644 index 18843b26d..000000000 --- a/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.mparticle.identity; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.mparticle.MParticle; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -public class MParticleUserTest extends BaseCleanStartedEachTest { - - @Test - public void testFirstLastSeenTime() throws InterruptedException { - MParticleUser user = MParticle.getInstance().Identity().getCurrentUser(); - long userFirstSeen = user.getFirstSeenTime(); - assertNotNull(user.getFirstSeenTime()); - assertEquals(user.getLastSeenTime(), System.currentTimeMillis(), 10); - - assertTrue(user.getFirstSeenTime() <= user.getLastSeenTime()); - - long newMpid = ran.nextLong(); - mServer.addConditionalLoginResponse(mStartingMpid, newMpid); - final MPLatch latch = new MPLatch(1); - MParticle.getInstance().Identity().login() - .addFailureListener(new TaskFailureListener() { - @Override - public void onFailure(@Nullable IdentityHttpResponse result) { - fail("Identity Request Failed"); - } - }) - .addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(@NonNull IdentityApiResult result) { - latch.countDown(); - } - }); - latch.await(); - MParticleUser user1 = MParticle.getInstance().Identity().getCurrentUser(); - assertEquals(newMpid, user1.getId()); - assertNotNull(user1.getFirstSeenTime()); - assertTrue(user1.getFirstSeenTime() >= user.getLastSeenTime()); - assertEquals(user1.getLastSeenTime(), System.currentTimeMillis(), 10); - assertEquals(userFirstSeen, user.getFirstSeenTime()); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserTest.kt b/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserTest.kt new file mode 100644 index 000000000..4c1ab0f04 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/identity/MParticleUserTest.kt @@ -0,0 +1,45 @@ +package com.mparticle.identity + +import com.mparticle.MParticle +import com.mparticle.messages.IdentityResponseMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse +import org.junit.Assert +import org.junit.Test +import kotlin.random.Random + +class MParticleUserTest : BaseStartedTest() { + @Test + @Throws(InterruptedException::class) + fun testFirstLastSeenTime() { + val user = MParticle.getInstance()!! + .Identity().currentUser + val userFirstSeen = user!!.firstSeenTime + Assert.assertNotNull(user.firstSeenTime) + Assert.assertEquals(user.lastSeenTime.toFloat(), System.currentTimeMillis().toFloat(), 10f) + Assert.assertTrue(user.firstSeenTime <= user.lastSeenTime) + val newMpid: Long = Random.Default.nextLong() + Server + .endpoint(EndpointType.Identity_Login) + .addResponseLogic({ it.body.previousMpid == mStartingMpid }) { + SuccessResponse { + responseObject = IdentityResponseMessage(newMpid) + } + } + val latch = FailureLatch() + MParticle.getInstance()!!.Identity().login() + .addFailureListener { Assert.fail("Identity Request Failed") } + .addSuccessListener { latch.countDown() } + latch.await() + val user1 = MParticle.getInstance()!! + .Identity().currentUser + Assert.assertEquals(newMpid, user1!!.id) + Assert.assertNotNull(user1.firstSeenTime) + Assert.assertTrue(user1.firstSeenTime >= user.lastSeenTime) + Assert.assertEquals(user1.lastSeenTime.toFloat(), System.currentTimeMillis().toFloat(), 10f) + Assert.assertEquals(userFirstSeen, user.firstSeenTime) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/AppStateManagerInstrumentedTest.java b/android-core/src/androidTest/java/com/mparticle/internal/AppStateManagerInstrumentedTest.java deleted file mode 100644 index 38aabd46c..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/AppStateManagerInstrumentedTest.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.mparticle.internal; - -import android.content.Context; -import android.util.MutableBoolean; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.internal.database.services.AccessUtils; -import com.mparticle.internal.database.services.MParticleDBManager; -import com.mparticle.internal.messages.BaseMPMessage; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import org.json.JSONArray; -import org.json.JSONException; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class AppStateManagerInstrumentedTest extends BaseCleanStartedEachTest { - AppStateManager mAppStateManager; - - @Before - public void before() throws Exception { - mAppStateManager = MParticle.getInstance().Internal().getAppStateManager(); - MParticle.getInstance().Internal().getConfigManager().setMpid(Constants.TEMPORARY_MPID, false); - } - - @Test - public void testEndSessionMultipleMpids() throws Exception { - final Set mpids = new HashSet(); - for (int i = 0; i < 5; i++) { - mpids.add(ran.nextLong()); - } - mAppStateManager.ensureActiveSession(); - for (Long mpid: mpids) { - mAppStateManager.getSession().addMpid(mpid); - } - final boolean[] checked = new boolean[1]; - final CountDownLatch latch = new MPLatch(1); - AccessUtils.setMessageStoredListener(new MParticleDBManager.MessageListener() { - @Override - public void onMessageStored(BaseMPMessage message) { - if (message.getMessageType().equals(Constants.MessageType.SESSION_END)) { - try { - JSONArray mpidsArray = message.getJSONArray(Constants.MessageKey.SESSION_SPANNING_MPIDS); - assertEquals(mpidsArray.length(), mpids.size()); - for (int i = 0; i < mpidsArray.length(); i++) { - if (!mpids.contains(mpidsArray.getLong(i))) { - return; - } - } - checked[0] = true; - latch.countDown(); - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - }); - mAppStateManager.endSession(); - latch.await(); - assertTrue(checked[0]); - } - - @Test - public void testDontIncludeDefaultMpidSessionEnd() throws Exception { - final Set mpids = new HashSet(); - for (int i = 0; i < 5; i++) { - mpids.add(ran.nextLong()); - } - mpids.add(Constants.TEMPORARY_MPID); - mAppStateManager.ensureActiveSession(); - for (Long mpid: mpids) { - mAppStateManager.getSession().addMpid(mpid); - } - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean checked = new MutableBoolean(false); - AccessUtils.setMessageStoredListener(new MParticleDBManager.MessageListener() { - @Override - public void onMessageStored(BaseMPMessage message) { - if (message.getMessageType().equals(Constants.MessageType.SESSION_END)) { - try { - JSONArray mpidsArray = message.getJSONArray(Constants.MessageKey.SESSION_SPANNING_MPIDS); - if (mpidsArray.length() == mpids.size() - 1) { - for (int i = 0; i < mpidsArray.length(); i++) { - if (!mpids.contains(mpidsArray.getLong(i)) || mpidsArray.getLong(i) == Constants.TEMPORARY_MPID) { - return; - } - } - checked.value = true; - latch.countDown(); - } - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - }); - mAppStateManager.endSession(); - latch.await(); - assertTrue(checked.value); - } - - @Test - public void testOnApplicationForeground() throws InterruptedException { - CountDownLatch latch = new MPLatch(2); - KitManagerTester kitManagerTester = new KitManagerTester(mContext, latch); - com.mparticle.AccessUtils.setKitManager(kitManagerTester); - goToBackground(); - assertNull(mAppStateManager.getCurrentActivity()); - Thread.sleep(AppStateManager.ACTIVITY_DELAY + 100); - - goToForeground(); - assertNotNull(mAppStateManager.getCurrentActivity().get()); - latch.await(); - assertTrue(kitManagerTester.onApplicationBackgroundCalled); - assertTrue(kitManagerTester.onApplicationForegroundCalled); - } - - class KitManagerTester extends KitFrameworkWrapper { - boolean onApplicationBackgroundCalled, onApplicationForegroundCalled = false; - CountDownLatch latch; - - public KitManagerTester(Context context, CountDownLatch latch) { - super(context, - new ReportingManager() { - @Override - public void log(JsonReportingMessage message) { - //do nothing - } - - @Override - public void logAll(List messageList) { - //do nothing - } - }, - MParticle.getInstance().Internal().getConfigManager(), - MParticle.getInstance().Internal().getAppStateManager(), - MParticleOptions.builder(mContext).credentials("some", "key").build()); - this.latch = latch; - } - - @Override - public void onApplicationBackground() { - assertNull(getCurrentActivity()); - onApplicationBackgroundCalled = true; - latch.countDown(); - } - - @Override - public void onApplicationForeground() { - assertNotNull(getCurrentActivity().get()); - onApplicationForegroundCalled = true; - latch.countDown(); - } - } - -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/AppStateManagerInstrumentedTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/AppStateManagerInstrumentedTest.kt new file mode 100644 index 000000000..801f5cd19 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/AppStateManagerInstrumentedTest.kt @@ -0,0 +1,184 @@ +package com.mparticle.internal + +import android.app.Activity +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.util.MutableBoolean +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.internal.database.services.AccessUtils +import com.mparticle.internal.database.services.MParticleDBManager +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import org.json.JSONArray +import org.json.JSONException +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class AppStateManagerInstrumentedTest : BaseStartedTest() { + init { + if (Looper.myLooper() == null) { + Looper.prepare() + } + } + var mAppStateManager: AppStateManager? = null + @Before + @Throws(Exception::class) + fun before() { + mAppStateManager = MParticle.getInstance()!!.Internal().appStateManager + MParticle.getInstance()!!.Internal().configManager.setMpid(Constants.TEMPORARY_MPID, false) + } + + @Test + @Throws(Exception::class) + fun testEndSessionMultipleMpids() { + val mpids: MutableSet = HashSet() + for (i in 0..4) { + mpids.add(Random.Default.nextLong()) + } + mAppStateManager!!.ensureActiveSession() + for (mpid in mpids) { + mAppStateManager!!.session.addMpid(mpid) + } + val checked = BooleanArray(1) + val latch: CountDownLatch = FailureLatch() + AccessUtils.setMessageStoredListener(object : MParticleDBManager.MessageListener { + override fun onMessageStored(message: BaseMPMessage) { + if (message.getMessageType() == Constants.MessageType.SESSION_END) { + try { + val mpidsArray: JSONArray = + message.getJSONArray(Constants.MessageKey.SESSION_SPANNING_MPIDS) + Assert.assertEquals(mpidsArray.length().toLong(), mpids.size.toLong()) + for (i in 0 until mpidsArray.length()) { + if (!mpids.contains(mpidsArray.getLong(i))) { + return + } + } + checked[0] = true + latch.countDown() + } catch (e: JSONException) { + e.printStackTrace() + } + } + } + }) + mAppStateManager!!.endSession() + latch.await() + Assert.assertTrue(checked[0]) + } + + @Test + @Throws(Exception::class) + fun testDontIncludeDefaultMpidSessionEnd() { + val mpids: MutableSet = HashSet() + for (i in 0..4) { + mpids.add(Random.Default.nextLong()) + } + mpids.add(Constants.TEMPORARY_MPID) + mAppStateManager!!.ensureActiveSession() + for (mpid in mpids) { + mAppStateManager!!.session.addMpid(mpid) + } + val latch: CountDownLatch = FailureLatch() + val checked = MutableBoolean(false) + AccessUtils.setMessageStoredListener(object : MParticleDBManager.MessageListener { + override fun onMessageStored(message: BaseMPMessage) { + if (message.getMessageType() == Constants.MessageType.SESSION_END) { + try { + val mpidsArray: JSONArray = + message.getJSONArray(Constants.MessageKey.SESSION_SPANNING_MPIDS) + if (mpidsArray.length() == mpids.size - 1) { + for (i in 0 until mpidsArray.length()) { + if (!mpids.contains(mpidsArray.getLong(i)) || mpidsArray.getLong(i) == Constants.TEMPORARY_MPID) { + return + } + } + checked.value = true + latch.countDown() + } + } catch (e: JSONException) { + e.printStackTrace() + } + } + } + }) + mAppStateManager!!.endSession() + latch.await() + Assert.assertTrue(checked.value) + } + + @Test + @Throws(InterruptedException::class) + fun testOnApplicationForeground() { + val latch: CountDownLatch = FailureLatch(count = 2) + val kitManagerTester = KitManagerTester(context, latch) + com.mparticle.AccessUtils.setKitManager(kitManagerTester) + sendBackground() + Assert.assertNull(mAppStateManager!!.currentActivity) + Thread.sleep(AppStateManager.ACTIVITY_DELAY + 100) + sendForeground() + Assert.assertNotNull(mAppStateManager!!.currentActivity.get()) + latch.await() + Assert.assertTrue(kitManagerTester.onApplicationBackgroundCalled) + Assert.assertTrue(kitManagerTester.onApplicationForegroundCalled) + } + + internal inner class KitManagerTester(context: Context, var latch: CountDownLatch) : + KitFrameworkWrapper( + context, + object : ReportingManager { + override fun log(message: JsonReportingMessage) { + // do nothing + } + + override fun logAll(messageList: List) { + // do nothing + } + }, + MParticle.getInstance()!!.Internal().configManager, + MParticle.getInstance()!!.Internal().appStateManager, + MParticleOptions.builder(context).credentials("some", "key").build() + ) { + var onApplicationBackgroundCalled = false + var onApplicationForegroundCalled = false + override fun onApplicationBackground() { + Assert.assertNull(currentActivity) + onApplicationBackgroundCalled = true + latch.countDown() + } + + override fun onApplicationForeground() { + Assert.assertNotNull(currentActivity.get()) + onApplicationForegroundCalled = true + latch.countDown() + } + } + + var activity = Activity() + + protected fun sendBackground() { + if (MParticle.getInstance() != null) { + val appStateManager = MParticle.getInstance()!!.Internal().appStateManager + // Need to set AppStateManager's Handler to be on the main looper, otherwise, it will not put the app in the background. + com.mparticle.internal.AccessUtils.setAppStateManagerHandler(Handler(Looper.getMainLooper())) + if (appStateManager.isBackgrounded) { + appStateManager.onActivityResumed(activity) + } + appStateManager.onActivityPaused(activity) + } + } + + protected fun sendForeground() { + activity = Activity() + if (MParticle.getInstance() != null) { + val appStateManager = MParticle.getInstance()!!.Internal().appStateManager + appStateManager.onActivityResumed(activity) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/ConfigManagerInstrumentedTest.java b/android-core/src/androidTest/java/com/mparticle/internal/ConfigManagerInstrumentedTest.java deleted file mode 100644 index 2b14ac9a0..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/ConfigManagerInstrumentedTest.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.mparticle.internal; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.fail; - -import com.mparticle.Configuration; -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.BaseAbstractTest; -import com.mparticle.testutils.MPLatch; -import com.mparticle.testutils.TestingUtils; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public class ConfigManagerInstrumentedTest extends BaseAbstractTest { - - @Test - public void testSetMpidCurrentUserState() throws InterruptedException { - final Long mpid1 = ran.nextLong(); - final Long mpid2 = ran.nextLong(); - final Long mpid3 = ran.nextLong(); - - startMParticle(); - - ConfigManager configManager = MParticle.getInstance().Internal().getConfigManager(); - - assertEquals(mStartingMpid.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - assertEquals(mStartingMpid.longValue(), configManager.getMpid()); - - configManager.setMpid(mpid1, ran.nextBoolean()); - assertEquals(mpid1.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - - boolean newIsLoggedIn = !MParticle.getInstance().Identity().getCurrentUser().isLoggedIn(); - - configManager.setMpid(mpid1, newIsLoggedIn); - assertEquals(mpid1.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - assertEquals(newIsLoggedIn, MParticle.getInstance().Identity().getCurrentUser().isLoggedIn()); - - configManager.setMpid(mpid2, false); - assertEquals(mpid2.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - assertFalse(MParticle.getInstance().Identity().getCurrentUser().isLoggedIn()); - - configManager.setMpid(mpid2, true); - assertEquals(mpid2.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - assertTrue(MParticle.getInstance().Identity().getCurrentUser().isLoggedIn()); - - configManager.setMpid(mpid3, true); - assertEquals(mpid3.longValue(), MParticle.getInstance().Identity().getCurrentUser().getId()); - assertTrue(MParticle.getInstance().Identity().getCurrentUser().isLoggedIn()); - } - - @Test - public void testConfigResponseParsing() throws JSONException, InterruptedException { - String token = mRandomUtils.getAlphaNumericString(20); - int aliasMaxWindow = ran.nextInt(); - - JSONObject config = new JSONObject() - .put("wst", token) - .put(ConfigManager.ALIAS_MAX_WINDOW, aliasMaxWindow); - - mServer.setupConfigResponse(config.toString()); - BothConfigsLoadedListener configLoadedListener = new BothConfigsLoadedListener(); - MPLatch latch = configLoadedListener.latch; - - startMParticle(MParticleOptions.builder(mContext).configuration(new AddConfigListener(configLoadedListener))); - latch.await(); - - assertEquals(token, MParticle.getInstance().Internal().getConfigManager().getWorkspaceToken()); - assertEquals(aliasMaxWindow, MParticle.getInstance().Internal().getConfigManager().getAliasMaxWindow()); - - //test set defaults when fields are not present - MParticle.setInstance(null); - mServer.setupConfigResponse(new JSONObject().toString()); - configLoadedListener = new BothConfigsLoadedListener(); - latch = configLoadedListener.latch; - - startMParticle(MParticleOptions.builder(mContext).configuration(new AddConfigListener(configLoadedListener))); - latch.await(); - - assertEquals("", MParticle.getInstance().Internal().getConfigManager().getWorkspaceToken()); - assertEquals(90, MParticle.getInstance().Internal().getConfigManager().getAliasMaxWindow()); - } - - @Test - public void cachedConfigLoadedExactlyOnce() throws InterruptedException, JSONException { - MPLatch latch = new MPLatch(1); - AndroidUtils.Mutable loadedCoreLocal = new AndroidUtils.Mutable<>(false); - AndroidUtils.Mutable loadedKitLocal = new AndroidUtils.Mutable<>(false); - - setCachedConfig(getSimpleConfigWithKits()); - mServer.setupConfigDeferred(); - ConfigManager.ConfigLoadedListener configLoadedListener = new ConfigManager.ConfigLoadedListener() { - @Override - public void onConfigUpdated(ConfigManager.ConfigType configType, boolean isNew) { - if (!isNew) { - switch (configType) { - case CORE: - if (loadedCoreLocal.value) { - fail("core config already loaded"); - } else { - Logger.error("LOADED CACHED Core"); - loadedCoreLocal.value = true; - } - case KIT: - if (loadedKitLocal.value) { - fail("kit config already loaded"); - } else { - Logger.error("LOADED CACHED Kit"); - loadedKitLocal.value = true; - } - } - } - if (loadedCoreLocal.value && loadedKitLocal.value) { - latch.countDown(); - - } - Logger.error("KIT = " + loadedKitLocal.value + " Core: " + loadedCoreLocal.value); - } - }; - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials("key", "secret") - .configuration(new AddConfigListener(configLoadedListener)) - .build(); - MParticle.start(options); - - //wait until both local configs are loaded - latch.await(); - - //try to coerce another load... - new ConfigManager(mContext); - MParticle instance = MParticle.getInstance(); - instance.logEvent(TestingUtils.getInstance().getRandomMPEventSimple()); - instance.setOptOut(true); - instance.setOptOut(false); - - //and finally, load remote config - mServer.setupConfigResponse(getSimpleConfigWithKits().toString()); - fetchConfig(); - BothConfigsLoadedListener bothConfigsLoadedListener = new BothConfigsLoadedListener(); - MPLatch reloadLatch = bothConfigsLoadedListener.latch; - MParticle.getInstance().Internal().getConfigManager().addConfigUpdatedListener(bothConfigsLoadedListener); - reloadLatch.await(); - } - - class BothConfigsLoadedListener implements ConfigManager.ConfigLoadedListener { - Set types; - MPLatch latch = new MPLatch(1); - - public BothConfigsLoadedListener(ConfigManager.ConfigType... configTypes) { - if (configTypes == null || configTypes.length == 0) { - configTypes = new ConfigManager.ConfigType[]{ConfigManager.ConfigType.CORE}; - } - types = this.types = new HashSet(Arrays.asList(configTypes)); - } - @Override - public void onConfigUpdated(ConfigManager.ConfigType configType, boolean isNew) { - if (isNew) { - types.remove(configType); - } - if (types.size() == 0) { - latch.countDown(); - } - } - } - - class AddConfigListener implements Configuration { - ConfigManager.ConfigLoadedListener configLoadedListener; - - public AddConfigListener(ConfigManager.ConfigLoadedListener configLoadedListener) { - this.configLoadedListener = configLoadedListener; - } - - @Override - public Class configures() { - return ConfigManager.class; - } - - @Override - public void apply(ConfigManager configManager) { - configManager.addConfigUpdatedListener(configLoadedListener); - } - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/ConfigManagerInstrumentedTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/ConfigManagerInstrumentedTest.kt new file mode 100644 index 000000000..a3cb5de32 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/ConfigManagerInstrumentedTest.kt @@ -0,0 +1,263 @@ +package com.mparticle.internal + +import com.mparticle.Configuration +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.internal.ConfigManager.ConfigLoadedListener +import com.mparticle.internal.ConfigManager.ConfigType +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.messages.KitConfigMessage +import com.mparticle.messages.toJsonString +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.TestingUtils +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.ErrorResponse +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse +import com.mparticle.utils.startMParticle +import junit.framework.TestCase +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Test +import java.util.Arrays +import kotlin.random.Random + +class ConfigManagerInstrumentedTest : BaseTest() { + fun simpleConfigWithKits() = ConfigResponseMessage( + id = "12345", + kits = listOf( + KitConfigMessage( + id = 1 + ) + ) + ) + + @Test + @Throws(InterruptedException::class) + fun testSetMpidCurrentUserState() { + val mpid1: Long = Random.Default.nextLong() + val mpid2: Long = Random.Default.nextLong() + val mpid3: Long = Random.Default.nextLong() + startMParticle() + val configManager = MParticle.getInstance()!!.Internal().configManager + Assert.assertEquals( + mStartingMpid, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + Assert.assertEquals(mStartingMpid, configManager.mpid) + configManager.setMpid(mpid1, Random.Default.nextBoolean()) + TestCase.assertEquals( + mpid1, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + val newIsLoggedIn = !MParticle.getInstance()!! + .Identity().currentUser!!.isLoggedIn + configManager.setMpid(mpid1, newIsLoggedIn) + TestCase.assertEquals( + mpid1, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + TestCase.assertEquals( + newIsLoggedIn, + MParticle.getInstance()!! + .Identity().currentUser!!.isLoggedIn + ) + configManager.setMpid(mpid2, false) + TestCase.assertEquals( + mpid2, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + TestCase.assertFalse( + MParticle.getInstance()!!.Identity().currentUser!!.isLoggedIn + ) + configManager.setMpid(mpid2, true) + TestCase.assertEquals( + mpid2, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + TestCase.assertTrue( + MParticle.getInstance()!!.Identity().currentUser!!.isLoggedIn + ) + configManager.setMpid(mpid3, true) + TestCase.assertEquals( + mpid3, + MParticle.getInstance()!! + .Identity().currentUser!!.id + ) + TestCase.assertTrue( + MParticle.getInstance()!!.Identity().currentUser!!.isLoggedIn + ) + } + + @Test + @Throws(JSONException::class, InterruptedException::class) + fun testConfigResponseParsing() { + val token: String = RandomUtils.getAlphaNumericString(20) + val aliasMaxWindow: Int = Random.Default.nextInt() + val config = ConfigResponseMessage( + workspaceToken = token, + aliasMaxWindow = aliasMaxWindow + ) + Server + .endpoint(EndpointType.Config) + .nextResponse { + SuccessResponse { + responseObject = config + } + } + + var configLoadedListener = BothConfigsLoadedListener() + var latch = configLoadedListener.latch + startMParticle( + MParticleOptions.builder(context) + .configuration(AddConfigListener(configLoadedListener)) + ) + latch.await() + TestCase.assertEquals( + token, + MParticle.getInstance()!!.Internal().configManager.workspaceToken + ) + TestCase.assertEquals( + aliasMaxWindow, + MParticle.getInstance()!! + .Internal().configManager.aliasMaxWindow + ) + + // test set defaults when fields are not present + MParticle.setInstance(null) + Server + .endpoint(EndpointType.Config) + .nextResponse { + SuccessResponse { responseObject = ConfigResponseMessage() } + } + configLoadedListener = BothConfigsLoadedListener() + latch = configLoadedListener.latch + startMParticle( + MParticleOptions.builder(context) + .configuration(AddConfigListener(configLoadedListener)) + ) + latch.await() + TestCase.assertEquals("", MParticle.getInstance()!!.Internal().configManager.workspaceToken) + TestCase.assertEquals(90, MParticle.getInstance()!!.Internal().configManager.aliasMaxWindow) + } + + @Test + @Throws(InterruptedException::class, JSONException::class) + fun cachedConfigLoadedExactlyOnce() { + val latch = FailureLatch() + val loadedCoreLocal = Mutable(false) + val loadedKitLocal = Mutable(false) + ConfigManager.getInstance(context) + .saveConfigJson( + JSONObject(simpleConfigWithKits().toJsonString()), null, null, System.currentTimeMillis() + ) + Server + .endpoint(EndpointType.Config) + .nextResponse { ErrorResponse(304) } + + val configLoadedListener: ConfigLoadedListener = object : ConfigLoadedListener { + override fun onConfigUpdated(configType: ConfigType, isNew: Boolean) { + if (!isNew) { + when (configType) { + ConfigType.CORE -> { + if (loadedCoreLocal.value) { + Assert.fail("core config already loaded") + } else { + Logger.error("LOADED CACHED Core") + loadedCoreLocal.value = true + } + if (loadedKitLocal.value) { + Assert.fail("kit config already loaded") + } else { + Logger.error("LOADED CACHED Kit") + loadedKitLocal.value = true + } + } + ConfigType.KIT -> if (loadedKitLocal.value) { + Assert.fail("kit config already loaded") + } else { + Logger.error("LOADED CACHED Kit") + loadedKitLocal.value = true + } + } + } + if (loadedCoreLocal.value && loadedKitLocal.value) { + latch.countDown() + } + Logger.error("KIT = " + loadedKitLocal.value.toString() + " Core: " + loadedCoreLocal.value) + } + } + val options = MParticleOptions.builder(context) + .credentials("key", "secret") + .configuration(AddConfigListener(configLoadedListener)) + .build() + MParticle.start(options) + + // wait until both local configs are loaded + latch.await() + + // try to coerce another load... + ConfigManager(context) + val instance = MParticle.getInstance() + instance!!.logEvent(TestingUtils.randomMPEventRich.event()) + instance.optOut = true + instance.optOut = false + + // and finally, load remote config + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse { responseObject = simpleConfigWithKits() } } + AccessUtils.fetchConfig() + + val bothConfigsLoadedListener = BothConfigsLoadedListener() + val reloadLatch = bothConfigsLoadedListener.latch + MParticle.getInstance()!!.Internal().configManager.addConfigUpdatedListener( + bothConfigsLoadedListener + ) + reloadLatch.await() + } + + internal inner class BothConfigsLoadedListener(vararg configTypes: ConfigType?) : + ConfigLoadedListener { + var types: MutableSet + var latch = FailureLatch() + override fun onConfigUpdated(configType: ConfigType, isNew: Boolean) { + if (isNew) { + types.remove(configType) + } + if (types.size == 0) { + latch.countDown() + } + } + + init { + var configTypes: Array = configTypes + if (configTypes == null || configTypes.size == 0) { + configTypes = arrayOf(ConfigType.CORE) + } + types = HashSet(Arrays.asList(*configTypes)) + types = types + } + } + + internal inner class AddConfigListener(val configLoadedListener: ConfigLoadedListener) : + Configuration { + override fun configures(): Class { + return ConfigManager::class.java + } + + override fun apply(configManager: ConfigManager) { + configManager.addConfigUpdatedListener(configLoadedListener) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/DeviceAttributesTests.java b/android-core/src/androidTest/java/com/mparticle/internal/DeviceAttributesTests.java deleted file mode 100644 index 4b52f0110..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/DeviceAttributesTests.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.mparticle.internal; - -import android.content.Context; -import androidx.test.platform.app.InstrumentationRegistry; - -import com.mparticle.testutils.BaseCleanInstallEachTest; -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; - -import org.json.JSONObject; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class DeviceAttributesTests extends BaseCleanInstallEachTest { - - @Test - public void testAndroidIDCollection() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - JSONObject attributes = new JSONObject(); - DeviceAttributes.addAndroidId(attributes, context); - assertFalse(attributes.has(Constants.MessageKey.DEVICE_ANID)); - assertFalse(attributes.has(Constants.MessageKey.DEVICE_OPEN_UDID)); - assertFalse(attributes.has(Constants.MessageKey.DEVICE_ID)); - - MParticleOptions options = MParticleOptions.builder(context) - .androidIdEnabled(false) - .credentials("key", "secret") - .build(); - MParticle.start(options); - JSONObject newAttributes = new JSONObject(); - DeviceAttributes.addAndroidId(newAttributes, context); - assertTrue(newAttributes.length() == 0); - - MParticle.setInstance(null); - - options = MParticleOptions.builder(context) - .androidIdEnabled(true) - .credentials("key", "secret") - .build(); - MParticle.start(options); - newAttributes = new JSONObject(); - String androidId = MPUtility.getAndroidID(context); - DeviceAttributes.addAndroidId(newAttributes, context); - assertTrue(newAttributes.length() == 3); - assertEquals(newAttributes.getString(Constants.MessageKey.DEVICE_ANID),androidId); - assertTrue(newAttributes.getString(Constants.MessageKey.DEVICE_OPEN_UDID).length() > 0); - assertEquals(newAttributes.getString(Constants.MessageKey.DEVICE_ID),androidId); - - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/DeviceAttributesTests.kt b/android-core/src/androidTest/java/com/mparticle/internal/DeviceAttributesTests.kt new file mode 100644 index 000000000..bd2921e9e --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/DeviceAttributesTests.kt @@ -0,0 +1,45 @@ +package com.mparticle.internal + +import com.mparticle.testing.BaseTest +class DeviceAttributesTests : BaseTest() { + @org.junit.Test + @Throws(java.lang.Exception::class) + fun testAndroidIDCollection() { + val context = + androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().context + val attributes = org.json.JSONObject() + DeviceAttributes.addAndroidId(attributes, context) + org.junit.Assert.assertFalse(attributes.has(Constants.MessageKey.DEVICE_ANID)) + org.junit.Assert.assertFalse(attributes.has(Constants.MessageKey.DEVICE_OPEN_UDID)) + org.junit.Assert.assertFalse(attributes.has(Constants.MessageKey.DEVICE_ID)) + var options = com.mparticle.MParticleOptions.builder(context) + .androidIdEnabled(false) + .credentials("key", "secret") + .build() + com.mparticle.MParticle.start(options) + var newAttributes = org.json.JSONObject() + DeviceAttributes.addAndroidId(newAttributes, context) + org.junit.Assert.assertTrue(newAttributes.length() == 0) + com.mparticle.MParticle.setInstance(null) + options = com.mparticle.MParticleOptions.builder(context) + .androidIdEnabled(true) + .credentials("key", "secret") + .build() + com.mparticle.MParticle.start(options) + newAttributes = org.json.JSONObject() + val androidId = MPUtility.getAndroidID(context) + DeviceAttributes.addAndroidId(newAttributes, context) + org.junit.Assert.assertTrue(newAttributes.length() == 3) + org.junit.Assert.assertEquals( + newAttributes.getString(Constants.MessageKey.DEVICE_ANID), + androidId + ) + org.junit.Assert.assertTrue( + newAttributes.getString(Constants.MessageKey.DEVICE_OPEN_UDID).isNotEmpty() + ) + org.junit.Assert.assertEquals( + newAttributes.getString(Constants.MessageKey.DEVICE_ID), + androidId + ) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/KitFrameworkWrapperTest.java b/android-core/src/androidTest/java/com/mparticle/internal/KitFrameworkWrapperTest.java deleted file mode 100644 index d8b339400..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/KitFrameworkWrapperTest.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.mparticle.internal; - -import android.content.Context; -import android.util.MutableBoolean; - -import com.mparticle.AccessUtils; -import com.mparticle.MParticle; -import com.mparticle.identity.IdentityApiRequest; -import com.mparticle.identity.MParticleUser; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.MPLatch; - -import org.junit.Test; - -import java.util.Random; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class KitFrameworkWrapperTest extends BaseCleanStartedEachTest { - - private void setKitManager(KitFrameworkWrapper kitManager) { - AccessUtils.setKitManager(kitManager); - com.mparticle.identity.AccessUtils.setKitManager(kitManager); - } - - @Test - public void testIdentify() throws InterruptedException { - final Long mpid = ran.nextLong(); - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean called = new MutableBoolean(false); - setKitManager(new StubKitManager(mContext) { - @Override - public void onIdentifyCompleted(MParticleUser user, IdentityApiRequest request) { - if (user.getId() == mStartingMpid) { - return; - } - assertEquals(mpid.longValue(), user.getId()); - called.value = true; - latch.countDown(); - } - }); - mServer.setupHappyIdentify(mpid); - MParticle.getInstance().Identity().identify(IdentityApiRequest.withEmptyUser().build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLogin() throws InterruptedException { - final Long mpid = ran.nextLong(); - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean called = new MutableBoolean(false); - setKitManager(new StubKitManager(mContext) { - @Override - public void onLoginCompleted(MParticleUser user, IdentityApiRequest request) { - if (user.getId() == mStartingMpid) { - return; - } - assertEquals(mpid.longValue(), user.getId()); - called.value = true; - latch.countDown(); - } - }); - mServer.setupHappyLogin(mpid); - MParticle.getInstance().Identity().login(IdentityApiRequest.withEmptyUser().build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLogout() throws InterruptedException { - final Long mpid = ran.nextLong(); - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean called = new MutableBoolean(false); - setKitManager(new StubKitManager(mContext) { - @Override - public void onLogoutCompleted(MParticleUser user, IdentityApiRequest request) { - if (user.getId() == mStartingMpid) { - return; - } - assertEquals(mpid.longValue(), user.getId()); - called.value = true; - latch.countDown(); - } - }); - mServer.setupHappyLogout(mpid); - MParticle.getInstance().Identity().logout(IdentityApiRequest.withEmptyUser().build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testModify() throws InterruptedException { - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean called = new MutableBoolean(false); - setKitManager(new StubKitManager(mContext) { - @Override - public void onModifyCompleted(MParticleUser user, IdentityApiRequest request) { - assertEquals(mStartingMpid.longValue(), user.getId()); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().modify(IdentityApiRequest.withUser(MParticle.getInstance().Identity().getCurrentUser()).build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testModifyUserChanged() throws InterruptedException { - final CountDownLatch latch = new MPLatch(1); - final MutableBoolean called = new MutableBoolean(false); - setKitManager(new StubKitManager(mContext) { - @Override - public void onModifyCompleted(MParticleUser user, IdentityApiRequest request) { - assertEquals(mStartingMpid.longValue(), user.getId()); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().modify(IdentityApiRequest.withEmptyUser().build()); - MParticle.getInstance().Internal().getConfigManager().setMpid(0, ran.nextBoolean()); - latch.await(); - final CountDownLatch latch2 = new MPLatch(1); - final Long mpid2 = ran.nextLong(); - MParticle.getInstance().Internal().getConfigManager().setMpid(mpid2, ran.nextBoolean()); - assertTrue(called.value); - called.value = false; - setKitManager(new StubKitManager(mContext) { - @Override - public void onModifyCompleted(MParticleUser user, IdentityApiRequest request) { - assertEquals(mpid2.longValue(), user.getId()); - called.value = true; - latch2.countDown(); - } - }); - MParticle.getInstance().Identity().modify(IdentityApiRequest.withUser(MParticle.getInstance().Identity().getCurrentUser()).build()); - MParticle.getInstance().Internal().getConfigManager().setMpid(ran.nextLong(), ran.nextBoolean()); - latch2.await(); - assertTrue(called.value); - } - - static class StubKitManager extends KitFrameworkWrapper { - - public StubKitManager(Context context) { - super(context, null, null, null, true, null); - setKitManager(null); - } - - @Override - public void loadKitLibrary() { - - } - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/KitFrameworkWrapperTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/KitFrameworkWrapperTest.kt new file mode 100644 index 000000000..4b81f684b --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/KitFrameworkWrapperTest.kt @@ -0,0 +1,175 @@ +package com.mparticle.internal + +import android.content.Context +import android.util.MutableBoolean +import com.mparticle.AccessUtils +import com.mparticle.MParticle +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.identity.MParticleUser +import com.mparticle.messages.IdentityResponseMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test +import java.util.concurrent.CountDownLatch +import kotlin.random.Random + +class KitFrameworkWrapperTest : BaseStartedTest() { + private fun setKitManager(kitManager: KitFrameworkWrapper) { + AccessUtils.setKitManager(kitManager) + com.mparticle.identity.AccessUtils.setKitManager(kitManager) + } + + @Test + @Throws(InterruptedException::class) + fun testIdentify() { + val mpid: Long = Random.Default.nextLong() + val latch: CountDownLatch = FailureLatch() + val called = Mutable(false) + setKitManager(object : StubKitManager(context) { + override fun onIdentifyCompleted(user: MParticleUser, request: IdentityApiRequest) { + if (user.id == mStartingMpid) { + return + } + assertEquals(mpid, user.id) + called.value = true + latch.countDown() + } + }) + Server.endpoint(EndpointType.Identity_Identify) + .addResponseLogic({ true }) { + SuccessResponse { responseObject = IdentityResponseMessage(mpid = mpid) } + } + MParticle.getInstance()!! + .Identity().identify(IdentityApiRequest.withEmptyUser().build()) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(InterruptedException::class) + fun testLogin() { + val mpid: Long = Random.Default.nextLong() + val latch: CountDownLatch = FailureLatch() + val called = Mutable(false) + setKitManager(object : StubKitManager(context) { + override fun onLoginCompleted(user: MParticleUser, request: IdentityApiRequest) { + if (user.id == mStartingMpid) { + return + } + assertEquals(mpid, user.id) + called.value = true + latch.countDown() + } + }) + Server.endpoint(EndpointType.Identity_Login) + .addResponseLogic({ true }) { + SuccessResponse { responseObject = IdentityResponseMessage(mpid = mpid) } + } + MParticle.getInstance()!! + .Identity().login(IdentityApiRequest.withEmptyUser().build()) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(InterruptedException::class) + fun testLogout() { + val mpid: Long = Random.Default.nextLong() + val latch: CountDownLatch = FailureLatch() + val called = Mutable(false) + setKitManager(object : StubKitManager(context) { + override fun onLogoutCompleted(user: MParticleUser, request: IdentityApiRequest) { + if (user.id == mStartingMpid) { + return + } + assertEquals(mpid, user.id) + called.value = true + latch.countDown() + } + }) + Server.endpoint(EndpointType.Identity_Logout) + .addResponseLogic({ true }) { + SuccessResponse { responseObject = IdentityResponseMessage(mpid = mpid) } + } + MParticle.getInstance()!! + .Identity().logout(IdentityApiRequest.withEmptyUser().build()) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(InterruptedException::class) + fun testModify() { + val latch: CountDownLatch = FailureLatch() + val called = Mutable(false) + setKitManager(object : StubKitManager(context) { + override fun onModifyCompleted(user: MParticleUser, request: IdentityApiRequest) { + assertEquals(mStartingMpid, user.id) + called.value = true + latch.countDown() + } + }) + MParticle.getInstance()!!.Identity().modify( + IdentityApiRequest.withUser( + MParticle.getInstance()!!.Identity().currentUser + ).build() + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(InterruptedException::class) + fun testModifyUserChanged() { + val latch: CountDownLatch = FailureLatch() + val called = MutableBoolean(false) + setKitManager(object : StubKitManager(context) { + override fun onModifyCompleted(user: MParticleUser, request: IdentityApiRequest) { + assertEquals(mStartingMpid, user.id) + called.value = true + latch.countDown() + } + }) + MParticle.getInstance()!! + .Identity().modify(IdentityApiRequest.withEmptyUser().build()) + MParticle.getInstance()!!.Internal().configManager.setMpid(0, Random.Default.nextBoolean()) + latch.await() + val latch2: CountDownLatch = FailureLatch() + val mpid2: Long = Random.Default.nextLong() + MParticle.getInstance()!!.Internal().configManager.setMpid(mpid2, Random.Default.nextBoolean()) + Assert.assertTrue(called.value) + called.value = false + setKitManager(object : StubKitManager(context) { + override fun onModifyCompleted(user: MParticleUser, request: IdentityApiRequest) { + assertEquals(mpid2, user.id) + called.value = true + latch2.countDown() + } + }) + MParticle.getInstance()!!.Identity().modify( + IdentityApiRequest.withUser( + MParticle.getInstance()!!.Identity().currentUser + ).build() + ) + MParticle.getInstance()!! + .Internal().configManager.setMpid(Random.Default.nextLong(), Random.Default.nextBoolean()) + latch2.await() + Assert.assertTrue(called.value) + } + + internal open class StubKitManager(context: Context?) : + KitFrameworkWrapper(context, null, null, null, true, null) { + override fun loadKitLibrary() {} + + init { + setKitManager(null) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/MPUtilityTest.java b/android-core/src/androidTest/java/com/mparticle/internal/MPUtilityTest.java deleted file mode 100644 index 58f48507a..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/MPUtilityTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.mparticle.internal; - -import android.content.Context; -import android.telephony.TelephonyManager; - -import com.mparticle.testutils.BaseCleanInstallEachTest; - -import org.junit.Test; - -import java.util.HashMap; -import java.util.Hashtable; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TreeMap; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -public class MPUtilityTest extends BaseCleanInstallEachTest { - - @Test - public void testInstantAppDetectionTest() { - assertFalse(MPUtility.isInstantApp(mContext)); - } - - @Test - public void testNullMapKey() throws Exception { - Map map = new HashMap(); - map.put("key1", "val1"); - map.put("key2", "val2"); - assertFalse(MPUtility.containsNullKey(map)); - map.put(null, "val3"); - assertTrue(MPUtility.containsNullKey(map)); - - map = new Hashtable(); - map.put("key1", "val1"); - map.put("key2", "val2"); - assertFalse(MPUtility.containsNullKey(map)); - - map = new TreeMap(map); - assertFalse(MPUtility.containsNullKey(map)); - - map = new LinkedHashMap(map); - assertFalse(MPUtility.containsNullKey(map)); - } - - @Test - public void testGetInstrumentedNetworkType() throws Exception { - TelephonyManager manager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - Integer result = MPUtility.getNetworkType(mContext, manager); - assertNull(result); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/MPUtilityTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/MPUtilityTest.kt new file mode 100644 index 000000000..710545621 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/MPUtilityTest.kt @@ -0,0 +1,40 @@ +package com.mparticle.internal + +import android.telephony.TelephonyManager +import com.mparticle.testing.BaseTest +import com.mparticle.testing.context +class MPUtilityTest : BaseTest() { + @org.junit.Test + fun testInstantAppDetectionTest() { + org.junit.Assert.assertFalse(MPUtility.isInstantApp(context)) + } + + @org.junit.Test + @Throws(java.lang.Exception::class) + fun testNullMapKey() { + var map = mutableMapOf( + "key1" to "val1", + "key2" to "val2" + ) + org.junit.Assert.assertFalse(MPUtility.containsNullKey(map)) + map[null] = "val3" + org.junit.Assert.assertTrue(MPUtility.containsNullKey(map)) + map = mutableMapOf() + map["key1"] = "val1" + map["key2"] = "val2" + org.junit.Assert.assertFalse(MPUtility.containsNullKey(map)) + map = java.util.TreeMap(map) + org.junit.Assert.assertFalse(MPUtility.containsNullKey(map)) + map = java.util.LinkedHashMap(map) + org.junit.Assert.assertFalse(MPUtility.containsNullKey(map)) + } + + @org.junit.Test + @Throws(java.lang.Exception::class) + fun testGetInstrumentedNetworkType() { + val manager: TelephonyManager = + context.getSystemService(android.content.Context.TELEPHONY_SERVICE) as TelephonyManager + val result = MPUtility.getNetworkType(context, manager) + org.junit.Assert.assertNull(result) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/MParticleJSInterfaceITest.java b/android-core/src/androidTest/java/com/mparticle/internal/MParticleJSInterfaceITest.java deleted file mode 100644 index 815e26af5..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/MParticleJSInterfaceITest.java +++ /dev/null @@ -1,721 +0,0 @@ -package com.mparticle.internal; - -import android.annotation.TargetApi; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.rule.ActivityTestRule; -import android.util.MutableBoolean; -import android.webkit.CookieManager; -import android.webkit.JavascriptInterface; -import android.webkit.WebChromeClient; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import com.mparticle.BaseEvent; -import com.mparticle.MParticle; -import com.mparticle.WebViewActivity; -import com.mparticle.commerce.CommerceEvent; -import com.mparticle.commerce.Product; -import com.mparticle.commerce.TransactionAttributes; -import com.mparticle.identity.AccessUtils; -import com.mparticle.test.R; -import com.mparticle.testutils.AndroidUtils; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.BuildConfig; -import com.mparticle.testutils.MPLatch; -import com.mparticle.testutils.RandomUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Assume; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - -import static com.mparticle.testutils.TestingUtils.assertJsonEqual; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class MParticleJSInterfaceITest extends BaseCleanStartedEachTest { - - @Rule - public ActivityTestRule rule = new ActivityTestRule(WebViewActivity.class); - - private static String jsSdk; - private static boolean sdkFetchedSuccessfully = false; - private static String bridgeToken = new RandomUtils().getAlphaString(5); - private static String bridgeVersion = "2"; - - private static final String jsStartupMParticle = "window.mParticle = {\n" + - " config: {\n" + - " isDevelopmentMode: true,\n" + - " useCookieStorage: true,\n" + - " identifyRequest: {\n" + - " userIdentities: { email: 'email@example.com', customerid: '123456' }\n" + - " },\n " + - " requiredWebviewBridgeName: \"" + bridgeToken + "\",\n" + - " minWebviewBridgeVersion:\"" + bridgeVersion + "\"\n" + - " }\n" + - " };" + - " window.mParticle = window.mParticle || {};\n" + - " window.mParticle.config = window.mParticle.config || {};\n" + - " window.mParticle.config.rq = [];\n" + - " window.mParticle.ready = function (f) {\n" + - " window.mParticle.config.rq.push(f);\n" + - " console.log(\"pushed f\");\n" + - " };\n"; - - private static final String jsTestWrapper = - " mParticle.init();\n" + - " mParticle.isDebug = true;\n" + - " console.log(\"testing started\")\n " + - " window.mParticle.ready(function () {\n" + - " console.log(\"mparticle started in JS land\");\n" + - "%s\n" + - " })\n"; - - private static final String jsSetMpidFunction = "function getCookieDomain() {\n" + - " var rootDomain = getDomain(document, location.hostname);\n" + - " if (rootDomain === '') {\n" + - " return '';\n" + - " } else {\n" + - " return '.' + rootDomain;\n" + - " }\n" + - "}\n" + - "\n" + - "function getDomain(doc, locationHostname) {\n" + - " var i,\n" + - " testParts,\n" + - " mpTest = 'mptest=cookie',\n" + - " hostname = locationHostname.split('.');\n" + - " for (i = hostname.length - 1; i >= 0; i--) {\n" + - " testParts = hostname.slice(i).join('.');\n" + - " doc.cookie = mpTest + ';domain=.' + testParts + ';';\n" + - " if (doc.cookie.indexOf(mpTest) > -1){\n" + - " doc.cookie = mpTest.split('=')[0] + '=;domain=.' + testParts + ';expires=Thu, 01 Jan 1970 00:00:01 GMT;';\n" + - " return testParts;\n" + - " }\n" + - " }\n" + - " return '';\n" + - "}\n" + - "\n" + - "\n" + - "function setCookie(cname, data, raw) {\n" + - " var date = new Date(),\n" + - " expires = new Date(date.getTime() +\n" + - " (365 * 24 * 60 * 60 * 1000)).toGMTString(),\n" + - " domain, cookieDomain,\n" + - " value;\n" + - "\n" + - " value = data;\n" + - "\n" + - " cookieDomain = getCookieDomain();\n" + - "\n" + - " if (cookieDomain === '') {\n" + - " domain = '';\n" + - " } else {\n" + - " domain = ';domain=' + cookieDomain;\n" + - " }\n" + - "\n" + - "var cookie = encodeURIComponent(cname) + '=' + value +\n" + - " ';expires=' + expires;\n" + - " // +\n" + - " // ';path=/' + domain;\n" + - " console.log(\"SETTNG COOKIE: \" + cookie);\n" + - " window.document.cookie = cookie;\n" + - " console.log(\"RETRIEVING cookie: \" + window.document.cookie);\n" + - "}"; - - private static final String htmlWrapper = "\n" + - "\n" + - "\n" + - " \n" + - " Mocha Tests\n" + - "\n" + - "\n" + - "
\n" + - "" + - "\n" + - ""; - - @BeforeClass - public static void beforeClass() { - try { - if (BuildConfig.JS_TEST_SDK) { - InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(R.raw.mparticle_js_sdk); - //add in all the basic configuration stuff the server would send with a production sdk fetch from the url - jsSdk = new StringBuilder() - .append("window.mParticle = window.mParticle || {};;\n" + - "window.mParticle.config = window.mParticle.config || {};;\n" + - "window.mParticle.config.serviceUrl = 'jssdk.mparticle.com/v2/JS/';;\n" + - "window.mParticle.config.secureServiceUrl = 'jssdks.mparticle.com/v2/JS/';;\n" + - "window.mParticle.config.minWebviewBridgeVersion = 1;\n" + - "window.mParticle.config.aliasMaxWindow = 90;\n" + - "window.mParticle.config.kitConfigs = window.mParticle.config.kitConfigs || [];;\n" + - "window.mParticle.config.pixelConfigs = window.mParticle.config.pixelConfigs || [];;") - .append(toString(inputStream)) - .append("window.mParticle.config.requestConfig = false;;\n" + - "mParticle.init(null, window.mParticle.config);;") - .toString(); - } else { - URLConnection connection = new URL("https://jssdkcdns.mparticle.com/js/v2/mparticle.js").openConnection(); - jsSdk = toString(connection.getInputStream()); - } - sdkFetchedSuccessfully = true; - } catch (Exception ex) { - sdkFetchedSuccessfully = false; - } - if (sdkFetchedSuccessfully) { - jsSdk = jsSdk.replace("jssdk.mparticle.com/v2/JS/", "http://localhost:8080/v2")//; console.log(\"replaced url V2 single\");") - .replace("jssdks.mparticle.com/v2/JS/", "http://localhost:8080/v2")//; console.log(\"replaced url V2 plural\");") - .replace("jssdks.mparticle.com/v1/JS/", "http://localhost:8080/v1")//; console.log(\"replaced url V1 plural\");") - .replace("jssdk.mparticle.com/v1/JS/", "http://localhost:8080/v1")//; console.log(\"replaced url V1 single\");") - .replace("https://identity.mparticle.com/v1/", "http://localhost:8080/v1/")//; console.log(\"replaced url Identity\");") - .replace("// jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license", "console.log(\"starting sdk\")") - .replace("window.mParticle.config.minWebviewBridgeVersion = 1", "window.mParticle.config.minWebviewBridgeVersion = " + bridgeVersion); - } - } - - @Before - public void before() { - Assume.assumeTrue(sdkFetchedSuccessfully); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - WebView.setWebContentsDebuggingEnabled(true); - } - }); - } - } - - @Test - public void testSetUserAttribute() throws Exception { - final String key = mRandomUtils.getAlphaNumericString(25); - final String value = mRandomUtils.getAlphaNumericString(25); - String testJavascript = String.format("mParticle.Identity.getCurrentUser().setUserAttribute(\"%s\", \"%s\");\n", key, value); - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface(){ - @Override - @JavascriptInterface - public void setUserAttribute(String json) { - super.setUserAttribute(json); - try { - JSONObject jsonObject = new JSONObject(json); - assertEquals(key, jsonObject.getString("key")); - assertEquals(value, jsonObject.getString("value")); - called.value = true; - latch.countDown(); - } - catch (JSONException jse) { - jse.printStackTrace(); - } - - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testRemoveUserAttribute() throws Exception { - final String key = mRandomUtils.getAlphaNumericString(20); - String testJavascript = String.format("mParticle.Identity.getCurrentUser().removeUserAttribute(\"%s\");\n", key); - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface(){ - @Override - @JavascriptInterface - public void removeUserAttribute(String json) { - super.removeUserAttribute(json); - try { - JSONObject jsonObject = new JSONObject(json); - assertEquals(key, jsonObject.getString("key")); - called.value = true; - latch.countDown(); - } - catch (JSONException jse) { - jse.printStackTrace(); - } - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testSetUserTag() throws Exception { - final String tag = mRandomUtils.getAlphaNumericString(25); - String testJavascript = String.format("mParticle.Identity.getCurrentUser().setUserTag(\"%s\");\n", tag); - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - //This is acceptable if the JS SDK calls either setUserTag, or setUserAttribute with a null value - runJavascriptTest(testJavascript, new MParticleJSInterface(){ - @Override - @JavascriptInterface - public void setUserTag(String json) { - super.setUserTag(json); - try { - JSONObject jsonObject = new JSONObject(json); - assertEquals(tag, jsonObject.getString("key")); - called.value = true; - latch.countDown(); - } - catch (JSONException jse) { - jse.printStackTrace(); - } - } - - @Override - @JavascriptInterface - public void setUserAttribute(String json) { - super.setUserAttribute(json); - try { - JSONObject jsonObject = new JSONObject(json); - assertEquals(tag, jsonObject.getString("key")); - assertEquals(jsonObject.optString("value", "null"), "null"); - called.value = true; - latch.countDown(); - } - catch (JSONException jse) { - jse.printStackTrace(); - } - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLogEvent() throws Exception { - final JSONObject customAttributes = MPUtility.mapToJson( mRandomUtils.getRandomAttributes(10)); - final JSONObject customFlagsJSON = MPUtility.mapToJson(getCustomFlags()); - String testJavascript = String.format("mParticle.logEvent('Play Movie Tapped',\n" + - " mParticle.EventType.Navigation,\n" + - " %s,\n" + - " %s);", customAttributes.toString(4), customFlagsJSON.toString(4)); - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(2); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - - @Override - protected void logEvent(BaseEvent event) { - Map> customFlags = event.getCustomFlags(); - assertEquals(3, customFlags.size()); - assertTrue(customFlags.containsKey("foo")); - assertTrue(customFlags.containsKey("bar")); - assertTrue(customFlags.containsKey("baz")); - List fooFlags = customFlags.get("foo"); - List barFlags = customFlags.get("bar"); - List bazFlags = customFlags.get("baz"); - assertEquals(3, fooFlags.size()); - assertTrue(fooFlags.contains("50")); - assertTrue(fooFlags.contains("true")); - assertTrue(fooFlags.contains("-27")); - assertEquals(2, barFlags.size()); - assertEquals(1, bazFlags.size()); - latch.countDown(); - } - - @Override - @JavascriptInterface - public void logEvent(String json) { - super.logEvent(json); - try { - JSONObject jsonObject = new JSONObject(json); - //make sure we are receiving the expected event from JS world - if (jsonObject.getInt(JS_KEY_EVENT_DATATYPE) == JS_MSG_TYPE_PE) { - assertEquals(jsonObject.getInt(JS_KEY_EVENT_CATEGORY), MParticle.EventType.Navigation.ordinal()); - JSONObject receivedCustomAttributes = jsonObject.getJSONObject(JS_KEY_EVENT_ATTRIBUTES); - JSONObject receivedCustomFlags = jsonObject.getJSONObject(JS_KEY_EVENT_FLAGS); - assertJsonEqual(customAttributes, receivedCustomAttributes); - assertJsonEqual(customFlagsJSON, receivedCustomFlags); - called.value = true; - latch.countDown(); - } - Logger.error(new JSONObject(json).toString(4)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLogCommerceEvent() throws Exception { - final JSONObject customAttributes = MPUtility.mapToJson( mRandomUtils.getRandomAttributes(10)); - final JSONObject customFlags = MPUtility.mapToJson(getCustomFlags()); - String testJavascript = String.format("// 1. Create the product\n" + - "var product = mParticle.eCommerce.createProduct(\n" + - " 'Double Room - Econ Rate', //\n" + - " 'econ-1', \n" + - " 100.00, \n" + - " 4\n" + - ");\n" + - "\n" + - "// 2. Summarize the transaction\n" + - "var transactionAttributes = {\n" + - " Id: 'foo-transaction-id',\n" + - " Revenue: 430.00,\n" + - " Tax: 30\n" + - "};\n" + - "\n" + - "// 3. Log the purchase event\n" + - "mParticle.eCommerce.logPurchase(transactionAttributes, product, true, %s, %s);", customAttributes.toString(4), customFlags); - - final MutableBoolean called = new MutableBoolean(false); - final AndroidUtils.Mutable error = new AndroidUtils.Mutable(null); - final CountDownLatch latch = new MPLatch(2); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - - @Override - protected void logEvent(BaseEvent event) { - Map> customFlags = event.getCustomFlags(); - assertEquals(3, customFlags.size()); - assertTrue(customFlags.containsKey("foo")); - assertTrue(customFlags.containsKey("bar")); - assertTrue(customFlags.containsKey("baz")); - List fooFlags = customFlags.get("foo"); - List barFlags = customFlags.get("bar"); - List bazFlags = customFlags.get("baz"); - assertEquals(3, fooFlags.size()); - assertTrue(fooFlags.contains("50")); - assertTrue(fooFlags.contains("true")); - assertTrue(fooFlags.contains("-27")); - assertEquals(2, barFlags.size()); - assertEquals(1, bazFlags.size()); - latch.countDown(); - } - - @Override - @JavascriptInterface - public void logEvent(String json) { - super.logEvent(json); - try { - CommerceEvent commerceEvent = toCommerceEvent(new JSONObject(json)); - assertEquals(1, commerceEvent.getProducts().size()); - assertEquals(Product.PURCHASE, commerceEvent.getProductAction()); - assertNull(commerceEvent.getCurrency()); - Product product = commerceEvent.getProducts().get(0); - assertEquals("Double Room - Econ Rate", product.getName()); - assertEquals("econ-1", product.getSku()); - assertEquals(100.0, product.getUnitPrice(), .1); - assertEquals(4.0, product.getQuantity(), .1); - TransactionAttributes transactionAttributes = commerceEvent.getTransactionAttributes(); - assertEquals("foo-transaction-id", transactionAttributes.getId()); - assertEquals(430.0, transactionAttributes.getRevenue(), .1); - assertEquals(30.0, transactionAttributes.getTax(), .1); - assertNull(transactionAttributes.getShipping()); - assertNull(transactionAttributes.getAffiliation()); - assertNull(transactionAttributes.getCouponCode()); - assertJsonEqual(customAttributes, MPUtility.mapToJson(commerceEvent.getCustomAttributeStrings())); - called.value = true; - } catch (Exception e) { - error.value = e; - } catch (AssertionError e) { - error.value = e; - } - latch.countDown(); - } - }); - assertNull(error.value); - latch.await(); - assertTrue(called.value); - } - - - @Test - public void testLogout() throws Exception { - final Map userIdentityMap = mRandomUtils.getRandomUserIdentities(); - JSONObject jsonObject = userIdentityMapToJson(userIdentityMap); - String testJavascript = String.format("mParticle.Identity.logout(%s , null);", jsonObject.toString(4)); - - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - @Override - @JavascriptInterface - public void logout(String json) { - super.logout(json); - try { - assertJsonEqual(new JSONObject(json), userIdentityMapToJsonJsSdkStyle(userIdentityMap)); - called.value = true; - latch.countDown(); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLogoutEmpty() throws Exception { - String testJavascript = "mParticle.Identity.logout();"; - - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - @Override - @JavascriptInterface - public void logout(String json) { - if (json == null || json.equals("undefined")) { - logout(); - } - } - - @Override - @JavascriptInterface - public void logout() { - called.value = true; - latch.countDown(); - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLogin() throws Exception { - final Map userIdentityMap = mRandomUtils.getRandomUserIdentities(); - JSONObject jsonObject = userIdentityMapToJson(userIdentityMap); - String testJavascript = String.format("mParticle.Identity.login(%s , null);", jsonObject.toString(4)); - - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - @Override - @JavascriptInterface - public void login(String json) { - super.login(json); - try { - assertJsonEqual(new JSONObject(json), userIdentityMapToJsonJsSdkStyle(userIdentityMap)); - called.value = true; - latch.countDown(); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testLoginEmpty() throws Exception { - String testJavascript = "mParticle.Identity.login();"; - - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - @Override - @JavascriptInterface - public void login(String json) { - if (json == null || json.equals("undefined")) { - login(); - } - } - - @Override - @JavascriptInterface - public void login() { - called.value = true; - latch.countDown(); - } - }); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testModify() throws Exception { - final Map userIdentities = mRandomUtils.getRandomUserIdentities(); - JSONObject jsonObject = userIdentityMapToJson(userIdentities); - String testJavascript = String.format("mParticle.Identity.modify(%s , null);", jsonObject.toString(4)); - - final MutableBoolean called = new MutableBoolean(false); - final CountDownLatch latch = new MPLatch(1); - runJavascriptTest(testJavascript, new MParticleJSInterface() { - @Override - @JavascriptInterface - public void modify(String json) { - super.modify(json); - try { - assertJsonEqual(new JSONObject(json), userIdentityMapToJsonJsSdkStyle(userIdentities)); - called.value = true; - latch.countDown(); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }); - latch.await(); - assertTrue(called.value); - } - - private String getJavascriptWrappedinHtml(String testJavascript) { - StringBuilder javascriptBuilder = new StringBuilder() - .append(jsSetMpidFunction) - .append("\n") - .append(setMpidJavascript(mStartingMpid)) - .append("\n") - .append(jsStartupMParticle) - .append("\n") - .append(jsSdk) - .append("\n") - .append(String.format(jsTestWrapper, testJavascript)); - return String.format(htmlWrapper, javascriptBuilder.toString()); - } - - private void runJavascriptTest(final String testJavascript, final MParticleJSInterface jsInterface) { - new Handler(Looper.getMainLooper()).post( - new Runnable() { - @Override - public void run() { - CookieManager cookieManager = CookieManager.getInstance(); - cookieManager.setAcceptCookie(true); - WebView wv = rule.getActivity().findViewById(R.id.web_view); - wv.setWebViewClient(new WebViewClient() { - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { - //Overriding the method and allowing Options response essentially - //disables CORS, which will allow us to point network requests at our - //local server - if (request.getMethod().equalsIgnoreCase("OPTIONS")) { - return OptionsAllowResponse.build(); - } - - return null; - } - }); - cookieManager.setAcceptThirdPartyCookies(wv, true); - wv.getSettings().setDomStorageEnabled(true); - wv.getSettings().setJavaScriptEnabled(true); - String bridgeName = MParticleJSInterface.getBridgeName(bridgeToken); - wv.removeJavascriptInterface(bridgeName); - wv.addJavascriptInterface(jsInterface, bridgeName); - wv.setWebChromeClient(new WebChromeClient() { - public void onConsoleMessage(String message, int lineNumber, String sourceID) { - Logger.warning("MParticle JS sdk", message + " -- From line " - + lineNumber); - } - }); - - String jsString = getJavascriptWrappedinHtml(testJavascript); - Logger.error(jsString); - wv.loadDataWithBaseURL("http://localhost/", - jsString, - "text/html", "utf-8", - null); - } - }); - } - - private String setMpidJavascript(long mpid) { - String cookies = String.format("{'gs':{'ie':1|'dt':'test_key'|'cgid':'886e874b-862b-4822-a24a-1146cd057101'|'das':'62c91b8d-fef6-44ea-b2cc-b55714b0d827'|'csm':'WyJ0ZXN0TVBJRCJd'|'sid':'2535f9ed-ab19-4a7c-9eeb-ce4e41e0cb06'|'les':1518536950918|'ssd':1518536950916}|'%s':{'ui':'eyIxIjoiY3VzdG9tZXJpZDEifQ=='}|'cu':'%s'}" - , String.valueOf(mpid) - , String.valueOf(mpid)); - return String.format("setCookie('mprtcl-v4', \"%s\");", cookies, cookies); - } - - private JSONObject userIdentityMapToJson(Map userIdentities) throws JSONException { - JSONObject userIdentityJson = new JSONObject(); - for (Map.Entry entry : userIdentities.entrySet()) { - userIdentityJson.put(AccessUtils.getIdentityTypeString(entry.getKey()), entry.getValue()); - } - return new JSONObject() - .put("userIdentities", userIdentityJson); - } - - private JSONObject userIdentityMapToJsonJsSdkStyle(Map userIdentities) throws JSONException { - JSONArray userIdentityJson = new JSONArray(); - for (Map.Entry entry : userIdentities.entrySet()) { - userIdentityJson.put(new JSONObject() - .put("Type", entry.getKey().getValue()) - .put("Identity", entry.getValue())); - } - return new JSONObject() - .put("UserIdentities", userIdentityJson); - } - - private Map getCustomFlags() { - final HashMap customFlags = new HashMap(); - List fooFlags = new ArrayList(); - fooFlags.add(50); - fooFlags.add(true); - fooFlags.add(-27); - List barFlags = new ArrayList(); - barFlags.add("this other"); - barFlags.add("that other"); - customFlags.put("foo", fooFlags); - customFlags.put("bar", barFlags); - customFlags.put("baz", "foobar"); - customFlags.put("nullval", null); - return customFlags; - } - - private static String toString(InputStream inputStream) throws IOException { - BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); - StringBuilder document = new StringBuilder(); - String line; - while ((line = in.readLine()) != null) { - document.append(line + '\n'); - } - in.close(); - return document.toString(); - } - - static class OptionsAllowResponse { - static final SimpleDateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy kk:mm:ss", Locale.US); - - @TargetApi(21) - static WebResourceResponse build() { - Date date = new Date(); - final String dateString = formatter.format(date); - - Map headers = new HashMap() {{ - put("Connection", "close"); - put("Content-Type", "text/plain"); - put("Date", dateString + " GMT"); - put("Access-Control-Allow-Origin", "*"); - put("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS"); - put("Access-Control-Max-Age", "600"); - put("Access-Control-Allow-Credentials", "true"); - put("Access-Control-Allow-Headers", "accept, authorization, Content-Type, x-mp-key"); - put("Via", "1.1 vegur"); - }}; - - return new WebResourceResponse("text/plain", "UTF-8", 200, "OK", headers, null); - } - } -} - - diff --git a/android-core/src/androidTest/java/com/mparticle/internal/MParticleJSInterfaceITest.kt b/android-core/src/androidTest/java/com/mparticle/internal/MParticleJSInterfaceITest.kt new file mode 100644 index 000000000..752d71c9f --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/MParticleJSInterfaceITest.kt @@ -0,0 +1,816 @@ +package com.mparticle.internal + +import android.annotation.TargetApi +import android.app.Activity +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.util.MutableBoolean +import android.webkit.CookieManager +import android.webkit.JavascriptInterface +import android.webkit.WebChromeClient +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.platform.app.InstrumentationRegistry +import com.mparticle.BaseEvent +import com.mparticle.BuildConfig +import com.mparticle.MParticle +import com.mparticle.api.identity.toIdentityType +import com.mparticle.commerce.Product +import com.mparticle.identity.AccessUtils +import com.mparticle.test.R +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.Utils.assertJsonEqual +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Assume +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStream +import java.io.InputStreamReader +import java.net.URL +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.concurrent.CountDownLatch + +class MParticleJSInterfaceITest : BaseStartedTest() { + @Rule + @JvmField + var rule: ActivityScenarioRule = ActivityScenarioRule( + WebViewActivity::class.java + ) + + @Before + fun before() { + Assume.assumeTrue(sdkFetchedSuccessfully) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + Handler(Looper.getMainLooper()).post( + Runnable { + WebView.setWebContentsDebuggingEnabled( + true + ) + } + ) + } + } + + @Test + @Throws(Exception::class) + fun testSetUserAttribute() { + val key: String = RandomUtils.getAlphaNumericString(25) + val value: String = RandomUtils.getAlphaNumericString(25) + val testJavascript = String.format( + "mParticle.Identity.getCurrentUser().setUserAttribute(\"%s\", \"%s\");\n", + key, + value + ) + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun setUserAttribute(json: String) { + super.setUserAttribute(json) + try { + val jsonObject = JSONObject(json) + Assert.assertEquals(key, jsonObject.getString("key")) + Assert.assertEquals(value, jsonObject.getString("value")) + called.value = true + latch.countDown() + } catch (jse: JSONException) { + jse.printStackTrace() + } + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testRemoveUserAttribute() { + val key: String = RandomUtils.getAlphaNumericString(20) + val testJavascript = + String.format("mParticle.Identity.getCurrentUser().removeUserAttribute(\"%s\");\n", key) + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun removeUserAttribute(json: String) { + super.removeUserAttribute(json) + try { + val jsonObject = JSONObject(json) + Assert.assertEquals(key, jsonObject.getString("key")) + called.value = true + latch.countDown() + } catch (jse: JSONException) { + jse.printStackTrace() + } + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testSetUserTag() { + val tag: String = RandomUtils.getAlphaNumericString(25) + val testJavascript = + String.format("mParticle.Identity.getCurrentUser().setUserTag(\"%s\");\n", tag) + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + // This is acceptable if the JS SDK calls either setUserTag, or setUserAttribute with a null value + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun setUserTag(json: String) { + super.setUserTag(json) + try { + val jsonObject = JSONObject(json) + Assert.assertEquals(tag, jsonObject.getString("key")) + called.value = true + latch.countDown() + } catch (jse: JSONException) { + jse.printStackTrace() + } + } + + @JavascriptInterface + override fun setUserAttribute(json: String) { + super.setUserAttribute(json) + try { + val jsonObject = JSONObject(json) + Assert.assertEquals(tag, jsonObject.getString("key")) + Assert.assertEquals(jsonObject.optString("value", "null"), "null") + called.value = true + latch.countDown() + } catch (jse: JSONException) { + jse.printStackTrace() + } + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testLogEvent() { + val customAttributes = MPUtility.mapToJson(RandomUtils.getRandomAttributes(10)) + val customFlagsJSON = MPUtility.mapToJson(customFlags) + val testJavascript = String.format( + """mParticle.logEvent('Play Movie Tapped', + mParticle.EventType.Navigation, + %s, + %s);""", + customAttributes.toString(4), customFlagsJSON.toString(4) + ) + var count = 0 + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + override fun logEvent(event: BaseEvent) { + val customFlags = event.customFlags + Assert.assertEquals(3, customFlags!!.size.toLong()) + Assert.assertTrue(customFlags.containsKey("foo")) + Assert.assertTrue(customFlags.containsKey("bar")) + Assert.assertTrue(customFlags.containsKey("baz")) + val fooFlags = customFlags["foo"]!! + val barFlags = customFlags["bar"]!! + val bazFlags = customFlags["baz"]!! + Assert.assertEquals(3, fooFlags.size.toLong()) + Assert.assertTrue(fooFlags.contains("50")) + Assert.assertTrue(fooFlags.contains("true")) + Assert.assertTrue(fooFlags.contains("-27")) + Assert.assertEquals(2, barFlags.size.toLong()) + Assert.assertEquals(1, bazFlags.size.toLong()) + count++ + if (count == 2) { + latch.countDown() + } + } + + @JavascriptInterface + override fun logEvent(json: String) { + super.logEvent(json) + try { + val jsonObject = JSONObject(json) + // make sure we are receiving the expected event from JS world + if (jsonObject.getInt(JS_KEY_EVENT_DATATYPE) == JS_MSG_TYPE_PE) { + Assert.assertEquals( + jsonObject.getInt(JS_KEY_EVENT_CATEGORY).toLong(), + MParticle.EventType.Navigation.ordinal.toLong() + ) + val receivedCustomAttributes = jsonObject.getJSONObject( + JS_KEY_EVENT_ATTRIBUTES + ) + val receivedCustomFlags = jsonObject.getJSONObject(JS_KEY_EVENT_FLAGS) + assertJsonEqual(customAttributes, receivedCustomAttributes) + assertJsonEqual(customFlagsJSON, receivedCustomFlags) + count++ + if (count == 2) { + latch.countDown() + } + } + Logger.error(JSONObject(json).toString(4)) + } catch (e: JSONException) { + e.printStackTrace() + } + } + } + ) + latch.await() + } + + @Test + @Throws(Exception::class) + fun testLogCommerceEvent() { + val customAttributes = MPUtility.mapToJson(RandomUtils.getRandomAttributes(10)) + val customFlags = MPUtility.mapToJson(customFlags) + val testJavascript = String.format( + """// 1. Create the product +var product = mParticle.eCommerce.createProduct( + 'Double Room - Econ Rate', // + 'econ-1', + 100.00, + 4 +); + +// 2. Summarize the transaction +var transactionAttributes = { + Id: 'foo-transaction-id', + Revenue: 430.00, + Tax: 30 +}; + +// 3. Log the purchase event +mParticle.eCommerce.logPurchase(transactionAttributes, product, true, %s, %s);""", + customAttributes.toString(4), + customFlags + ) + val called = MutableBoolean(false) + val error = Mutable(null) + val latch: CountDownLatch = FailureLatch(count = 2) + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + override fun logEvent(event: BaseEvent) { + val customFlags = event.customFlags + Assert.assertEquals(3, customFlags!!.size.toLong()) + Assert.assertTrue(customFlags.containsKey("foo")) + Assert.assertTrue(customFlags.containsKey("bar")) + Assert.assertTrue(customFlags.containsKey("baz")) + val fooFlags = customFlags["foo"]!! + val barFlags = customFlags["bar"]!! + val bazFlags = customFlags["baz"]!! + Assert.assertEquals(3, fooFlags.size.toLong()) + Assert.assertTrue(fooFlags.contains("50")) + Assert.assertTrue(fooFlags.contains("true")) + Assert.assertTrue(fooFlags.contains("-27")) + Assert.assertEquals(2, barFlags.size.toLong()) + Assert.assertEquals(1, bazFlags.size.toLong()) + latch.countDown() + } + + @JavascriptInterface + override fun logEvent(json: String) { + super.logEvent(json) + try { + val commerceEvent = toCommerceEvent(JSONObject(json)) + Assert.assertEquals(1, commerceEvent.products!!.size.toLong()) + Assert.assertEquals(Product.PURCHASE, commerceEvent.productAction) + Assert.assertNull(commerceEvent.currency) + val product = commerceEvent.products!![0] + Assert.assertEquals("Double Room - Econ Rate", product.name) + Assert.assertEquals("econ-1", product.sku) + Assert.assertEquals(100.0, product.unitPrice, .1) + Assert.assertEquals(4.0, product.quantity, .1) + val transactionAttributes = commerceEvent.transactionAttributes + Assert.assertEquals("foo-transaction-id", transactionAttributes!!.id) + Assert.assertEquals(430.0, transactionAttributes.revenue!!, .1) + Assert.assertEquals(30.0, transactionAttributes.tax!!, .1) + Assert.assertNull(transactionAttributes.shipping) + Assert.assertNull(transactionAttributes.affiliation) + Assert.assertNull(transactionAttributes.couponCode) + assertJsonEqual( + customAttributes, + MPUtility.mapToJson(commerceEvent.customAttributes) + ) + called.value = true + } catch (e: Exception) { + error.value = e + } catch (e: AssertionError) { + error.value = e + } + latch.countDown() + } + } + ) + Assert.assertNull(error.value) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testLogout() { + val userIdentityMap: Map = + RandomUtils.getRandomUserIdentities().entries.associate { it.key.toIdentityType() to it.value } + val jsonObject = userIdentityMapToJson(userIdentityMap) + val testJavascript = + String.format("mParticle.Identity.logout(%s , null);", jsonObject.toString(4)) + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun logout(json: String) { + super.logout(json) + try { + assertJsonEqual( + JSONObject(json), + userIdentityMapToJsonJsSdkStyle(userIdentityMap) + ) + called.value = true + latch.countDown() + } catch (e: JSONException) { + e.printStackTrace() + } + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testLogoutEmpty() { + val testJavascript = "mParticle.Identity.logout();" + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun logout(json: String) { + if (json == null || json == "undefined") { + logout() + } + } + + @JavascriptInterface + override fun logout() { + called.value = true + latch.countDown() + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testLogin() { + val userIdentityMap: Map = + RandomUtils.getRandomUserIdentities().entries.associate { it.key.toIdentityType() to it.value } + val jsonObject = userIdentityMapToJson(userIdentityMap) + val testJavascript = + String.format("mParticle.Identity.login(%s , null);", jsonObject.toString(4)) + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun login(json: String) { + super.login(json) + try { + assertJsonEqual( + JSONObject(json), + userIdentityMapToJsonJsSdkStyle(userIdentityMap) + ) + called.value = true + latch.countDown() + } catch (e: JSONException) { + e.printStackTrace() + } + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testLoginEmpty() { + val testJavascript = "mParticle.Identity.login();" + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun login(json: String) { + if (json == null || json == "undefined") { + login() + } + } + + @JavascriptInterface + override fun login() { + called.value = true + latch.countDown() + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testModify() { + val userIdentities: Map = + RandomUtils.getRandomUserIdentities().entries.associate { it.key.toIdentityType() to it.value } + val jsonObject = userIdentityMapToJson(userIdentities) + val testJavascript = + String.format("mParticle.Identity.modify(%s , null);", jsonObject.toString(4)) + val called = MutableBoolean(false) + val latch: CountDownLatch = FailureLatch() + runJavascriptTest( + testJavascript, + object : MParticleJSInterface() { + @JavascriptInterface + override fun modify(json: String) { + super.modify(json) + try { + assertJsonEqual( + JSONObject(json), + userIdentityMapToJsonJsSdkStyle(userIdentities) + ) + called.value = true + latch.countDown() + } catch (e: JSONException) { + e.printStackTrace() + } + } + } + ) + latch.await() + Assert.assertTrue(called.value) + } + + private fun getJavascriptWrappedinHtml(testJavascript: String): String { + val javascriptBuilder = StringBuilder() + .append(jsSetMpidFunction) + .append("\n") + .append(setMpidJavascript(mStartingMpid)) + .append("\n") + .append(jsStartupMParticle) + .append("\n") + .append(jsSdk) + .append("\n") + .append(String.format(jsTestWrapper, testJavascript)) + return String.format(htmlWrapper, javascriptBuilder.toString()) + } + + private fun runJavascriptTest(testJavascript: String, jsInterface: MParticleJSInterface) { + Handler(Looper.getMainLooper()).post( + Runnable { + val cookieManager = CookieManager.getInstance() + cookieManager.setAcceptCookie(true) + rule.scenario.onActivity { + it.findViewById(R.id.web_view).let { wv -> + wv.setWebViewClient(object : WebViewClient() { + override fun shouldInterceptRequest( + view: WebView, + request: WebResourceRequest + ): WebResourceResponse? { + // Overriding the method and allowing Options response essentially + // disables CORS, which will allow us to point network requests at our + // local server + return if (request.getMethod() + .equals("OPTIONS", ignoreCase = true) + ) { + OptionsAllowResponse.build() + } else null + } + }) + cookieManager.setAcceptThirdPartyCookies(wv, true) + wv.getSettings().setDomStorageEnabled(true) + wv.getSettings().setJavaScriptEnabled(true) + val bridgeName = MParticleJSInterface.getBridgeName(bridgeToken) + wv.removeJavascriptInterface(bridgeName) + wv.addJavascriptInterface(jsInterface, bridgeName) + wv.setWebChromeClient(object : WebChromeClient() { + override fun onConsoleMessage( + message: String, + lineNumber: Int, + sourceID: String + ) { + Logger.warning( + "MParticle JS sdk", + message + " -- From line " + + lineNumber + ) + } + }) + val jsString = getJavascriptWrappedinHtml(testJavascript) + Logger.error(jsString) + wv.loadDataWithBaseURL( + "http://localhost/", + jsString, + "text/html", "utf-8", + null + ) + } + } + } + ) + } + + private fun setMpidJavascript(mpid: Long): String { + val cookies = String.format( + "{'gs':{'ie':1|'dt':'test_key'|'cgid':'886e874b-862b-4822-a24a-1146cd057101'|'das':'62c91b8d-fef6-44ea-b2cc-b55714b0d827'|'csm':'WyJ0ZXN0TVBJRCJd'|'sid':'2535f9ed-ab19-4a7c-9eeb-ce4e41e0cb06'|'les':1518536950918|'ssd':1518536950916}|'%s':{'ui':'eyIxIjoiY3VzdG9tZXJpZDEifQ=='}|'cu':'%s'}", + mpid.toString(), + mpid.toString() + ) + return String.format("setCookie('mprtcl-v4', \"%s\");", cookies, cookies) + } + + @Throws(JSONException::class) + private fun userIdentityMapToJson(userIdentities: Map): JSONObject { + val userIdentityJson = JSONObject() + for ((key, value) in userIdentities) { + userIdentityJson.put(AccessUtils.getIdentityTypeString(key), value) + } + return JSONObject() + .put("userIdentities", userIdentityJson) + } + + @Throws(JSONException::class) + private fun userIdentityMapToJsonJsSdkStyle(userIdentities: Map): JSONObject { + val userIdentityJson = JSONArray() + for ((key, value) in userIdentities) { + userIdentityJson.put( + JSONObject() + .put("Type", key.value) + .put("Identity", value) + ) + } + return JSONObject() + .put("UserIdentities", userIdentityJson) + } + + private val customFlags: Map + private get() { + val fooFlags = mutableListOf(50, true, -27) + val barFlags = mutableListOf("this other", "that other") + return mutableMapOf( + "foo" to fooFlags, + "bar" to barFlags, + "baz" to "foobar", + "nullval" to null + ) + } + + internal object OptionsAllowResponse { + val formatter = SimpleDateFormat("E, dd MMM yyyy kk:mm:ss", Locale.US) + @TargetApi(21) + fun build(): WebResourceResponse { + val date = Date() + val dateString = formatter.format(date) + val headers: Map = mutableMapOf( + "Connection" to "close", + "Content-Type" to "text/plain", + "Date" to "$dateString GMT", + "Access-Control-Allow-Origin" to "*", + "Access-Control-Allow-Methods" to "GET, POST, DELETE, PUT, OPTIONS", + "Access-Control-Max-Age" to "600", + "Access-Control-Allow-Credentials" to "true", + "Access-Control-Allow-Headers" to "accept, authorization, Content-Type, x-mp-key", + "Via" to "1.1 vegur" + ) + + return WebResourceResponse("text/plain", "UTF-8", 200, "OK", headers, null) + } + } + + companion object { + private var jsSdk: String? = null + private var sdkFetchedSuccessfully = false + private val bridgeToken: String = RandomUtils.getAlphaString(5) + private const val bridgeVersion = "2" + private val jsStartupMParticle = """window.mParticle = { + config: { + isDevelopmentMode: true, + useCookieStorage: true, + identifyRequest: { + userIdentities: { email: 'email@example.com', customerid: '123456' } + }, + requiredWebviewBridgeName: "$bridgeToken", + minWebviewBridgeVersion:"$bridgeVersion" + } + }; window.mParticle = window.mParticle || {}; + window.mParticle.config = window.mParticle.config || {}; + window.mParticle.config.rq = []; + window.mParticle.ready = function (f) { + window.mParticle.config.rq.push(f); + console.log("pushed f"); + }; +""" + private const val jsTestWrapper = " mParticle.init();\n" + + " mParticle.isDebug = true;\n" + + " console.log(\"testing started\")\n " + + " window.mParticle.ready(function () {\n" + + " console.log(\"mparticle started in JS land\");\n" + + "%s\n" + + " })\n" + private const val jsSetMpidFunction = "function getCookieDomain() {\n" + + " var rootDomain = getDomain(document, location.hostname);\n" + + " if (rootDomain === '') {\n" + + " return '';\n" + + " } else {\n" + + " return '.' + rootDomain;\n" + + " }\n" + + "}\n" + + "\n" + + "function getDomain(doc, locationHostname) {\n" + + " var i,\n" + + " testParts,\n" + + " mpTest = 'mptest=cookie',\n" + + " hostname = locationHostname.split('.');\n" + + " for (i = hostname.length - 1; i >= 0; i--) {\n" + + " testParts = hostname.slice(i).join('.');\n" + + " doc.cookie = mpTest + ';domain=.' + testParts + ';';\n" + + " if (doc.cookie.indexOf(mpTest) > -1){\n" + + " doc.cookie = mpTest.split('=')[0] + '=;domain=.' + testParts + ';expires=Thu, 01 Jan 1970 00:00:01 GMT;';\n" + + " return testParts;\n" + + " }\n" + + " }\n" + + " return '';\n" + + "}\n" + + "\n" + + "\n" + + "function setCookie(cname, data, raw) {\n" + + " var date = new Date(),\n" + + " expires = new Date(date.getTime() +\n" + + " (365 * 24 * 60 * 60 * 1000)).toGMTString(),\n" + + " domain, cookieDomain,\n" + + " value;\n" + + "\n" + + " value = data;\n" + + "\n" + + " cookieDomain = getCookieDomain();\n" + + "\n" + + " if (cookieDomain === '') {\n" + + " domain = '';\n" + + " } else {\n" + + " domain = ';domain=' + cookieDomain;\n" + + " }\n" + + "\n" + + "var cookie = encodeURIComponent(cname) + '=' + value +\n" + + " ';expires=' + expires;\n" + + " // +\n" + + " // ';path=/' + domain;\n" + + " console.log(\"SETTNG COOKIE: \" + cookie);\n" + + " window.document.cookie = cookie;\n" + + " console.log(\"RETRIEVING cookie: \" + window.document.cookie);\n" + + "}" + private const val htmlWrapper = "\n" + + "\n" + + "\n" + + " \n" + + " Mocha Tests\n" + + "\n" + + "\n" + + "
\n" + + "" + + "\n" + + "" + + @BeforeClass + fun beforeClassJS() { + try { + if (BuildConfig.JS_TEST_SDK) { + val inputStream = + InstrumentationRegistry.getInstrumentation().context.resources.openRawResource( + R.raw.mparticle_js_sdk + ) + // add in all the basic configuration stuff the server would send with a production sdk fetch from the url + jsSdk = StringBuilder() + .append( + """ + window.mParticle = window.mParticle || {};; + window.mParticle.config = window.mParticle.config || {};; + window.mParticle.config.serviceUrl = 'jssdk.mparticle.com/v2/JS/';; + window.mParticle.config.secureServiceUrl = 'jssdks.mparticle.com/v2/JS/';; + window.mParticle.config.minWebviewBridgeVersion = 1; + window.mParticle.config.aliasMaxWindow = 90; + window.mParticle.config.kitConfigs = window.mParticle.config.kitConfigs || [];; + window.mParticle.config.pixelConfigs = window.mParticle.config.pixelConfigs || [];; + """.trimIndent() + ) + .append(toString(inputStream)) + .append( + """ + window.mParticle.config.requestConfig = false;; + mParticle.init(null, window.mParticle.config);; + """.trimIndent() + ) + .toString() + } else { + val connection = + URL("https://jssdkcdns.mparticle.com/js/v2/mparticle.js").openConnection() + jsSdk = toString(connection.getInputStream()) + } + sdkFetchedSuccessfully = true + } catch (ex: Exception) { + sdkFetchedSuccessfully = false + } + if (sdkFetchedSuccessfully) { + jsSdk = jsSdk!!.replace( + "jssdk.mparticle.com/v2/JS/", + "http://localhost:8080/v2" + ) // ; console.log(\"replaced url V2 single\");") + .replace( + "jssdks.mparticle.com/v2/JS/", + "http://localhost:8080/v2" + ) // ; console.log(\"replaced url V2 plural\");") + .replace( + "jssdks.mparticle.com/v1/JS/", + "http://localhost:8080/v1" + ) // ; console.log(\"replaced url V1 plural\");") + .replace( + "jssdk.mparticle.com/v1/JS/", + "http://localhost:8080/v1" + ) // ; console.log(\"replaced url V1 single\");") + .replace( + "https://identity.mparticle.com/v1/", + "http://localhost:8080/v1/" + ) // ; console.log(\"replaced url Identity\");") + .replace( + "// jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license", + "console.log(\"starting sdk\")" + ) + .replace( + "window.mParticle.config.minWebviewBridgeVersion = 1", + "window.mParticle.config.minWebviewBridgeVersion = " + bridgeVersion + ) + } + } + + @Throws(IOException::class) + private fun toString(inputStream: InputStream): String { + val `in` = BufferedReader(InputStreamReader(inputStream)) + val document = StringBuilder() + var line: String + while (`in`.readLine().also { line = it } != null) { + document.append( + """ + $line + + """.trimIndent() + ) + } + `in`.close() + return document.toString() + } + } + + class WebViewActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(com.mparticle.test.R.layout.web_view_activity) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/MessageManagerTests.java b/android-core/src/androidTest/java/com/mparticle/internal/MessageManagerTests.java deleted file mode 100644 index 7efe9a9b7..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/MessageManagerTests.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.mparticle.internal; - -import android.content.Context; -import android.content.SharedPreferences; - -import com.mparticle.AccessUtils; -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.internal.database.tables.SessionTable; -import com.mparticle.internal.messages.BaseMPMessage; -import com.mparticle.testutils.BaseCleanInstallEachTest; - -import junit.framework.Assert; - -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class MessageManagerTests extends BaseCleanInstallEachTest { - - - @Test - public void testInstallReferrerMigration() throws Exception { - //test previously installed - setFirstRunLegacy(true, "key"); - assertNull(MParticle.getInstance()); - startMParticle(); - getMessageManager().setFirstRunForAST(true); - - assertTrue(getMessageManager().isFirstRunForMessage()); - assertTrue(getMessageManager().isFirstRunForAST()); - - setFirstRunLegacy(false, "key"); - MParticle.setInstance(null); - startMParticle(); - assertFalse(getMessageManager().isFirstRunForMessage()); - assertFalse(getMessageManager().isFirstRunForAST()); - } - - @Test - public void testInstallReferrerFlags() throws Exception { - // test that both AST and First Run flags get properly flipped when their - // corresponding setters get called - setFirstRunLegacy(true, "key"); - assertNull(MParticle.getInstance()); - startMParticle(); - getMessageManager().setFirstRunForAST(true); - - assertTrue(getMessageManager().isFirstRunForAST()); - getMessageManager().setFirstRunForAST(false); - assertFalse(getMessageManager().isFirstRunForAST()); - - assertTrue(getMessageManager().isFirstRunForMessage()); - getMessageManager().setFirstRunForMessage(false); - assertFalse(getMessageManager().isFirstRunForMessage()); - - // same thing, but make sure nothing funky happens when the order gets - // reversed - MParticle.setInstance(null); - setFirstRunLegacy(true, "key"); - assertNull(MParticle.getInstance()); - startMParticle(); - - assertTrue(getMessageManager().isFirstRunForMessage()); - getMessageManager().setFirstRunForMessage(false); - assertFalse(getMessageManager().isFirstRunForMessage()); - - assertTrue(getMessageManager().isFirstRunForAST()); - getMessageManager().setFirstRunForAST(false); - assertFalse(getMessageManager().isFirstRunForAST()); - - // test that the flags remain persisted when the application restarts - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - startMParticle(); - - assertFalse(getMessageManager().isFirstRunForMessage()); - assertFalse(getMessageManager().isFirstRunForAST()); - - } - - @Test - public void testDuplicateSessionEnds() throws Exception { - startMParticle(); - InternalSession session = new InternalSession(); - session.start(mContext); - getMessageManager().startSession(session); - com.mparticle.internal.AccessUtils.awaitMessageHandler(); - BaseMPMessage message = getMessageManager().getMParticleDBManager().getSessionForSessionEndMessage(session.mSessionID, null, session.getMpids()); - Assert.assertNotNull(message); - getMessageManager().getMParticleDBManager().updateSessionStatus(session.mSessionID, SessionTable.SessionTableColumns.STATUS); - message = getMessageManager().getMParticleDBManager().getSessionForSessionEndMessage(session.mSessionID, null , session.getMpids()); - Assert.assertNull(message); - } - - @Test - public void testInstallReferrerFlagsEdgeCases() throws Exception { - setFirstRunLegacy(true, "key"); - - //start SDK, and send only AST, but not First Run message - assertNull(MParticle.getInstance()); - startMParticle(); - getMessageManager().setFirstRunForAST(true); - - assertTrue(getMessageManager().isFirstRunForAST()); - getMessageManager().setFirstRunForAST(false); - assertFalse(getMessageManager().isFirstRunForAST()); - - //restart SDK, and assert that AST message has been flagged, but First Run message has not - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - startMParticle(); - - assertTrue(getMessageManager().isFirstRunForMessage()); - assertFalse(getMessageManager().isFirstRunForAST()); - - - setFirstRunLegacy(true, "key"); - - //start SDK, and send only First Run message, but not AST - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - startMParticle(); - assertTrue(getMessageManager().isFirstRunForMessage()); - getMessageManager().setFirstRunForMessage(false); - assertFalse(getMessageManager().isFirstRunForMessage()); - - //restart SDK, and assert that First Run message has been flagged as sent, but AST has not - MParticle.setInstance(null); - assertNull(MParticle.getInstance()); - startMParticle(); - - assertFalse(getMessageManager().isFirstRunForMessage()); - assertTrue(getMessageManager().isFirstRunForAST()); - - } - - @Test - public void testDelayedStartInvoked() throws InterruptedException { - MParticleOptions options = MParticleOptions.builder(mContext).credentials("key", "secret").build(); - MParticle.start(options); - MessageManager messageManager = AccessUtils.getMessageManager(); - assertFalse(messageManager.hasDelayedStartOccurred()); - MessageHandler handler = com.mparticle.internal.AccessUtils.getMessageHandler(); - handler.sendMessage(handler.obtainMessage()); - com.mparticle.internal.AccessUtils.awaitMessageHandler(); - assertTrue(messageManager.hasDelayedStartOccurred()); - - } - - /** - * simulates the install state to settings pre 5.0.9 || pre 4.17.1 - * @param firstRun - */ - private void setFirstRunLegacy(boolean firstRun, String key) { - SharedPreferences sharedPreferences = mContext.getSharedPreferences(Constants.PREFS_FILE, Context.MODE_PRIVATE); - sharedPreferences.edit() - .remove(Constants.PrefKeys.FIRSTRUN_AST + key) - .remove(Constants.PrefKeys.FIRSTRUN_MESSAGE + key) - .apply(); - if (firstRun) { - sharedPreferences.edit().remove(Constants.PrefKeys.FIRSTRUN_OBSELETE + key).apply(); - } else { - sharedPreferences.edit().putBoolean(Constants.PrefKeys.FIRSTRUN_OBSELETE + key, false).apply(); - } - } - - private MessageManager getMessageManager() { - return AccessUtils.getMessageManager(); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/MessageManagerTests.kt b/android-core/src/androidTest/java/com/mparticle/internal/MessageManagerTests.kt new file mode 100644 index 000000000..853d3273d --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/MessageManagerTests.kt @@ -0,0 +1,178 @@ +package com.mparticle.internal + +import android.content.Context +import android.content.SharedPreferences +import com.mparticle.AccessUtils +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.internal.database.tables.SessionTable +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.context +import com.mparticle.utils.startMParticle +import org.junit.Assert +import org.junit.Test + +class MessageManagerTests : BaseTest() { + @Test + @Throws(Exception::class) + fun testInstallReferrerMigration() { + val apiKey = "apiKey" + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + // test previously installed + setFirstRunLegacy(true, apiKey) + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + messageManager.isFirstRunForAST = true + Assert.assertTrue(messageManager.isFirstRunForMessage) + Assert.assertTrue(messageManager.isFirstRunForAST) + setFirstRunLegacy(false, apiKey) + MParticle.setInstance(null) + startMParticle(options) + Assert.assertFalse(messageManager.isFirstRunForMessage) + Assert.assertFalse(messageManager.isFirstRunForAST) + } + + @Test + @Throws(Exception::class) + fun testInstallReferrerFlags() { + // test that both AST and First Run flags get properly flipped when their + // corresponding setters get called + val apiKey = "apiKey" + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + setFirstRunLegacy(true, apiKey) + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + messageManager.isFirstRunForAST = true + Assert.assertTrue(messageManager.isFirstRunForAST) + messageManager.isFirstRunForAST = false + Assert.assertFalse(messageManager.isFirstRunForAST) + Assert.assertTrue(messageManager.isFirstRunForMessage) + messageManager.isFirstRunForMessage = false + Assert.assertFalse(messageManager.isFirstRunForMessage) + + // same thing, but make sure nothing funky happens when the order gets + // reversed + MParticle.setInstance(null) + setFirstRunLegacy(true, "apiKey") + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + Assert.assertTrue(messageManager.isFirstRunForMessage) + messageManager.isFirstRunForMessage = false + Assert.assertFalse(messageManager.isFirstRunForMessage) + Assert.assertTrue(messageManager.isFirstRunForAST) + messageManager.isFirstRunForAST = false + Assert.assertFalse(messageManager.isFirstRunForAST) + + // test that the flags remain persisted when the application restarts + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + Assert.assertFalse(messageManager.isFirstRunForMessage) + Assert.assertFalse(messageManager.isFirstRunForAST) + } + + @Test + @Throws(Exception::class) + fun testDuplicateSessionEnds() { + startMParticle() + val session = InternalSession() + session.start(context) + messageManager.startSession(session) + com.mparticle.internal.AccessUtils.awaitMessageHandler() + var message: BaseMPMessage? = + messageManager.mParticleDBManager.getSessionForSessionEndMessage( + session.mSessionID, + null, + session.mpids + ) + junit.framework.Assert.assertNotNull(message) + messageManager.mParticleDBManager.updateSessionStatus( + session.mSessionID, + SessionTable.SessionTableColumns.STATUS + ) + message = messageManager.mParticleDBManager.getSessionForSessionEndMessage( + session.mSessionID, + null, + session.mpids + ) + junit.framework.Assert.assertNull(message) + } + + @Test + @Throws(Exception::class) + fun testInstallReferrerFlagsEdgeCases() { + val apiKey = "apiKey" + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + setFirstRunLegacy(true, "key") + + // start SDK, and send only AST, but not First Run message + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + messageManager.isFirstRunForAST = true + Assert.assertTrue(messageManager.isFirstRunForAST) + messageManager.isFirstRunForAST = false + Assert.assertFalse(messageManager.isFirstRunForAST) + + // restart SDK, and assert that AST message has been flagged, but First Run message has not + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + Assert.assertTrue(messageManager.isFirstRunForMessage) + Assert.assertFalse(messageManager.isFirstRunForAST) + setFirstRunLegacy(true, apiKey) + + // start SDK, and send only First Run message, but not AST + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + Assert.assertTrue(messageManager.isFirstRunForMessage) + messageManager.isFirstRunForMessage = false + Assert.assertFalse(messageManager.isFirstRunForMessage) + + // restart SDK, and assert that First Run message has been flagged as sent, but AST has not + MParticle.setInstance(null) + Assert.assertNull(MParticle.getInstance()) + startMParticle(options) + Assert.assertFalse(messageManager.isFirstRunForMessage) + Assert.assertTrue(messageManager.isFirstRunForAST) + } + + @Test + @Throws(InterruptedException::class) + fun testDelayedStartInvoked() { + val options = MParticleOptions.builder(context).credentials("key", "secret").build() + MParticle.start(options) + val messageManager = AccessUtils.messageManager + Assert.assertFalse(messageManager.hasDelayedStartOccurred()) + val handler = com.mparticle.internal.AccessUtils.messageHandler + handler.sendMessage(handler.obtainMessage()) + com.mparticle.internal.AccessUtils.awaitMessageHandler() + Assert.assertTrue(messageManager.hasDelayedStartOccurred()) + } + + /** + * simulates the install state to settings pre 5.0.9 || pre 4.17.1 + * @param firstRun + */ + private fun setFirstRunLegacy(firstRun: Boolean, key: String) { + val sharedPreferences: SharedPreferences = + context.getSharedPreferences(Constants.PREFS_FILE, Context.MODE_PRIVATE) + sharedPreferences.edit() + .remove(Constants.PrefKeys.FIRSTRUN_AST + key) + .remove(Constants.PrefKeys.FIRSTRUN_MESSAGE + key) + .apply() + if (firstRun) { + sharedPreferences.edit().remove(Constants.PrefKeys.FIRSTRUN_OBSELETE + key).apply() + } else { + sharedPreferences.edit().putBoolean(Constants.PrefKeys.FIRSTRUN_OBSELETE + key, false) + .apply() + } + } + + private val messageManager: MessageManager + private get() = AccessUtils.messageManager +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/UserStorageTest.java b/android-core/src/androidTest/java/com/mparticle/internal/UserStorageTest.java deleted file mode 100644 index 758291426..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/UserStorageTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mparticle.internal; - -import com.mparticle.MParticle; -import com.mparticle.testutils.BaseCleanStartedEachTest; - -import org.junit.Before; -import org.junit.Test; - -import java.util.HashSet; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class UserStorageTest extends BaseCleanStartedEachTest { - - @Before - public void before() { - MParticle.reset(mContext); - } - - @Test - public void testSetFirstSeenTime() throws InterruptedException { - long startTime = System.currentTimeMillis(); - UserStorage storage = UserStorage.create(mContext, ran.nextLong()); - long firstSeen = storage.getFirstSeenTime(); - - assertTrue(firstSeen >= startTime && firstSeen <= System.currentTimeMillis()); - - //make sure that the firstSeenTime does not update if it has already been set - storage.setFirstSeenTime(10L); - assertEquals(firstSeen, storage.getFirstSeenTime()); - } - - @Test - public void testSetLastSeenTime() throws InterruptedException { - UserStorage storage = UserStorage.create(mContext, 2); - long time = System.currentTimeMillis(); - storage.setLastSeenTime(time); - assertEquals(time, storage.getLastSeenTime()); - } - - interface UserConfigRunnable { - void run(UserStorage userStorage); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/UserStorageTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/UserStorageTest.kt new file mode 100644 index 000000000..390e2878f --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/UserStorageTest.kt @@ -0,0 +1,42 @@ +package com.mparticle.internal + +import com.mparticle.MParticle +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.context +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import kotlin.random.Random + +class UserStorageTest : BaseStartedTest() { + @Before + fun before() { + MParticle.reset(context) + } + + @Test + @Throws(InterruptedException::class) + fun testSetFirstSeenTime() { + val startTime = System.currentTimeMillis() + val storage = UserStorage.create(context, Random.Default.nextLong()) + val firstSeen = storage.firstSeenTime + Assert.assertTrue(firstSeen >= startTime && firstSeen <= System.currentTimeMillis()) + + // make sure that the firstSeenTime does not update if it has already been set + storage.setFirstSeenTime(10L) + Assert.assertEquals(firstSeen, storage.firstSeenTime) + } + + @Test + @Throws(InterruptedException::class) + fun testSetLastSeenTime() { + val storage = UserStorage.create(context, 2) + val time = System.currentTimeMillis() + storage.setLastSeenTime(time) + Assert.assertEquals(time, storage.lastSeenTime) + } + + internal interface UserConfigRunnable { + fun run(userStorage: UserStorage?) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/TestSQLiteOpenHelper.java b/android-core/src/androidTest/java/com/mparticle/internal/database/TestSQLiteOpenHelper.java deleted file mode 100644 index 65fe69cb1..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/TestSQLiteOpenHelper.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.mparticle.internal.database; - -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import androidx.test.platform.app.InstrumentationRegistry; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; -import com.mparticle.testutils.MPLatch; - -import java.util.concurrent.CountDownLatch; - -public class TestSQLiteOpenHelper extends SQLiteOpenHelper { - SQLiteOpenHelperWrapper helper; - public CountDownLatch onCreateLatch; - public CountDownLatch onUpgradeLatch; - public CountDownLatch onDowngradeLatch; - - public TestSQLiteOpenHelper(SQLiteOpenHelperWrapper helper, String databaseName) { - this(helper, databaseName, 1); - } - - public TestSQLiteOpenHelper(SQLiteOpenHelperWrapper helper, String databaseName, int version) { - super(InstrumentationRegistry.getInstrumentation().getContext(), databaseName, null, version); - this.helper = helper; - this.onCreateLatch = new MPLatch(1); - this.onUpgradeLatch = new MPLatch(1); - this.onDowngradeLatch = new MPLatch(1); - getWritableDatabase(); - } - - @Override - public void onCreate(SQLiteDatabase db) { - helper.onCreate(db); - onCreateLatch.countDown(); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - helper.onUpgrade(db, oldVersion, newVersion); - onUpgradeLatch.countDown(); - } - - @Override - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - helper.onDowngrade(db, oldVersion, newVersion); - onDowngradeLatch.countDown(); - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/TestSQLiteOpenHelper.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/TestSQLiteOpenHelper.kt new file mode 100644 index 000000000..c32e68b4e --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/TestSQLiteOpenHelper.kt @@ -0,0 +1,38 @@ +package com.mparticle.internal.database + +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteOpenHelper +import androidx.test.platform.app.InstrumentationRegistry +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import com.mparticle.testing.FailureLatch + +class TestSQLiteOpenHelper @JvmOverloads constructor( + helper: SQLiteOpenHelperWrapper, + databaseName: String?, + version: Int = 1 +) : SQLiteOpenHelper( + InstrumentationRegistry.getInstrumentation().context, databaseName, null, version +) { + var helper: SQLiteOpenHelperWrapper = helper + var onCreateLatch = FailureLatch() + var onUpgradeLatch = FailureLatch() + var onDowngradeLatch = FailureLatch() + override fun onCreate(db: SQLiteDatabase) { + helper.onCreate(db) + onCreateLatch.countDown() + } + + override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onUpgrade(db, oldVersion, newVersion) + onUpgradeLatch.countDown() + } + + override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onDowngrade(db, oldVersion, newVersion) + onDowngradeLatch.countDown() + } + + init { + writableDatabase + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeMessageTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeMessageTableTest.java deleted file mode 100644 index 18c1de099..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeMessageTableTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.mparticle.internal.database; - -import android.database.sqlite.SQLiteDatabase; -import android.provider.BaseColumns; -import androidx.test.platform.app.InstrumentationRegistry; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; -import com.mparticle.internal.database.tables.BaseTableTest; -import com.mparticle.internal.database.tables.MParticleDatabaseHelper; -import com.mparticle.internal.database.tables.MessageTable; - -import org.junit.Test; - -public class UpgradeMessageTableTest extends BaseTableTest { - private MParticleDatabaseHelper helper = new MParticleDatabaseHelper(mContext); - - static final String CREATE_MESSAGES_DDL = - "CREATE TABLE IF NOT EXISTS " + MessageTable.MessageTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - MessageTable.MessageTableColumns.SESSION_ID + " STRING NOT NULL, " + - MessageTable.MessageTableColumns.API_KEY + " STRING NOT NULL, " + - MessageTable.MessageTableColumns.MESSAGE + " TEXT, " + - MessageTable.MessageTableColumns.STATUS + " INTEGER, " + - MessageTable.MessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + - MessageTable.MessageTableColumns.MESSAGE_TYPE + " TEXT, " + - MessageTable.MessageTableColumns.CF_UUID + " TEXT, " + - MessageTable.MessageTableColumns.MP_ID + " INTEGER" + - ");"; - - @Test - public void addMessageTableTest() throws InterruptedException { - //test to make sure it doesn't crash when there is an FcmMessages table to delete - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(CREATE_MESSAGES_DDL); - helper.onCreate(database); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - helper.onUpgrade(database, oldVersion, newVersion); - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - helper.onDowngrade(database, oldVersion, newVersion); - } - }, 9); - deleteTestingDatabase(); - - //test to make sure it doesn't crash when there is NO FcmMessages table to delete - runTest(helper, 8); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeMessageTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeMessageTableTest.kt new file mode 100644 index 000000000..74a3fa898 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeMessageTableTest.kt @@ -0,0 +1,55 @@ +package com.mparticle.internal.database + +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import com.mparticle.internal.database.tables.BaseTableTest +import com.mparticle.internal.database.tables.MParticleDatabaseHelper +import com.mparticle.internal.database.tables.MessageTable +import com.mparticle.testing.context +import org.junit.Test + +class UpgradeMessageTableTest : BaseTableTest() { + private val helper = MParticleDatabaseHelper(context) + @Test + @Throws(InterruptedException::class) + fun addMessageTableTest() { + // test to make sure it doesn't crash when there is an FcmMessages table to delete + runTest( + object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(CREATE_MESSAGES_DDL) + helper.onCreate(database) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onUpgrade(database, oldVersion, newVersion) + } + + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onDowngrade(database, oldVersion, newVersion) + } + }, + 9 + ) + deleteTestingDatabase() + + // test to make sure it doesn't crash when there is NO FcmMessages table to delete + runTest(helper, 8) + } + + companion object { + const val CREATE_MESSAGES_DDL = + "CREATE TABLE IF NOT EXISTS " + MessageTable.MessageTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + MessageTable.MessageTableColumns.SESSION_ID + " STRING NOT NULL, " + + MessageTable.MessageTableColumns.API_KEY + " STRING NOT NULL, " + + MessageTable.MessageTableColumns.MESSAGE + " TEXT, " + + MessageTable.MessageTableColumns.STATUS + " INTEGER, " + + MessageTable.MessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + + MessageTable.MessageTableColumns.MESSAGE_TYPE + " TEXT, " + + MessageTable.MessageTableColumns.CF_UUID + " TEXT, " + + MessageTable.MessageTableColumns.MP_ID + " INTEGER" + + ");" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeVersionTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeVersionTest.java deleted file mode 100644 index 489019808..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeVersionTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.mparticle.internal.database; - -import android.database.sqlite.SQLiteDatabase; -import android.location.Location; - -import com.mparticle.internal.InternalSession; -import com.mparticle.internal.database.services.BreadcrumbService; -import com.mparticle.internal.database.services.MessageService; -import com.mparticle.internal.database.services.ReportingService; -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; -import com.mparticle.internal.database.services.SessionService; -import com.mparticle.internal.database.services.UploadService; -import com.mparticle.internal.database.services.UserAttributesService; -import com.mparticle.internal.database.tables.BaseTableTest; -import com.mparticle.internal.database.tables.BreadcrumbTableTest; -import com.mparticle.internal.database.tables.MParticleDatabaseHelper; -import com.mparticle.internal.database.tables.MessageTableTest; -import com.mparticle.internal.database.tables.MpIdDependentTable; -import com.mparticle.internal.database.tables.ReportingTableTest; -import com.mparticle.internal.database.tables.SessionTableTest; -import com.mparticle.internal.database.tables.UploadTable; -import com.mparticle.internal.database.tables.UserAttributeTableTest; -import com.mparticle.internal.messages.BaseMPMessage; -import com.mparticle.testutils.MPLatch; -import com.mparticle.testutils.TestingUtils; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; - -import java.util.Iterator; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -public class UpgradeVersionTest extends BaseTableTest { - private MParticleDatabaseHelper helper = new MParticleDatabaseHelper(mContext); - - protected interface FcmMessageTableColumns { - String CONTENT_ID = "content_id"; - String CAMPAIGN_ID = "campaign_id"; - String TABLE_NAME = "gcm_messages"; - String PAYLOAD = "payload"; - String CREATED_AT = "message_time"; - String DISPLAYED_AT = "displayed_time"; - String EXPIRATION = "expiration"; - String BEHAVIOR = "behavior"; - String APPSTATE = "appstate"; - } - - static final String CREATE_GCM_MSG_DDL = - "CREATE TABLE IF NOT EXISTS " + FcmMessageTableColumns.TABLE_NAME + " (" + FcmMessageTableColumns.CONTENT_ID + - " INTEGER PRIMARY KEY, " + - FcmMessageTableColumns.PAYLOAD + " TEXT NOT NULL, " + - FcmMessageTableColumns.APPSTATE + " TEXT NOT NULL, " + - FcmMessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + - FcmMessageTableColumns.EXPIRATION + " INTEGER NOT NULL, " + - FcmMessageTableColumns.BEHAVIOR + " INTEGER NOT NULL," + - FcmMessageTableColumns.CAMPAIGN_ID + " TEXT NOT NULL, " + - FcmMessageTableColumns.DISPLAYED_AT + " INTEGER NOT NULL " + - ");"; - - @Test - public void testDropFcmMessageTable() throws InterruptedException { - //test to make sure it doesn't crash when there is an FcmMessages table to delete - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(CREATE_GCM_MSG_DDL); - helper.onCreate(database); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - helper.onUpgrade(database, oldVersion, newVersion); - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - helper.onDowngrade(database, oldVersion, newVersion); - } - }, 7); - deleteTestingDatabase(); - - //test to make sure it doesn't crash when there is NO FcmMessages table to delete - runTest(helper, 7); - } - - @Test - public void testDowngradeTable() throws InterruptedException, JSONException { - - //Open database and insert some values - TestSQLiteOpenHelper baseDatabase = new TestSQLiteOpenHelper(helper, DB_NAME, Integer.MAX_VALUE); - baseDatabase.onCreateLatch.await(); - MPDatabase db = new MPDatabaseImpl(baseDatabase.getWritableDatabase()); - - BaseMPMessage message = new BaseMPMessage.Builder("test").build(new InternalSession(), new Location("New York City"), 1); - - BreadcrumbService.insertBreadcrumb(db, mContext, message, "key", 1l); - MessageService.insertMessage(db, "key", message, 1L, "id", 1); - ReportingService.insertReportingMessage(db, TestingUtils.getInstance().getRandomReportingMessage("123"), 1L); - SessionService.insertSession(db, message, "key", "", "", 1L); - UploadService.insertAliasRequest(db, "key", new JSONObject().put("key", "value")); - UserAttributesService.insertAttribute(db, "key", "value", 1L, false, 1L); - - //test to make sure there are values in the database - JSONObject databaseJSON = getDatabaseContents(db); - assertEquals(6, databaseJSON.length()); - Iterator databaseTables = databaseJSON.keys(); - while(databaseTables.hasNext()) { - String tableName = databaseTables.next(); - assertEquals(tableName,1, databaseJSON.getJSONArray(tableName).length()); - } - - //reopen the database, make sure nothing happens on a normal install - baseDatabase = new TestSQLiteOpenHelper(helper, DB_NAME, Integer.MAX_VALUE); - db = new MPDatabaseImpl(baseDatabase.getWritableDatabase()); - - //test to make sure the values are still in the database - databaseJSON = getDatabaseContents(db); - assertEquals(6, databaseJSON.length()); - databaseTables = databaseJSON.keys(); - while(databaseTables.hasNext()) { - String tableName = databaseTables.next(); - assertEquals(tableName,1, databaseJSON.getJSONArray(tableName).length()); - } - - //downgrade the database - baseDatabase = new TestSQLiteOpenHelper(helper, DB_NAME, 1); - baseDatabase.getWritableDatabase(); - baseDatabase.onDowngradeLatch.await(); - db = new MPDatabaseImpl(baseDatabase.getWritableDatabase()); - - //test to make sure the values where delete and the database is empty - databaseJSON = getDatabaseContents(db); - assertEquals(6, databaseJSON.length()); - databaseTables = databaseJSON.keys(); - while(databaseTables.hasNext()) { - String tableName = databaseTables.next(); - assertEquals(tableName, 0, databaseJSON.getJSONArray(tableName).length()); - } - } - - @Test - public void testAddMpidColumns() throws InterruptedException, JSONException { - SQLiteOpenHelperWrapper sqLiteOpenHelperWrapper = new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(SessionTableTest.old_CREATE_SESSION_DDL); - db.execSQL(MessageTableTest.old_no_mpid_CREATE_MESSAGES_DDL); - db.execSQL(BreadcrumbTableTest.old_CREATE_BREADCRUMBS_DDL); - db.execSQL(ReportingTableTest.old_CREATE_REPORTING_DDL); - db.execSQL(UserAttributeTableTest.old_CREATE_USER_ATTRIBUTES_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - helper.onUpgrade(database, oldVersion, newVersion); - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - helper.onDowngrade(database, oldVersion, newVersion); - } - }; - TestSQLiteOpenHelper sqLiteOpenHelper = new TestSQLiteOpenHelper(sqLiteOpenHelperWrapper, DB_NAME, 6); - sqLiteOpenHelper.onCreateLatch.await(); - - JSONObject databaseContents = getDatabaseSchema(sqLiteOpenHelper.getWritableDatabase()); - Iterator keys = databaseContents.keys(); - while(keys.hasNext()) { - String key = keys.next(); - assertFalse(databaseContents.getJSONObject(key).has(MpIdDependentTable.MP_ID)); - } - sqLiteOpenHelper = new TestSQLiteOpenHelper(sqLiteOpenHelperWrapper, DB_NAME, 8); - sqLiteOpenHelper.getWritableDatabase(); - sqLiteOpenHelper.onUpgradeLatch.await(); - - databaseContents = getDatabaseSchema(sqLiteOpenHelper.getWritableDatabase()); - keys = databaseContents.keys(); - while(keys.hasNext()) { - String key = keys.next(); - if (!key.equals("uploads")) { - assertTrue(databaseContents.getJSONObject(key).has(MpIdDependentTable.MP_ID)); - } else { - assertFalse(databaseContents.getJSONObject(key).has(MpIdDependentTable.MP_ID)); - } - } - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeVersionTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeVersionTest.kt new file mode 100644 index 000000000..f49efd521 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/UpgradeVersionTest.kt @@ -0,0 +1,183 @@ +package com.mparticle.internal.database + +import android.database.sqlite.SQLiteDatabase +import android.location.Location +import com.mparticle.internal.InternalSession +import com.mparticle.internal.database.services.BreadcrumbService +import com.mparticle.internal.database.services.MessageService +import com.mparticle.internal.database.services.ReportingService +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import com.mparticle.internal.database.services.SessionService +import com.mparticle.internal.database.services.UploadService +import com.mparticle.internal.database.services.UserAttributesService +import com.mparticle.internal.database.tables.BaseTableTest +import com.mparticle.internal.database.tables.BreadcrumbTableTest +import com.mparticle.internal.database.tables.MParticleDatabaseHelper +import com.mparticle.internal.database.tables.MessageTableTest +import com.mparticle.internal.database.tables.MpIdDependentTable +import com.mparticle.internal.database.tables.ReportingTableTest +import com.mparticle.internal.database.tables.SessionTableTest +import com.mparticle.internal.database.tables.UserAttributeTableTest +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.testing.context +import org.json.JSONException +import org.json.JSONObject +import org.junit.Assert +import org.junit.Test + +class UpgradeVersionTest : BaseTableTest() { + private val helper = MParticleDatabaseHelper(context) + + protected interface FcmMessageTableColumns { + companion object { + const val CONTENT_ID = "content_id" + const val CAMPAIGN_ID = "campaign_id" + const val TABLE_NAME = "gcm_messages" + const val PAYLOAD = "payload" + const val CREATED_AT = "message_time" + const val DISPLAYED_AT = "displayed_time" + const val EXPIRATION = "expiration" + const val BEHAVIOR = "behavior" + const val APPSTATE = "appstate" + } + } + + @Test + @Throws(InterruptedException::class) + fun testDropFcmMessageTable() { + // test to make sure it doesn't crash when there is an FcmMessages table to delete + runTest( + object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(CREATE_GCM_MSG_DDL) + helper.onCreate(database) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onUpgrade(database, oldVersion, newVersion) + } + + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onDowngrade(database, oldVersion, newVersion) + } + }, + 7 + ) + deleteTestingDatabase() + + // test to make sure it doesn't crash when there is NO FcmMessages table to delete + runTest(helper, 7) + } + + @Test + @Throws(InterruptedException::class, JSONException::class) + fun testDowngradeTable() { + + // Open database and insert some values + var baseDatabase = + TestSQLiteOpenHelper(helper, BaseTableTest.DB_NAME, Int.MAX_VALUE) + baseDatabase.onCreateLatch.await() + var db = MPDatabaseImpl(baseDatabase.writableDatabase) + val message: BaseMPMessage = + BaseMPMessage.Builder("test").build(InternalSession(), Location("New York City"), 1) + BreadcrumbService.insertBreadcrumb(db, context, message, "key", 1L) + MessageService.insertMessage(db, "key", message, 1L, "id", 1) + ReportingService.insertReportingMessage( + db, + ReportingTableTest.getRandomReportingMessage("123"), + 1L + ) + SessionService.insertSession(db, message, "key", "", "", 1L) + UploadService.insertAliasRequest(db, "key", JSONObject().put("key", "value")) + UserAttributesService.insertAttribute(db, "key", "value", 1L, false, 1L) + + // test to make sure there are values in the database + var databaseContents = mockingPlatforms.getDatabaseContents(db as MPDatabase) + Assert.assertEquals(6, databaseContents.size) + databaseContents.entries.forEach { + Assert.assertEquals( + it.key, + 1, + it.value.size + ) + } + + // reopen the database, make sure nothing happens on a normal install + baseDatabase = TestSQLiteOpenHelper(helper, BaseTableTest.DB_NAME, Int.MAX_VALUE) + db = MPDatabaseImpl(baseDatabase.writableDatabase) + + // test to make sure the values are still in the database + databaseContents = mockingPlatforms.getDatabaseContents(db as MPDatabase) + Assert.assertEquals(6, databaseContents.size.toLong()) + databaseContents.forEach { + Assert.assertEquals(it.key, 1, it.value.size) + } + + // downgrade the database + baseDatabase = TestSQLiteOpenHelper(helper, BaseTableTest.DB_NAME, 1) + baseDatabase.writableDatabase + baseDatabase.onDowngradeLatch.await() + db = MPDatabaseImpl(baseDatabase.writableDatabase) + + // test to make sure the values where delete and the database is empty + databaseContents = mockingPlatforms.getDatabaseContents(db as MPDatabase) + Assert.assertEquals(6, databaseContents.size) + databaseContents.forEach { + Assert.assertEquals(it.key, 0, it.value.size) + } + } + + @Test + @Throws(InterruptedException::class, JSONException::class) + fun testAddMpidColumns() { + val sqLiteOpenHelperWrapper: SQLiteOpenHelperWrapper = object : SQLiteOpenHelperWrapper { + override fun onCreate(db: SQLiteDatabase) { + db.execSQL(com.mparticle.internal.database.tables.SessionTableTest.old_CREATE_SESSION_DDL) + db.execSQL(MessageTableTest.old_no_mpid_CREATE_MESSAGES_DDL) + db.execSQL(BreadcrumbTableTest.old_CREATE_BREADCRUMBS_DDL) + db.execSQL(ReportingTableTest.old_CREATE_REPORTING_DDL) + db.execSQL(UserAttributeTableTest.old_CREATE_USER_ATTRIBUTES_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onUpgrade(database, oldVersion, newVersion) + } + + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + helper.onDowngrade(database, oldVersion, newVersion) + } + } + var sqLiteOpenHelper = + TestSQLiteOpenHelper(sqLiteOpenHelperWrapper, BaseTableTest.DB_NAME, 6) + sqLiteOpenHelper.onCreateLatch.await() + var databaseContents = mockingPlatforms.getDatabaseSchema(sqLiteOpenHelper.writableDatabase) + databaseContents.forEach { Assert.assertFalse(it.value.contains(MpIdDependentTable.MP_ID)) } + + sqLiteOpenHelper = + TestSQLiteOpenHelper(sqLiteOpenHelperWrapper, BaseTableTest.DB_NAME, 8) + sqLiteOpenHelper.writableDatabase + sqLiteOpenHelper.onUpgradeLatch.await() + databaseContents = mockingPlatforms.getDatabaseSchema(sqLiteOpenHelper.writableDatabase) + databaseContents.forEach { + if (it.key == "uploads") { + Assert.assertFalse(it.value.contains(MpIdDependentTable.MP_ID)) + } else { + Assert.assertTrue(it.value.contains(MpIdDependentTable.MP_ID)) + } + } + } + + companion object { + const val CREATE_GCM_MSG_DDL = + "CREATE TABLE IF NOT EXISTS " + FcmMessageTableColumns.TABLE_NAME + " (" + FcmMessageTableColumns.CONTENT_ID + + " INTEGER PRIMARY KEY, " + + FcmMessageTableColumns.PAYLOAD + " TEXT NOT NULL, " + + FcmMessageTableColumns.APPSTATE + " TEXT NOT NULL, " + + FcmMessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + + FcmMessageTableColumns.EXPIRATION + " INTEGER NOT NULL, " + + FcmMessageTableColumns.BEHAVIOR + " INTEGER NOT NULL," + + FcmMessageTableColumns.CAMPAIGN_ID + " TEXT NOT NULL, " + + FcmMessageTableColumns.DISPLAYED_AT + " INTEGER NOT NULL " + + ");" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/AccessUtils.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/AccessUtils.java deleted file mode 100644 index 04616f798..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/AccessUtils.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.mparticle.internal.database.services; - -public final class AccessUtils { - - public static void setMessageStoredListener(MParticleDBManager.MessageListener listener) { - MParticleDBManager.setMessageListener(listener); - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/AccessUtils.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/AccessUtils.kt new file mode 100644 index 000000000..7b1d7ed15 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/AccessUtils.kt @@ -0,0 +1,7 @@ +package com.mparticle.internal.database.services + +object AccessUtils { + fun setMessageStoredListener(listener: MParticleDBManager.MessageListener?) { + MParticleDBManager.setMessageListener(listener) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/BaseMPServiceTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/BaseMPServiceTest.java deleted file mode 100644 index 6f2a52ccd..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/BaseMPServiceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mparticle.internal.database.services; - -import android.database.sqlite.SQLiteOpenHelper; -import android.location.Location; - -import com.mparticle.internal.InternalSession; -import com.mparticle.internal.database.TestSQLiteOpenHelper; -import com.mparticle.internal.database.MPDatabaseImpl; -import com.mparticle.internal.database.tables.MParticleDatabaseHelper; -import com.mparticle.internal.messages.BaseMPMessage; -import com.mparticle.testutils.BaseCleanInstallEachTest; - -import org.json.JSONException; -import org.junit.Before; - -import java.util.UUID; - -abstract public class BaseMPServiceTest extends BaseCleanInstallEachTest { - protected static MPDatabaseImpl database; - - @Before - public final void beforeBaseMPService() throws Exception { - SQLiteOpenHelper openHelper = new TestSQLiteOpenHelper(new MParticleDatabaseHelper(mContext), MParticleDatabaseHelper.getDbName()); - database = new MPDatabaseImpl(openHelper.getWritableDatabase()); - } - - BaseMPMessage getMpMessage() throws JSONException { - return getMpMessage(UUID.randomUUID().toString()); - } - - BaseMPMessage getMpMessage(String sessionId) throws JSONException { - return getMpMessage(sessionId, mRandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE)); - } - - BaseMPMessage getMpMessage(String sessionId, long mpid) throws JSONException { - InternalSession session = new InternalSession(); - session.mSessionID = sessionId; - return new BaseMPMessage.Builder(mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(20, 48))).build(session, new Location(mRandomUtils.getAlphaNumericString(mRandomUtils.randomInt(1, 55))), mpid); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/BaseMPServiceTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/BaseMPServiceTest.kt new file mode 100644 index 000000000..274027f10 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/BaseMPServiceTest.kt @@ -0,0 +1,59 @@ +package com.mparticle.internal.database.services + +import android.database.sqlite.SQLiteOpenHelper +import android.location.Location +import com.mparticle.internal.InternalSession +import com.mparticle.internal.database.MPDatabaseImpl +import com.mparticle.internal.database.TestSQLiteOpenHelper +import com.mparticle.internal.database.tables.MParticleDatabaseHelper +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.context +import org.json.JSONException +import org.junit.Before +import java.util.UUID + +abstract class BaseMPServiceTest : BaseTest() { + @Before + @Throws(Exception::class) + fun beforeBaseMPService() { + val openHelper: SQLiteOpenHelper = TestSQLiteOpenHelper( + MParticleDatabaseHelper(context), + MParticleDatabaseHelper.getDbName() + ) + database = MPDatabaseImpl(openHelper.writableDatabase) + } + + @get:Throws(JSONException::class) + val mpMessage: BaseMPMessage + get() = getMpMessage(UUID.randomUUID().toString()) + + @Throws(JSONException::class) + fun getMpMessage(sessionId: String): BaseMPMessage { + return getMpMessage(sessionId, RandomUtils.randomLong(Long.MIN_VALUE, Long.MAX_VALUE)) + } + + @Throws(JSONException::class) + fun getMpMessage(sessionId: String, mpid: Long): BaseMPMessage { + val session = InternalSession() + session.mSessionID = sessionId + return BaseMPMessage.Builder( + RandomUtils.getAlphaNumericString( + RandomUtils.randomInt( + 20, + 48 + ) + ) + ).build( + session, + Location(RandomUtils.getAlphaNumericString(RandomUtils.randomInt(1, 55))), + mpid + ) + } + + companion object { + @JvmStatic + protected var database: MPDatabaseImpl? = null + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/BreadcrumbServiceTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/BreadcrumbServiceTest.java deleted file mode 100644 index 7fbe462de..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/BreadcrumbServiceTest.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.mparticle.internal.database.services; - -import android.location.Location; - -import com.mparticle.internal.ConfigManager; -import com.mparticle.internal.InternalSession; -import com.mparticle.internal.messages.BaseMPMessage; - -import org.json.JSONException; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class BreadcrumbServiceTest extends BaseMPServiceTest { - private static BaseMPMessage message; - private static int breadCrumbLimit; - - @Before - public void before() throws Exception { - message = new BaseMPMessage.Builder("test").build(new InternalSession(), new Location("New York City"), 1); - breadCrumbLimit = ConfigManager.getBreadcrumbLimit(mContext); - } - - /** - * test throwing a bunch of trash, edge cases into the table and make sure that null values are - * not stored in essential fields, and that it does not break the database - * @throws Exception - */ - @Test - public void testNullValues() throws Exception { - for (int i = 0; i < breadCrumbLimit + 10; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, message, "k", null); - } - assertEquals(BreadcrumbService.getBreadcrumbCount(database, null), 0); - - for (int i = 0; i < breadCrumbLimit + 10; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, message, null, 10L); - } - - assertEquals(BreadcrumbService.getBreadcrumbCount(database, 10L), 0); - - for (int i = 0; i < breadCrumbLimit + 10; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, null, "k", 10L); - } - - assertEquals(BreadcrumbService.getBreadcrumbCount(database, 10L), 0); - - for (int i = 0; i < 10; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, message, "k", 10L); - } - - assertEquals(BreadcrumbService.getBreadcrumbCount(database, 10L), 10); - - for (int i = 0; i < breadCrumbLimit + 10; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, message, null, 10L); - } - - assertEquals(BreadcrumbService.getBreadcrumbCount(database, 10L), 10); - - for (int i = 0; i < breadCrumbLimit + 10; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, null, "k", 10L); - } - - assertEquals(BreadcrumbService.getBreadcrumbCount(database, 10L), 10); - } - - /** - * test that the new DB schema of storing stuff dependent on MPID is working - * @throws Exception - */ - @Test - public void testMpIdSpecific() throws Exception { - - /** - * this test won't work if you can't store breadcrumbs - */ - assertTrue(breadCrumbLimit >= 2); - - int expectedCount = breadCrumbLimit; - for (int i = 0; i < expectedCount; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, message, "apiKey", 1L); - } - assertEquals(BreadcrumbService.getBreadcrumbs(database, mContext, 1L).length(), expectedCount); - assertEquals(BreadcrumbService.getBreadcrumbs(database, mContext, 2L).length(), 0); - - for (int i = 0; i < expectedCount -1; i++) { - BreadcrumbService.insertBreadcrumb(database, mContext, message, "apiKey", 2L); - } - - assertEquals(BreadcrumbService.getBreadcrumbs(database, mContext, 1L).length(), expectedCount); - assertEquals(BreadcrumbService.getBreadcrumbs(database, mContext, 2L).length(), expectedCount - 1); - assertEquals(BreadcrumbService.getBreadcrumbs(database, mContext, 3L).length(), 0); - } - - @Test - public void testBreadcrumbLimit() throws JSONException { - List deleted = new ArrayList(); - - for (int i = 0; i < breadCrumbLimit + 10; i++) { - deleted.add(BreadcrumbService.insertBreadcrumb(database, mContext, message, "apiKey", 10L)); - } - - // make sure that 10 (number attempted to be inserted above the breadcrumb limit) entries have been deleted - deleted.removeAll(Collections.singleton(new Integer(-1))); - assertEquals(deleted.size(), 10); - - assertEquals(BreadcrumbService.getBreadcrumbs(database, mContext, 10L).length(), breadCrumbLimit); - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/BreadcrumbServiceTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/BreadcrumbServiceTest.kt new file mode 100644 index 000000000..59e63459d --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/BreadcrumbServiceTest.kt @@ -0,0 +1,233 @@ +package com.mparticle.internal.database.services + +import android.location.Location +import com.mparticle.internal.ConfigManager +import com.mparticle.internal.InternalSession +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.testing.context +import org.json.JSONException +import org.junit.Assert +import org.junit.Before +import org.junit.Test + +class BreadcrumbServiceTest : BaseMPServiceTest() { + @Before + @Throws(Exception::class) + fun before() { + message = + BaseMPMessage.Builder("test").build(InternalSession(), Location("New York City"), 1) + breadCrumbLimit = ConfigManager.getBreadcrumbLimit(context) + } + + /** + * test throwing a bunch of trash, edge cases into the table and make sure that null values are + * not stored in essential fields, and that it does not break the database + * @throws Exception + */ + @Test + @Throws(Exception::class) + fun testNullValues() { + for (i in 0 until breadCrumbLimit + 10) { + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + "k", + null + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbCount( + database, + null + ).toLong(), + 0 + ) + for (i in 0 until breadCrumbLimit + 10) { + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + null, + 10L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbCount( + database, + 10L + ).toLong(), + 0 + ) + for (i in 0 until breadCrumbLimit + 10) { + BreadcrumbService.insertBreadcrumb( + database, + context, + null, + "k", + 10L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbCount( + database, + 10L + ).toLong(), + 0 + ) + for (i in 0..9) { + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + "k", + 10L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbCount( + database, + 10L + ).toLong(), + 10 + ) + for (i in 0 until breadCrumbLimit + 10) { + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + null, + 10L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbCount( + database, + 10L + ).toLong(), + 10 + ) + for (i in 0 until breadCrumbLimit + 10) { + BreadcrumbService.insertBreadcrumb( + database, + context, + null, + "k", + 10L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbCount( + database, + 10L + ).toLong(), + 10 + ) + } + + /** + * test that the new DB schema of storing stuff dependent on MPID is working + * @throws Exception + */ + @Test + @Throws(Exception::class) + fun testMpIdSpecific() { + /** + * this test won't work if you can't store breadcrumbs + */ + Assert.assertTrue(breadCrumbLimit >= 2) + val expectedCount = breadCrumbLimit + for (i in 0 until expectedCount) { + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + "apiKey", + 1L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbs( + database, + context, + 1L + ).length().toLong(), + expectedCount.toLong() + ) + Assert.assertEquals( + BreadcrumbService.getBreadcrumbs( + database, + context, + 2L + ).length().toLong(), + 0 + ) + for (i in 0 until expectedCount - 1) { + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + "apiKey", + 2L + ) + } + Assert.assertEquals( + BreadcrumbService.getBreadcrumbs( + database, + context, + 1L + ).length().toLong(), + expectedCount.toLong() + ) + Assert.assertEquals( + BreadcrumbService.getBreadcrumbs( + database, + context, + 2L + ).length().toLong(), + (expectedCount - 1).toLong() + ) + Assert.assertEquals( + BreadcrumbService.getBreadcrumbs( + database, + context, + 3L + ).length().toLong(), + 0 + ) + } + + @Test + @Throws(JSONException::class) + fun testBreadcrumbLimit() { + val deleted: MutableList = ArrayList() + for (i in 0 until breadCrumbLimit + 10) { + deleted.add( + BreadcrumbService.insertBreadcrumb( + database, + context, + message, + "apiKey", + 10L + ) + ) + } + + // make sure that 10 (number attempted to be inserted above the breadcrumb limit) entries have been deleted + deleted.removeAll(setOf(-1)) + Assert.assertEquals(deleted.size.toLong(), 10) + Assert.assertEquals( + BreadcrumbService.getBreadcrumbs( + database, + context, + 10L + ).length().toLong(), + breadCrumbLimit.toLong() + ) + } + + companion object { + private var message: BaseMPMessage? = null + private var breadCrumbLimit = 0 + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/MParticleDBManagerTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/MParticleDBManagerTest.java deleted file mode 100644 index 5eea73313..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/MParticleDBManagerTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.mparticle.internal.database.services; - -import android.os.Handler; -import android.os.Looper; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.mparticle.TypedUserAttributeListener; -import com.mparticle.UserAttributeListener; -import com.mparticle.identity.UserAttributeListenerWrapper; -import com.mparticle.testutils.AndroidUtils.Mutable; -import com.mparticle.testutils.BaseCleanInstallEachTest; -import com.mparticle.testutils.MPLatch; - -import junit.framework.Assert; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; - -public class MParticleDBManagerTest extends BaseCleanInstallEachTest{ - - @Test - public void testRemoveUserAttributes() throws Exception { - MParticleDBManager manager = new MParticleDBManager(mContext); - MParticleDBManager.UserAttributeRemoval removal = new MParticleDBManager.UserAttributeRemoval(); - removal.key = "foo"; - removal.mpId = 10L; - manager.removeUserAttribute(removal, null); - Map attributes = manager.getUserAttributes(10); - Assert.assertNull(attributes.get("foo")); - MParticleDBManager.UserAttributeResponse newAttributes = new MParticleDBManager.UserAttributeResponse(); - newAttributes.mpId = 10L; - newAttributes.attributeLists = new HashMap>(); - List attributeList = new ArrayList(); - attributeList.add("bar"); - attributeList.add("baz"); - newAttributes.attributeLists.put("foo", attributeList); - manager.setUserAttribute(newAttributes); - attributes = manager.getUserAttributes(10); - Assert.assertNotNull(attributes.get("foo")); - manager.removeUserAttribute(removal, null); - attributes = manager.getUserAttributes(10); - Assert.assertNull(attributes.get("foo")); - } - - @Test - public void testUserUserAttributeLists() throws Exception { - MParticleDBManager manager = new MParticleDBManager(mContext); - MParticleDBManager.UserAttributeRemoval removal = new MParticleDBManager.UserAttributeRemoval(); - removal.key = "foo"; - removal.mpId = 10L; - manager.removeUserAttribute(removal, null); - Map attributes = manager.getUserAttributes(10); - Assert.assertNull(attributes.get("foo")); - MParticleDBManager.UserAttributeResponse newAttributes = new MParticleDBManager.UserAttributeResponse(); - newAttributes.mpId = 10L; - newAttributes.attributeLists = new HashMap>(); - List attributeList = new ArrayList(); - attributeList.add("bar"); - attributeList.add("baz"); - newAttributes.attributeLists.put("foo", attributeList); - manager.setUserAttribute(newAttributes); - attributes = manager.getUserAttributes(10); - Assert.assertNotNull(attributes.get("foo")); - Assert.assertEquals(attributeList, attributes.get("foo")); - - attributeList = new ArrayList(); - attributeList.add("bar"); - attributeList.add("baz"); - attributeList.add("bar-2"); - newAttributes.attributeLists.clear(); - newAttributes.attributeLists.put("foo", attributeList); - manager.setUserAttribute(newAttributes); - attributes = manager.getUserAttributes(10); - Assert.assertNotNull(attributes.get("foo")); - Assert.assertEquals(attributeList, attributes.get("foo")); - - attributeList = new ArrayList(); - attributeList.add("bar-2"); - attributeList.add("bar"); - attributeList.add("baz"); - newAttributes.attributeLists.clear(); - newAttributes.attributeLists.put("foo", attributeList); - manager.setUserAttribute(newAttributes); - attributes = manager.getUserAttributes(10); - Assert.assertNotNull(attributes.get("foo")); - Assert.assertEquals(attributeList, attributes.get("foo")); - - attributeList = new ArrayList(); - attributeList.add("bar"); - newAttributes.attributeLists.clear(); - newAttributes.attributeLists.put("foo", attributeList); - manager.setUserAttribute(newAttributes); - attributes = manager.getUserAttributes(10); - Assert.assertNotNull(attributes.get("foo")); - Assert.assertEquals(attributeList, attributes.get("foo")); - } - - @Test - public void testGetUserAttributesAsync() throws InterruptedException { - startMParticle(); - - final Mutable dbAccessThread = new Mutable(null); - final MParticleDBManager manager = new MParticleDBManager(){ - @Override - public Map getUserAttributeSingles(long mpId) { - dbAccessThread.value = Thread.currentThread(); - return null; - } - - @Override - public TreeMap> getUserAttributeLists(long mpId) { - return null; - } - }; - - final Mutable latch = new Mutable(new MPLatch(1)); - final Mutable callbackThread = new Mutable(null); - - //when not on the main thread, it should callback on the current thread, and access the DB on the same thread - assertNotEquals("main", Thread.currentThread().getName()); - - TypedUserAttributeListener listener = new TypedUserAttributeListener() { - @Override - public void onUserAttributesReceived(@NonNull Map userAttributes, @NonNull Map> userAttributeLists, long mpid) { - callbackThread.value = Thread.currentThread(); - latch.value.countDown(); - } - }; - manager.getUserAttributes(new UserAttributeListenerWrapper(listener), 1); - - assertNotNull(callbackThread.value); - assertEquals(Thread.currentThread().getName(), callbackThread.value.getName()); - assertEquals(Thread.currentThread().getName(), dbAccessThread.value.getName()); - callbackThread.value = null; - dbAccessThread.value = null; - - latch.value = new MPLatch(1); - - //when run from the main thread, it should be called back on the main thread, but NOT access the DB on the same thread - TypedUserAttributeListener listener1 = new TypedUserAttributeListener() { - @Override - public void onUserAttributesReceived(@NonNull Map userAttributes, @NonNull Map> userAttributeLists, long mpid) { - callbackThread.value = Thread.currentThread(); - latch.value.countDown(); - } - }; - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - manager.getUserAttributes(new UserAttributeListenerWrapper(listener), 1); - } - }); - latch.value.await(); - - assertNotNull(callbackThread.value); - assertEquals("main", callbackThread.value.getName()); - assertNotEquals("main", dbAccessThread.value.getName()); - //it's ok if this value changes in the future, if you know what you're doing. previously - //this was being run on an AsyncTask, but it may have been leading to db locks, "messages" - //thread is know to not be an issue w/db access - assertEquals("mParticleMessageHandler", dbAccessThread.value.getName()); - } -} \ No newline at end of file diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/MParticleDBManagerTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/MParticleDBManagerTest.kt new file mode 100644 index 000000000..f76349a79 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/MParticleDBManagerTest.kt @@ -0,0 +1,156 @@ +package com.mparticle.internal.database.services + +import android.os.Looper +import com.mparticle.TypedUserAttributeListener +import com.mparticle.identity.UserAttributeListenerWrapper +import com.mparticle.internal.database.services.MParticleDBManager.UserAttributeRemoval +import com.mparticle.internal.database.services.MParticleDBManager.UserAttributeResponse +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.context +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals +import org.junit.Assert.assertNotNull + +class MParticleDBManagerTest : BaseTest() { + @org.junit.Test + @Throws(java.lang.Exception::class) + fun testRemoveUserAttributes() { + val manager = MParticleDBManager(context) + val removal = UserAttributeRemoval() + removal.key = "foo" + removal.mpId = 10L + manager.removeUserAttribute(removal, null) + var attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNull(attributes["foo"]) + val newAttributes = UserAttributeResponse() + newAttributes.mpId = 10L + newAttributes.attributeLists = java.util.HashMap>() + val attributeList = mutableListOf() + attributeList.add("bar") + attributeList.add("baz") + newAttributes.attributeLists.put("foo", attributeList) + manager.setUserAttribute(newAttributes) + attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNotNull(attributes["foo"]) + manager.removeUserAttribute(removal, null) + attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNull(attributes["foo"]) + } + + @org.junit.Test + @Throws(java.lang.Exception::class) + fun testUserUserAttributeLists() { + val manager = MParticleDBManager(context) + val removal = UserAttributeRemoval() + removal.key = "foo" + removal.mpId = 10L + manager.removeUserAttribute(removal, null) + var attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNull(attributes["foo"]) + val newAttributes = UserAttributeResponse() + newAttributes.mpId = 10L + newAttributes.attributeLists = mutableMapOf>() + var attributeList = mutableListOf() + attributeList.add("bar") + attributeList.add("baz") + newAttributes.attributeLists.put("foo", attributeList) + manager.setUserAttribute(newAttributes) + attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNotNull(attributes["foo"]) + junit.framework.Assert.assertEquals(attributeList, attributes["foo"]) + attributeList = java.util.ArrayList() + attributeList.add("bar") + attributeList.add("baz") + attributeList.add("bar-2") + newAttributes.attributeLists.clear() + newAttributes.attributeLists.put("foo", attributeList) + manager.setUserAttribute(newAttributes) + attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNotNull(attributes["foo"]) + junit.framework.Assert.assertEquals(attributeList, attributes["foo"]) + attributeList = java.util.ArrayList() + attributeList.add("bar-2") + attributeList.add("bar") + attributeList.add("baz") + newAttributes.attributeLists.clear() + newAttributes.attributeLists.put("foo", attributeList) + manager.setUserAttribute(newAttributes) + attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNotNull(attributes["foo"]) + junit.framework.Assert.assertEquals(attributeList, attributes["foo"]) + attributeList = java.util.ArrayList() + attributeList.add("bar") + newAttributes.attributeLists.clear() + newAttributes.attributeLists.put("foo", attributeList) + manager.setUserAttribute(newAttributes) + attributes = manager.getUserAttributes(10) + junit.framework.Assert.assertNotNull(attributes["foo"]) + junit.framework.Assert.assertEquals(attributeList, attributes["foo"]) + } + + @org.junit.Test + @Throws(InterruptedException::class) + fun testGetUserAttributesAsync() { + startMParticle() + val dbAccessThread = Mutable(null) + val manager: MParticleDBManager = object : MParticleDBManager() { + override fun getUserAttributeSingles(mpId: Long): java.util.TreeMap? { + dbAccessThread.value = Thread.currentThread() + return null + } + + override fun getUserAttributeLists(mpId: Long): java.util.TreeMap>? { + return null + } + } + val latch = Mutable(FailureLatch()) + val callbackThread = Mutable(null) + + // when not on the main thread, it should callback on the current thread, and access the DB on the same thread + assertNotEquals("main", Thread.currentThread().name) + var listener: TypedUserAttributeListener = object : TypedUserAttributeListener { + override fun onUserAttributesReceived( + userAttributes: Map, + userAttributeLists: Map?>, + mpid: Long + ) { + callbackThread.value = Thread.currentThread() + latch.value.countDown() + } + } + manager.getUserAttributes(UserAttributeListenerWrapper(listener), 1) + assertNotNull(callbackThread.value) + assertEquals(Thread.currentThread().name, callbackThread.value?.name) + assertEquals(Thread.currentThread().name, dbAccessThread.value?.name) + callbackThread.value = null + dbAccessThread.value = null + latch.value = FailureLatch() + + listener = object : TypedUserAttributeListener { + override fun onUserAttributesReceived( + userAttributes: Map, + userAttributeLists: Map?>, + mpid: Long + ) { + callbackThread.value = Thread.currentThread() + latch.value.countDown() + } + } + // when run from the main thread, it should be called back on the main thread, but NOT access the DB on the same thread + android.os.Handler(Looper.getMainLooper()).post( + Runnable { + manager.getUserAttributes(UserAttributeListenerWrapper(listener), 1) + } + ) + latch.value.await() + assertNotNull(callbackThread.value) + assertEquals("main", callbackThread.value?.name) + assertNotEquals("main", dbAccessThread.value?.name) + // it's ok if this value changes in the future, if you know what you're doing. previously + // this was being run on an AsyncTask, but it may have been leading to db locks, "messages" + // thread is know to not be an issue w/db access + assertEquals("mParticleMessageHandler", dbAccessThread.value?.name) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/MessageServiceTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/MessageServiceTest.java deleted file mode 100644 index 0b235feca..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/MessageServiceTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.mparticle.internal.database.services; - -import android.location.Location; - -import com.mparticle.internal.Constants; -import com.mparticle.internal.InternalSession; -import com.mparticle.internal.MessageManager; -import com.mparticle.internal.messages.BaseMPMessage; - -import org.json.JSONException; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -public class MessageServiceTest extends BaseMPServiceTest { - Long mpid1, mpid2, mpid3; - - @Before - public void before() throws Exception { - mpid1 = ran.nextLong(); - mpid2 = ran.nextLong(); - mpid3 = ran.nextLong(); - } - - @Test - public void testMessagesForUploadByMpid() throws Exception { - for (int i = 0; i < 20; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), mpid1, null, null); - } - assertEquals(MessageService.getMessagesForUpload(database, true, mpid1).size(), 20); - assertEquals(MessageService.getMessagesForUpload(database, true, Constants.TEMPORARY_MPID).size(), 0); - assertEquals(MessageService.getMessagesForUpload(database).size(), 20); - for (int i = 0; i < 30; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), Constants.TEMPORARY_MPID, null, null); - } - assertEquals(MessageService.getMessagesForUpload(database, true, mpid1).size(), 20); - assertEquals(MessageService.getMessagesForUpload(database, true, mpid2).size(), 0); - assertEquals(MessageService.getMessagesForUpload(database, true, Constants.TEMPORARY_MPID).size(), 30); - assertEquals(MessageService.getMessagesForUpload(database).size(), 20); - for (int i = 0; i < 35; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), mpid2, null, null); - } - assertEquals(MessageService.getMessagesForUpload(database, true, mpid1).size(), 20); - assertEquals(MessageService.getMessagesForUpload(database, true, mpid2).size(), 35); - assertEquals(MessageService.getMessagesForUpload(database, true, Constants.TEMPORARY_MPID).size(), 30); - assertEquals(MessageService.getMessagesForUpload(database).size(), 55); - - assertEquals(MessageService.markMessagesAsUploaded(database, Integer.MAX_VALUE), 55); - assertEquals(MessageService.getMessagesForUpload(database, true, mpid1).size(), 0); - assertEquals(MessageService.getMessagesForUpload(database, true, mpid2).size(), 0); - assertEquals(MessageService.getMessagesForUpload(database, true, Constants.TEMPORARY_MPID).size(), 30); - assertEquals(MessageService.getMessagesForUpload(database).size(), 0); - } - - @Test - public void testSessionHistoryByMpid() throws Exception { - String currentSession = UUID.randomUUID().toString(); - String previousSession = UUID.randomUUID().toString(); - for (int i = 0; i < 20; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(currentSession), mpid1, null, null); - } - for (int i = 0; i < 30; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(currentSession), Constants.TEMPORARY_MPID, null, null); - } - for (int i = 0; i < 35; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(currentSession), mpid2, null, null); - } - assertEquals(MessageService.markMessagesAsUploaded(database, Integer.MAX_VALUE), 55); - assertEquals(MessageService.getSessionHistory(database, previousSession).size(), 55); - assertEquals(MessageService.getSessionHistory(database, previousSession, true, mpid1).size(), 20); - assertEquals(MessageService.getSessionHistory(database, previousSession, true, mpid2).size(), 35); - assertEquals(MessageService.getSessionHistory(database, previousSession, false, mpid1).size(), 35); - assertEquals(MessageService.getSessionHistory(database, previousSession, false, Constants.TEMPORARY_MPID).size(), 55); - } - - @Test - public void testSessionHistoryAccuracy() throws Exception { - String currentSession = UUID.randomUUID().toString(); - String previousSession = UUID.randomUUID().toString(); - BaseMPMessage testMessage; - Long[] mpids = new Long[]{mpid1, mpid2, mpid3}; - Long testMpid; - Map testMessages = new HashMap(); - for (int i = 0; i < 100; i++) { - testMpid = mpids[mRandomUtils.randomInt(0, 3)]; - testMessage = getMpMessage(currentSession, testMpid); - testMessages.put(testMessage.toString(), testMessage); - MessageService.insertMessage(database, "apiKey",testMessage , testMpid, null, null); - } - assertEquals(MessageService.markMessagesAsUploaded(database, Integer.MAX_VALUE), 100); - List readyMessages = MessageService.getSessionHistory(database, previousSession, false, Constants.TEMPORARY_MPID); - assertEquals(readyMessages.size(), testMessages.size()); - for (MessageService.ReadyMessage readyMessage: readyMessages) { - BaseMPMessage message = testMessages.get(readyMessage.getMessage()); - assertNotNull(message); - assertEquals(readyMessage.getMpid(), message.getMpId()); - assertEquals(readyMessage.getMessage(), message.toString()); - assertEquals(readyMessage.getSessionId(), currentSession); - } - - } - - @Test - public void testMessageFlow() throws JSONException { - for (int i = 0; i < 10; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), 1, "dataplan1", 1); - } - List messageList = MessageService.getMessagesForUpload(database); - assertEquals(messageList.size(), 10); - assertEquals(MessageService.getSessionHistory(database, "123").size(), 0); - - int max = getMaxId(messageList); - int numUpldated = MessageService.markMessagesAsUploaded(database, max); - assertEquals(numUpldated, 10); - assertEquals(MessageService.getMessagesForUpload(database).size(), 0); - assertEquals(MessageService.getSessionHistory(database, "").size(), 10); - } - - @Test - public void testMessageFlowMax() throws JSONException { - for (int i = 0; i < 110; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), 1, null, null); - } - List messages = MessageService.getMessagesForUpload(database); - assertEquals(messages.size(), 100); - assertEquals(MessageService.getSessionHistory(database, "").size(), 0); - - int max = getMaxId(messages); - int numUpdated = MessageService.markMessagesAsUploaded(database, max); - assertEquals(numUpdated, 100); - assertEquals(MessageService.getSessionHistory(database, "").size(), 100); - - messages = MessageService.getMessagesForUpload(database); - max = getMaxId(messages); - numUpdated = MessageService.markMessagesAsUploaded(database, max); - assertEquals(numUpdated, 110); - assertEquals(MessageService.getSessionHistory(database, "").size(), 100); - } - - @Test - public void testDeleteOldMessages() throws JSONException { - String currentSession = UUID.randomUUID().toString(); - String newSession = UUID.randomUUID().toString(); - for (int i = 0; i < 10; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(currentSession), 1, null, null); - } - assertEquals(MessageService.markMessagesAsUploaded(database, 10), 10); - assertEquals(MessageService.getMessagesForUpload(database).size(), 0); - - MessageService.deleteOldMessages(database, currentSession); - assertEquals(MessageService.getSessionHistory(database, newSession).size(), 10); - - MessageService.deleteOldMessages(database, newSession); - assertEquals(MessageService.getSessionHistory(database, newSession).size(), 0); - } - - @Test - public void testMessagesMaxSize() throws JSONException { - for (int i = 0; i < 10; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), 1, "a", 1); - } - assertEquals(MessageService.getMessagesForUpload(database).size(), 10); - - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < Constants.LIMIT_MAX_MESSAGE_SIZE; i++) { - builder.append("ab"); - } - BaseMPMessage message = new BaseMPMessage.Builder(builder.toString()).build(new InternalSession(), new Location("New York City"), 1); - MessageService.insertMessage(database, "apiKey", message, 1, "b", 2); - - assertEquals(MessageService.getMessagesForUpload(database).size(), 10); - for (int i = 0; i < 10; i++) { - MessageService.insertMessage(database, "apiKey", getMpMessage(), 1, "c", 3); - } - assertEquals(MessageService.getMessagesForUpload(database).size(), 20); - } - - private int getMaxId(List messages) { - int max = 0; - for (MessageService.ReadyMessage message: messages) { - if (message.getMessageId() > max) { - max = message.getMessageId(); - } - } - return max; - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/MessageServiceTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/MessageServiceTest.kt new file mode 100644 index 000000000..d9ef78fe6 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/MessageServiceTest.kt @@ -0,0 +1,496 @@ +package com.mparticle.internal.database.services + +import android.location.Location +import com.mparticle.internal.Constants +import com.mparticle.internal.InternalSession +import com.mparticle.internal.database.services.MessageService.ReadyMessage +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.testing.RandomUtils +import org.json.JSONException +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.util.UUID +import kotlin.random.Random + +class MessageServiceTest : BaseMPServiceTest() { + var mpid1: Long? = null + var mpid2: Long? = null + var mpid3: Long? = null + @Before + @Throws(Exception::class) + fun before() { + mpid1 = Random.Default.nextLong() + mpid2 = Random.Default.nextLong() + mpid3 = Random.Default.nextLong() + } + + @Test + @Throws(Exception::class) + fun testMessagesForUploadByMpid() { + for (i in 0..19) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + mpid1!!, + null, + null + ) + } + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid1!! + ).size.toLong(), + 20 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + Constants.TEMPORARY_MPID + ).size.toLong(), + 0 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 20 + ) + for (i in 0..29) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + Constants.TEMPORARY_MPID, + null, + null + ) + } + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid1!! + ).size.toLong(), + 20 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid2!! + ).size.toLong(), + 0 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + Constants.TEMPORARY_MPID + ).size.toLong(), + 30 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 20 + ) + for (i in 0..34) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + mpid2!!, + null, + null + ) + } + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid1!! + ).size.toLong(), + 20 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid2!! + ).size.toLong(), + 35 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + Constants.TEMPORARY_MPID + ).size.toLong(), + 30 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 55 + ) + Assert.assertEquals( + MessageService.markMessagesAsUploaded( + database, + Int.MAX_VALUE + ).toLong(), + 55 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid1!! + ).size.toLong(), + 0 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + mpid2!! + ).size.toLong(), + 0 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload( + database, + true, + Constants.TEMPORARY_MPID + ).size.toLong(), + 30 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 0 + ) + } + + @Test + @Throws(Exception::class) + fun testSessionHistoryByMpid() { + val currentSession = UUID.randomUUID().toString() + val previousSession = UUID.randomUUID().toString() + for (i in 0..19) { + MessageService.insertMessage( + database, + "apiKey", + getMpMessage(currentSession), + mpid1!!, + null, + null + ) + } + for (i in 0..29) { + MessageService.insertMessage( + database, + "apiKey", + getMpMessage(currentSession), + Constants.TEMPORARY_MPID, + null, + null + ) + } + for (i in 0..34) { + MessageService.insertMessage( + database, + "apiKey", + getMpMessage(currentSession), + mpid2!!, + null, + null + ) + } + Assert.assertEquals( + MessageService.markMessagesAsUploaded( + database, + Int.MAX_VALUE + ).toLong(), + 55 + ) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + previousSession + ).size.toLong(), + 55 + ) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + previousSession, + true, + mpid1!! + ).size.toLong(), + 20 + ) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + previousSession, + true, + mpid2!! + ).size.toLong(), + 35 + ) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + previousSession, + false, + mpid1!! + ).size.toLong(), + 35 + ) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + previousSession, + false, + Constants.TEMPORARY_MPID + ).size.toLong(), + 55 + ) + } + + @Test + @Throws(Exception::class) + fun testSessionHistoryAccuracy() { + val currentSession = UUID.randomUUID().toString() + val previousSession = UUID.randomUUID().toString() + var testMessage: BaseMPMessage? + val mpids = arrayOf(mpid1, mpid2, mpid3) + var testMpid: Long? + val testMessages: MutableMap = HashMap() + for (i in 0..99) { + testMpid = mpids[RandomUtils.randomInt(0, 3)] + testMessage = getMpMessage(currentSession, testMpid!!) + testMessages[testMessage.toString()] = testMessage + MessageService.insertMessage( + database, + "apiKey", + testMessage, + testMpid, + null, + null + ) + } + Assert.assertEquals( + MessageService.markMessagesAsUploaded( + database, + Int.MAX_VALUE + ).toLong(), + 100 + ) + val readyMessages = MessageService.getSessionHistory( + database, + previousSession, + false, + Constants.TEMPORARY_MPID + ) + Assert.assertEquals(readyMessages.size.toLong(), testMessages.size.toLong()) + for (readyMessage in readyMessages) { + val message = testMessages[readyMessage.message] + Assert.assertNotNull(message) + Assert.assertEquals(readyMessage.mpid, message!!.mpId) + Assert.assertEquals(readyMessage.message, message.toString()) + Assert.assertEquals(readyMessage.sessionId, currentSession) + } + } + + @Test + @Throws(JSONException::class) + fun testMessageFlow() { + for (i in 0..9) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + 1, + "dataplan1", + 1 + ) + } + val messageList = MessageService.getMessagesForUpload(database) + Assert.assertEquals(messageList.size.toLong(), 10) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + "123" + ).size.toLong(), + 0 + ) + val max = getMaxId(messageList) + val numUpldated = + MessageService.markMessagesAsUploaded(database, max) + Assert.assertEquals(numUpldated.toLong(), 10) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 0 + ) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + "" + ).size.toLong(), + 10 + ) + } + + @Test + @Throws(JSONException::class) + fun testMessageFlowMax() { + for (i in 0..109) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + 1, + null, + null + ) + } + var messages = MessageService.getMessagesForUpload(database) + Assert.assertEquals(messages.size.toLong(), 100) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + "" + ).size.toLong(), + 0 + ) + var max = getMaxId(messages) + var numUpdated = + MessageService.markMessagesAsUploaded(database, max) + Assert.assertEquals(numUpdated.toLong(), 100) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + "" + ).size.toLong(), + 100 + ) + messages = MessageService.getMessagesForUpload(database) + max = getMaxId(messages) + numUpdated = + MessageService.markMessagesAsUploaded(database, max) + Assert.assertEquals(numUpdated.toLong(), 110) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + "" + ).size.toLong(), + 100 + ) + } + + @Test + @Throws(JSONException::class) + fun testDeleteOldMessages() { + val currentSession = UUID.randomUUID().toString() + val newSession = UUID.randomUUID().toString() + for (i in 0..9) { + MessageService.insertMessage( + database, + "apiKey", + getMpMessage(currentSession), + 1, + null, + null + ) + } + Assert.assertEquals( + MessageService.markMessagesAsUploaded( + database, + 10 + ).toLong(), + 10 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 0 + ) + MessageService.deleteOldMessages(database, currentSession) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + newSession + ).size.toLong(), + 10 + ) + MessageService.deleteOldMessages(database, newSession) + Assert.assertEquals( + MessageService.getSessionHistory( + database, + newSession + ).size.toLong(), + 0 + ) + } + + @Test + @Throws(JSONException::class) + fun testMessagesMaxSize() { + for (i in 0..9) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + 1, + "a", + 1 + ) + } + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 10 + ) + val builder = StringBuilder() + for (i in 0 until Constants.LIMIT_MAX_MESSAGE_SIZE) { + builder.append("ab") + } + val message = BaseMPMessage.Builder(builder.toString()) + .build(InternalSession(), Location("New York City"), 1) + MessageService.insertMessage( + database, + "apiKey", + message, + 1, + "b", + 2 + ) + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 10 + ) + for (i in 0..9) { + MessageService.insertMessage( + database, + "apiKey", + mpMessage, + 1, + "c", + 3 + ) + } + Assert.assertEquals( + MessageService.getMessagesForUpload(database).size.toLong(), + 20 + ) + } + + private fun getMaxId(messages: List): Int { + var max = 0 + for (message in messages) { + if (message.messageId > max) { + max = message.messageId + } + } + return max + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/ReportingServiceTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/ReportingServiceTest.java deleted file mode 100644 index ee0553428..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/ReportingServiceTest.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.mparticle.internal.database.services; - - -import com.mparticle.internal.Constants; -import com.mparticle.internal.JsonReportingMessage; -import com.mparticle.testutils.TestingUtils; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Random; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class ReportingServiceTest extends BaseMPServiceTest { - - @Test - public void testInsertReportingMessage() throws JSONException { - List reportingMessages = getNReportingMessages(20, "123"); - for (JsonReportingMessage reportingMessage: reportingMessages) { - ReportingService.insertReportingMessage(database, reportingMessage, 2L); - } - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 2L).size(), 20); - assertEquals(ReportingService.getReportingMessagesForUpload(database).size(), 20); - } - - @Test - public void testInsertReportingMessageMpIdSpecific() throws JSONException { - for (JsonReportingMessage reportingMessage: getNReportingMessages(2, "123")) { - ReportingService.insertReportingMessage(database, reportingMessage, 2L); - } - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 2L).size(), 2); - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 3L).size(), 0); - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 4L).size(), 0); - assertEquals(ReportingService.getReportingMessagesForUpload(database).size(), 2); - for (JsonReportingMessage reportingMessage: getNReportingMessages(3, "123")) { - ReportingService.insertReportingMessage(database, reportingMessage, 3L); - } - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 2L).size(), 2); - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 3L).size(), 3); - assertEquals(ReportingService.getReportingMessagesForUpload(database, false, 4L).size(), 5); - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 4L).size(), 0); - assertEquals(ReportingService.getReportingMessagesForUpload(database).size(), 5); - for (JsonReportingMessage reportingMessage: getNReportingMessages(3, "123")) { - ReportingService.insertReportingMessage(database, reportingMessage, Constants.TEMPORARY_MPID); - } - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 2L).size(), 2); - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, 3L).size(), 3); - assertEquals(ReportingService.getReportingMessagesForUpload(database, true, Constants.TEMPORARY_MPID).size(), 3); - assertEquals(ReportingService.getReportingMessagesForUpload(database, false, 4L).size(), 8); - assertEquals(ReportingService.getReportingMessagesForUpload(database).size(), 5); - } - - @Test - public void testDeleteReportingMessages() throws JSONException { - for (JsonReportingMessage reportingMessage: getNReportingMessages(2)) { - ReportingService.insertReportingMessage(database, reportingMessage, 2L); - } - for (JsonReportingMessage reportingMessage: getNReportingMessages(1)) { - ReportingService.insertReportingMessage(database, reportingMessage, 3L); - } - List messagesFor2 = ReportingService.getReportingMessagesForUpload(database, true, 2L); - List messagesFor3 = ReportingService.getReportingMessagesForUpload(database, true, 3L); - assertEquals(messagesFor2.size(), 2); - assertEquals(messagesFor3.size(), 1); - - ReportingService.deleteReportingMessage(database, messagesFor2.get(0).getReportingMessageId()); - - messagesFor2 = ReportingService.getReportingMessagesForUpload(database, true, 2L); - messagesFor3 = ReportingService.getReportingMessagesForUpload(database, true, 3L); - assertEquals(messagesFor2.size(), 1); - assertEquals(messagesFor3.size(), 1); - - ReportingService.deleteReportingMessage(database, messagesFor3.get(0).getReportingMessageId()); - - - messagesFor2 = ReportingService.getReportingMessagesForUpload(database, true, 2L); - messagesFor3 = ReportingService.getReportingMessagesForUpload(database, true, 3L); - assertEquals(messagesFor2.size(), 1); - assertEquals(messagesFor3.size(), 0); - } - - - @Test - public void testEntryIntegrity() throws JSONException { - List jsonReportingMessages = getNReportingMessages(2); - for (JsonReportingMessage reportingMessage: jsonReportingMessages) { - ReportingService.insertReportingMessage(database, reportingMessage, 1L); - } - List reportingMessages = ReportingService.getReportingMessagesForUpload(database, true, 1L); - Collections.sort(reportingMessages, new Comparator() { - @Override - public int compare(ReportingService.ReportingMessage o1, ReportingService.ReportingMessage o2) { - try { - return ((Integer)o1.getMsgObject().getInt("a random Number")).compareTo(o2.getMsgObject().getInt("a random Number")) ; - } catch (JSONException e) { - e.printStackTrace(); - } - return -1; - } - }); - - Collections.sort(jsonReportingMessages, new Comparator() { - @Override - public int compare(JsonReportingMessage o1, JsonReportingMessage o2) { - try { - return ((Integer)o1.toJson().getInt("a random Number")).compareTo(o2.toJson().getInt("a random Number")); - } catch (JSONException e) { - e.printStackTrace(); - } - return -1; - } - }); - - assertEquals(jsonReportingMessages.size(), reportingMessages.size()); - - for (int i = 0; i < jsonReportingMessages.size() && i < reportingMessages.size(); i++) { - assertTrue(equals(jsonReportingMessages.get(i), reportingMessages.get(i))); - } - } - - - - private List getNReportingMessages(int n) { - return getNReportingMessages(n, null); - } - - private List getNReportingMessages(int n, String sessionId) { - List reportingMessages = new ArrayList(); - for (int i = 0; i < n; i++) { - reportingMessages.add(TestingUtils.getInstance().getRandomReportingMessage(sessionId != null ? sessionId : String.valueOf(ran.nextInt()))); - } - return reportingMessages; - } - - private boolean equals(JsonReportingMessage jsonReportingMessage, ReportingService.ReportingMessage reportingMessage) { - String reportingString = reportingMessage.getMsgObject().toString(); - String origStirng = jsonReportingMessage.toJson().toString(); - - return reportingMessage.getSessionId().equals(jsonReportingMessage.getSessionId()) && - reportingString.equals(origStirng); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/ReportingServiceTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/ReportingServiceTest.kt new file mode 100644 index 000000000..634ce3335 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/ReportingServiceTest.kt @@ -0,0 +1,298 @@ +package com.mparticle.internal.database.services + +import com.mparticle.internal.Constants +import com.mparticle.internal.JsonReportingMessage +import com.mparticle.internal.database.tables.ReportingTableTest +import org.json.JSONException +import org.junit.Assert +import org.junit.Test +import java.util.Collections +import kotlin.random.Random + +class ReportingServiceTest : BaseMPServiceTest() { + @Test + @Throws(JSONException::class) + fun testInsertReportingMessage() { + val reportingMessages: List = getNReportingMessages(20, "123") + for (reportingMessage in reportingMessages) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + 2L + ) + } + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ).size.toLong(), + 20 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload(database).size.toLong(), + 20 + ) + } + + @Test + @Throws(JSONException::class) + fun testInsertReportingMessageMpIdSpecific() { + for (reportingMessage in getNReportingMessages(2, "123")) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + 2L + ) + } + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ).size.toLong(), + 2 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 3L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 4L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload(database).size.toLong(), + 2 + ) + for (reportingMessage in getNReportingMessages(3, "123")) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + 3L + ) + } + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ).size.toLong(), + 2 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 3L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + false, + 4L + ).size.toLong(), + 5 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 4L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload(database).size.toLong(), + 5 + ) + for (reportingMessage in getNReportingMessages(3, "123")) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + Constants.TEMPORARY_MPID + ) + } + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ).size.toLong(), + 2 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + 3L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + true, + Constants.TEMPORARY_MPID + ).size.toLong(), + 3 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload( + database, + false, + 4L + ).size.toLong(), + 8 + ) + Assert.assertEquals( + ReportingService.getReportingMessagesForUpload(database).size.toLong(), + 5 + ) + } + + @Test + @Throws(JSONException::class) + fun testDeleteReportingMessages() { + for (reportingMessage in getNReportingMessages(2)) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + 2L + ) + } + for (reportingMessage in getNReportingMessages(1)) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + 3L + ) + } + var messagesFor2 = ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ) + var messagesFor3 = ReportingService.getReportingMessagesForUpload( + database, + true, + 3L + ) + Assert.assertEquals(messagesFor2.size.toLong(), 2) + Assert.assertEquals(messagesFor3.size.toLong(), 1) + ReportingService.deleteReportingMessage( + database, + messagesFor2[0].reportingMessageId + ) + messagesFor2 = ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ) + messagesFor3 = ReportingService.getReportingMessagesForUpload( + database, + true, + 3L + ) + Assert.assertEquals(messagesFor2.size.toLong(), 1) + Assert.assertEquals(messagesFor3.size.toLong(), 1) + ReportingService.deleteReportingMessage( + database, + messagesFor3[0].reportingMessageId + ) + messagesFor2 = ReportingService.getReportingMessagesForUpload( + database, + true, + 2L + ) + messagesFor3 = ReportingService.getReportingMessagesForUpload( + database, + true, + 3L + ) + Assert.assertEquals(messagesFor2.size.toLong(), 1) + Assert.assertEquals(messagesFor3.size.toLong(), 0) + } + + @Test + @Throws(JSONException::class) + fun testEntryIntegrity() { + val jsonReportingMessages: List = getNReportingMessages(2) + for (reportingMessage in jsonReportingMessages) { + ReportingService.insertReportingMessage( + database, + reportingMessage, + 1L + ) + } + val reportingMessages = ReportingService.getReportingMessagesForUpload( + database, + true, + 1L + ) + Collections.sort( + reportingMessages, + java.util.Comparator { o1, o2 -> + try { + return@Comparator o1.msgObject.getInt("a random Number") + .compareTo(o2.msgObject.getInt("a random Number")) + } catch (e: JSONException) { + e.printStackTrace() + } + -1 + } + ) + Collections.sort( + jsonReportingMessages, + java.util.Comparator { o1, o2 -> + try { + return@Comparator o1.toJson().getInt("a random Number").compareTo( + o2.toJson().getInt("a random Number") + ) + } catch (e: JSONException) { + e.printStackTrace() + } + -1 + } + ) + Assert.assertEquals(jsonReportingMessages.size.toLong(), reportingMessages.size.toLong()) + var i = 0 + while (i < jsonReportingMessages.size && i < reportingMessages.size) { + Assert.assertTrue(equals(jsonReportingMessages[i], reportingMessages[i])) + i++ + } + } + + private fun getNReportingMessages(n: Int): List { + return getNReportingMessages(n, null) + } + + private fun getNReportingMessages(n: Int, sessionId: String?): List { + val reportingMessages: MutableList = ArrayList() + for (i in 0 until n) { + reportingMessages.add( + ReportingTableTest.getRandomReportingMessage(sessionId ?: Random.Default.nextInt().toString()) + ) + } + return reportingMessages + } + + private fun equals( + jsonReportingMessage: JsonReportingMessage, + reportingMessage: ReportingService.ReportingMessage + ): Boolean { + val reportingString = reportingMessage.msgObject.toString() + val origStirng: String = jsonReportingMessage.toJson().toString() + return reportingMessage.sessionId == jsonReportingMessage.sessionId && reportingString == origStirng + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/SessionServiceTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/SessionServiceTest.java deleted file mode 100644 index 89c66e82d..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/SessionServiceTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.mparticle.internal.database.services; - -import android.database.Cursor; -import androidx.annotation.Nullable; - -import com.mparticle.internal.BatchId; -import com.mparticle.internal.MessageBatch; -import com.mparticle.internal.database.tables.SessionTable; -import com.mparticle.internal.messages.BaseMPMessage; - -import junit.framework.Assert; - -import org.json.JSONObject; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class SessionServiceTest extends BaseMPServiceTest { - - @Test - public void testUpdateSessionInstallReferrer() throws Exception { - JSONObject fooObject = new JSONObject(); - String sessionId = UUID.randomUUID().toString(); - fooObject.put("foo", "bar"); - BaseMPMessage mpMessage = getMpMessage(sessionId); - SessionService.insertSession(database, mpMessage, "foo-app-key", fooObject.toString(), fooObject.toString(), 1); - fooObject = new JSONObject(); - String randomId = UUID.randomUUID().toString(); - fooObject.put("foo", randomId); - SessionService.updateSessionInstallReferrer(database, fooObject, sessionId); - Cursor cursor = null; - try { - cursor = SessionService.getSessions(database); - while (cursor.moveToNext()) { - String currentSessionId = cursor.getString(cursor.getColumnIndexOrThrow(SessionTable.SessionTableColumns.SESSION_ID)); - String appInfo = cursor.getString(cursor.getColumnIndexOrThrow(SessionTable.SessionTableColumns.APP_INFO)); - if (sessionId.equals(currentSessionId)) { - JSONObject appInfoObject = new JSONObject(appInfo); - assertEquals(randomId, appInfoObject.getString("foo")); - return; - } - } - }finally { - if (cursor != null && !cursor.isClosed()) { - cursor.close(); - } - } - Assert.fail("Failed to find updated app customAttributes object."); - } - - @Test - public void flattenMessagesByBatchIdTest() { - Map batchMap = new HashMap(); - batchMap.put(new BatchId(ran.nextLong(), "1", "a", 1), new MockMessageBatch(1)); - batchMap.put(new BatchId(ran.nextLong(), "2", null, null), new MockMessageBatch(2)); - batchMap.put(new BatchId(ran.nextLong(), "1", "a", 2), new MockMessageBatch(3)); - batchMap.put(new BatchId(ran.nextLong(), "1", "ab", null), new MockMessageBatch(4)); - batchMap.put(new BatchId(ran.nextLong(), "2", null, 3), new MockMessageBatch(5)); - batchMap.put(new BatchId(ran.nextLong(), "3", null, 3), new MockMessageBatch(6)); - batchMap.put(new BatchId(ran.nextLong(), "1", null, 3), new MockMessageBatch(7)); - - Map> batchBySessionId = SessionService.flattenBySessionId(batchMap); - assertEquals(4, batchBySessionId.get("1").size()); - assertEquals(2, batchBySessionId.get("2").size()); - assertEquals(1, batchBySessionId.get("3").size()); - - //make sure the elements in the list are unique..no inadvertent copies - List session1Batches = new ArrayList(batchBySessionId.get("1")); - int size = session1Batches.size(); - for (MessageBatch messageBatch: session1Batches) { - batchBySessionId.get("1").remove(messageBatch); - assertEquals(--size, batchBySessionId.get("1").size()); - } - } - - class MockMessageBatch extends MessageBatch { - int id; - - public MockMessageBatch(int id) { - super(); - this.id = id; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof MockMessageBatch) { - return ((Integer)id).equals(((MockMessageBatch)obj).id); - } else { - return super.equals(obj); - } - } - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/SessionServiceTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/SessionServiceTest.kt new file mode 100644 index 000000000..063363fd7 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/SessionServiceTest.kt @@ -0,0 +1,95 @@ +package com.mparticle.internal.database.services + +import android.database.Cursor +import com.mparticle.internal.BatchId +import com.mparticle.internal.MessageBatch +import com.mparticle.internal.database.tables.SessionTable +import org.json.JSONObject +import org.junit.Assert +import org.junit.Assert.fail +import org.junit.Test +import java.util.UUID +import kotlin.random.Random + +class SessionServiceTest : BaseMPServiceTest() { + @Test + @Throws(Exception::class) + fun testUpdateSessionInstallReferrer() { + var fooObject = JSONObject() + val sessionId = UUID.randomUUID().toString() + fooObject.put("foo", "bar") + val mpMessage = getMpMessage(sessionId) + SessionService.insertSession( + database, + mpMessage, + "foo-app-key", + fooObject.toString(), + fooObject.toString(), + 1 + ) + fooObject = JSONObject() + val randomId = UUID.randomUUID().toString() + fooObject.put("foo", randomId) + SessionService.updateSessionInstallReferrer( + database, + fooObject, + sessionId + ) + var cursor: Cursor? = null + try { + cursor = SessionService.getSessions(database) + while (cursor.moveToNext()) { + val currentSessionId = + cursor.getString(cursor.getColumnIndexOrThrow(SessionTable.SessionTableColumns.SESSION_ID)) + val appInfo = + cursor.getString(cursor.getColumnIndexOrThrow(SessionTable.SessionTableColumns.APP_INFO)) + if (sessionId == currentSessionId) { + val appInfoObject = JSONObject(appInfo) + Assert.assertEquals(randomId, appInfoObject.getString("foo")) + return + } + } + } finally { + if (cursor != null && !cursor.isClosed) { + cursor.close() + } + } + fail("Failed to find updated app customAttributes object.") + } + + @Test + fun flattenMessagesByBatchIdTest() { + val batchMap: MutableMap = HashMap() + batchMap[BatchId(Random.Default.nextLong(), "1", "a", 1)] = MockMessageBatch(1) + batchMap[BatchId(Random.Default.nextLong(), "2", null, null)] = MockMessageBatch(2) + batchMap[BatchId(Random.Default.nextLong(), "1", "a", 2)] = MockMessageBatch(3) + batchMap[BatchId(Random.Default.nextLong(), "1", "ab", null)] = MockMessageBatch(4) + batchMap[BatchId(Random.Default.nextLong(), "2", null, 3)] = MockMessageBatch(5) + batchMap[BatchId(Random.Default.nextLong(), "3", null, 3)] = MockMessageBatch(6) + batchMap[BatchId(Random.Default.nextLong(), "1", null, 3)] = MockMessageBatch(7) + val batchBySessionId = SessionService.flattenBySessionId(batchMap) + Assert.assertEquals(4, batchBySessionId["1"]!!.size.toLong()) + Assert.assertEquals(2, batchBySessionId["2"]!!.size.toLong()) + Assert.assertEquals(1, batchBySessionId["3"]!!.size.toLong()) + + // make sure the elements in the list are unique..no inadvertent copies + val session1Batches = mutableListOf( + batchBySessionId["1"] + ) + var size = session1Batches.size + for (messageBatch in session1Batches) { + batchBySessionId["1"]!!.removeAll(messageBatch ?: listOf()) + Assert.assertEquals(--size, batchBySessionId["1"]!!.size) + } + } + + internal inner class MockMessageBatch(var id: Int) : MessageBatch() { + override fun equals(other: Any?): Boolean { + return if (other is MockMessageBatch) { + id == other.id + } else { + super.equals(other) + } + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/UserAttributesServiceTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/services/UserAttributesServiceTest.java deleted file mode 100644 index b802d20e2..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/services/UserAttributesServiceTest.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.mparticle.internal.database.services; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class UserAttributesServiceTest extends BaseMPServiceTest { - @Test - public void testStoreByMpid() { - for (int i = 0; i < 20; i++) { - UserAttributesService.insertAttribute(database, String.valueOf(ran.nextInt()), String.valueOf(ran.nextInt()), System.currentTimeMillis(), false, 3L); - } - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 20); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 4L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 4L).size(), 0); - for (int i = 0; i < 30; i++) { - UserAttributesService.insertAttribute(database, String.valueOf(ran.nextInt()), String.valueOf(ran.nextInt()), System.currentTimeMillis(), false, 4L); - } - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 20); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 4L).size(), 30); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 4L).size(), 0); - for (int i = 0; i < 15; i++) { - UserAttributesService.insertAttribute(database, String.valueOf(ran.nextInt()), String.valueOf(ran.nextInt()), System.currentTimeMillis(), true, 3L); - } - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 20); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 4L).size(), 30); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 15); - assertEquals(UserAttributesService.getUserAttributesLists(database, 4L).size(), 0); - for (int i = 0; i < 30; i++) { - UserAttributesService.insertAttribute(database, String.valueOf(ran.nextInt()), String.valueOf(ran.nextInt()), System.currentTimeMillis(), true, 5L); - } - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 20); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 4L).size(), 30); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 15); - assertEquals(UserAttributesService.getUserAttributesLists(database, 4L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 5L).size(), 30); - } - - @Test - public void testDeleteByMpid() { - testDeleteByMpid(true); - } - - private void testDeleteByMpid(boolean repeat) { - for (int i = 0; i < 3; i++) { - UserAttributesService.insertAttribute(database, "key" + i, String.valueOf(ran.nextInt()), System.currentTimeMillis(), false, 2L); - } - for (int i = 0; i < 3; i++) { - UserAttributesService.insertAttribute(database, "key" + i, String.valueOf(ran.nextInt()), System.currentTimeMillis(), false, 3L); - } - for (int i = 3; i < 6; i++) { - UserAttributesService.insertAttribute(database, "key" + i, String.valueOf(ran.nextInt()), System.currentTimeMillis(), true, 2L); - } - for (int i = 3; i < 6; i++) { - UserAttributesService.insertAttribute(database, "key" + i, String.valueOf(ran.nextInt()), System.currentTimeMillis(), true, 3L); - } - assertEquals(UserAttributesService.getUserAttributesSingles(database, 2L).size(), 3); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 3); - assertEquals(UserAttributesService.getUserAttributesLists(database, 2L).size(), 3); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 3); - - UserAttributesService.deleteAttributes(database, "key1", 2L); - UserAttributesService.deleteAttributes(database, "key4", 3L); - - assertEquals(UserAttributesService.getUserAttributesSingles(database, 2L).size(), 2); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 3); - assertEquals(UserAttributesService.getUserAttributesLists(database, 2L).size(), 3); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 2); - - for (int i = 0; i < 6; i++) { - UserAttributesService.deleteAttributes(database, "key" + i, 2L); - } - - assertEquals(UserAttributesService.getUserAttributesSingles(database, 2L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 3); - assertEquals(UserAttributesService.getUserAttributesLists(database, 2L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 2); - - for (int i = 0; i < 6; i++) { - UserAttributesService.deleteAttributes(database, "key" + i, 3L); - } - - assertEquals(UserAttributesService.getUserAttributesSingles(database, 2L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesSingles(database, 3L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 2L).size(), 0); - assertEquals(UserAttributesService.getUserAttributesLists(database, 3L).size(), 0); - - - //easy way to test to make sure that insert is working properly after delete, just run the same test again - if (repeat) { - testDeleteByMpid(false); - } - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/services/UserAttributesServiceTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/services/UserAttributesServiceTest.kt new file mode 100644 index 000000000..79b5fe627 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/services/UserAttributesServiceTest.kt @@ -0,0 +1,353 @@ +package com.mparticle.internal.database.services + +import org.junit.Assert +import org.junit.Test +import java.lang.String +import kotlin.Boolean +import kotlin.random.Random + +class UserAttributesServiceTest : BaseMPServiceTest() { + @Test + fun testStoreByMpid() { + for (i in 0..19) { + UserAttributesService.insertAttribute( + database, + String.valueOf(Random.Default.nextInt()), + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + false, + 3L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 20 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 4L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 4L + ).size.toLong(), + 0 + ) + for (i in 0..29) { + UserAttributesService.insertAttribute( + database, + String.valueOf(Random.Default.nextInt()), + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + false, + 4L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 20 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 4L + ).size.toLong(), + 30 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 4L + ).size.toLong(), + 0 + ) + for (i in 0..14) { + UserAttributesService.insertAttribute( + database, + String.valueOf(Random.Default.nextInt()), + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + true, + 3L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 20 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 4L + ).size.toLong(), + 30 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 15 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 4L + ).size.toLong(), + 0 + ) + for (i in 0..29) { + UserAttributesService.insertAttribute( + database, + String.valueOf(Random.Default.nextInt()), + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + true, + 5L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 20 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 4L + ).size.toLong(), + 30 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 15 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 4L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 5L + ).size.toLong(), + 30 + ) + } + + @Test + fun testDeleteByMpid() { + testDeleteByMpid(true) + } + + private fun testDeleteByMpid(repeat: Boolean) { + for (i in 0..2) { + UserAttributesService.insertAttribute( + database, + "key$i", + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + false, + 2L + ) + } + for (i in 0..2) { + UserAttributesService.insertAttribute( + database, + "key$i", + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + false, + 3L + ) + } + for (i in 3..5) { + UserAttributesService.insertAttribute( + database, + "key$i", + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + true, + 2L + ) + } + for (i in 3..5) { + UserAttributesService.insertAttribute( + database, + "key$i", + String.valueOf(Random.Default.nextInt()), + System.currentTimeMillis(), + true, + 3L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 2L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 2L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 3 + ) + UserAttributesService.deleteAttributes(database, "key1", 2L) + UserAttributesService.deleteAttributes(database, "key4", 3L) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 2L + ).size.toLong(), + 2 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 2L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 2 + ) + for (i in 0..5) { + UserAttributesService.deleteAttributes( + database, + "key$i", + 2L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 2L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 3 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 2L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 2 + ) + for (i in 0..5) { + UserAttributesService.deleteAttributes( + database, + "key$i", + 3L + ) + } + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 2L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesSingles( + database, + 3L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 2L + ).size.toLong(), + 0 + ) + Assert.assertEquals( + UserAttributesService.getUserAttributesLists( + database, + 3L + ).size.toLong(), + 0 + ) + + // easy way to test to make sure that insert is working properly after delete, just run the same test again + if (repeat) { + testDeleteByMpid(false) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BaseTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BaseTableTest.java deleted file mode 100644 index 13bf3ec12..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BaseTableTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; -import androidx.test.platform.app.InstrumentationRegistry; - -import com.mparticle.internal.database.TestSQLiteOpenHelper; -import com.mparticle.testutils.BaseCleanInstallEachTest; -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Before; - -import com.mparticle.testutils.MPLatch; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class BaseTableTest extends BaseCleanInstallEachTest { - public static final String DB_NAME = "test_database"; - CountDownLatch onCreateLatch = new MPLatch(1); - CountDownLatch onUpgradeLatch = new MPLatch(1); - - protected void runTest(SQLiteOpenHelperWrapper helper) throws InterruptedException { - runTest(helper, 6); - } - - protected void runTest(SQLiteOpenHelperWrapper helper, int oldVersion) throws InterruptedException { - InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase(DB_NAME); - TestSQLiteOpenHelper openHelper = new TestSQLiteOpenHelper(helper, DB_NAME, oldVersion); - openHelper.getWritableDatabase(); - openHelper.onCreateLatch.await(); - openHelper = new TestSQLiteOpenHelper(helper, DB_NAME, MParticleDatabaseHelper.DB_VERSION); - openHelper.getWritableDatabase(); - if (oldVersion < MParticleDatabaseHelper.DB_VERSION) { - openHelper.onUpgradeLatch.await(); - } - InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase(DB_NAME); - } - - @Before - public final void before() throws Exception { - deleteTestingDatabase(); - } - - protected void deleteTestingDatabase() { - InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase(DB_NAME); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BaseTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BaseTableTest.kt new file mode 100644 index 000000000..c9ece6fe2 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BaseTableTest.kt @@ -0,0 +1,38 @@ +package com.mparticle.internal.database.tables + +import androidx.test.platform.app.InstrumentationRegistry +import com.mparticle.internal.database.TestSQLiteOpenHelper +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import com.mparticle.testing.BaseTest +import org.junit.Before + +open class BaseTableTest : BaseTest() { + + @Throws(InterruptedException::class) + protected fun runTest(helper: SQLiteOpenHelperWrapper, oldVersion: Int = 6) { + InstrumentationRegistry.getInstrumentation().targetContext.deleteDatabase(DB_NAME) + var openHelper = TestSQLiteOpenHelper(helper, DB_NAME, oldVersion) + openHelper.writableDatabase + openHelper.onCreateLatch.await() + openHelper = TestSQLiteOpenHelper(helper, DB_NAME, MParticleDatabaseHelper.DB_VERSION) + openHelper.writableDatabase + if (oldVersion < MParticleDatabaseHelper.DB_VERSION) { + openHelper.onUpgradeLatch.await() + } + InstrumentationRegistry.getInstrumentation().targetContext.deleteDatabase(DB_NAME) + } + + @Before + @Throws(Exception::class) + fun before() { + deleteTestingDatabase() + } + + protected fun deleteTestingDatabase() { + InstrumentationRegistry.getInstrumentation().targetContext.deleteDatabase(DB_NAME) + } + + companion object { + const val DB_NAME = "test_database" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BreadcrumbTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BreadcrumbTableTest.java deleted file mode 100644 index 11ee182a6..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BreadcrumbTableTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; -import android.provider.BaseColumns; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Test; - -public class BreadcrumbTableTest extends BaseTableTest{ - public static final String old_CREATE_BREADCRUMBS_DDL = - "CREATE TABLE IF NOT EXISTS " + BreadcrumbTable.BreadcrumbTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - BreadcrumbTable.BreadcrumbTableColumns.SESSION_ID + " STRING NOT NULL, " + - BreadcrumbTable.BreadcrumbTableColumns.API_KEY + " STRING NOT NULL, " + - BreadcrumbTable.BreadcrumbTableColumns.MESSAGE + " TEXT, " + - BreadcrumbTable.BreadcrumbTableColumns.CREATED_AT + " INTEGER NOT NULL, " + - BreadcrumbTable.BreadcrumbTableColumns.CF_UUID + " TEXT" + - ");"; - - @Test - public void createTableTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(BreadcrumbTable.CREATE_BREADCRUMBS_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BreadcrumbTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BreadcrumbTableTest.kt new file mode 100644 index 000000000..517e22709 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/BreadcrumbTableTest.kt @@ -0,0 +1,33 @@ +package com.mparticle.internal.database.tables + +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import org.junit.Test + +class BreadcrumbTableTest : BaseTableTest() { + @Test + @Throws(InterruptedException::class) + fun createTableTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(BreadcrumbTable.CREATE_BREADCRUMBS_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } + + companion object { + const val old_CREATE_BREADCRUMBS_DDL = + "CREATE TABLE IF NOT EXISTS " + BreadcrumbTable.BreadcrumbTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + BreadcrumbTable.BreadcrumbTableColumns.SESSION_ID + " STRING NOT NULL, " + + BreadcrumbTable.BreadcrumbTableColumns.API_KEY + " STRING NOT NULL, " + + BreadcrumbTable.BreadcrumbTableColumns.MESSAGE + " TEXT, " + + BreadcrumbTable.BreadcrumbTableColumns.CREATED_AT + " INTEGER NOT NULL, " + + BreadcrumbTable.BreadcrumbTableColumns.CF_UUID + " TEXT" + + ");" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/MessageTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/MessageTableTest.java deleted file mode 100644 index a2852cc25..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/MessageTableTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; -import android.os.Message; -import android.provider.BaseColumns; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Test; - -public class MessageTableTest extends BaseTableTest { - public static final String old_no_mpid_CREATE_MESSAGES_DDL = - "CREATE TABLE IF NOT EXISTS " + MessageTable.MessageTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - MessageTable.MessageTableColumns.SESSION_ID + " STRING NOT NULL, " + - MessageTable.MessageTableColumns.API_KEY + " STRING NOT NULL, " + - MessageTable.MessageTableColumns.MESSAGE + " TEXT, " + - MessageTable.MessageTableColumns.STATUS + " INTEGER, " + - MessageTable.MessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + - MessageTable.MessageTableColumns.MESSAGE_TYPE + " TEXT, " + - MessageTable.MessageTableColumns.CF_UUID + " TEXT" + - ");"; - - private static final String old_no_dp_CREATE_MESSAGES_DDL = "CREATE TABLE IF NOT EXISTS " + MessageTable.MessageTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - MessageTable.MessageTableColumns.SESSION_ID + " STRING NOT NULL, " + - MessageTable.MessageTableColumns.API_KEY + " STRING NOT NULL, " + - MessageTable.MessageTableColumns.MESSAGE + " TEXT, " + - MessageTable.MessageTableColumns.STATUS + " INTEGER, " + - MessageTable.MessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + - MessageTable.MessageTableColumns.MESSAGE_TYPE + " TEXT, " + - MessageTable.MessageTableColumns.CF_UUID + " TEXT, " + - MessageTable.MessageTableColumns.MP_ID + " INTEGER " + - ");"; - - - @Test - public void createTableTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(MessageTable.CREATE_MESSAGES_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - //do nothing - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } - - @Test - public void addDataplanColumnsTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(old_no_dp_CREATE_MESSAGES_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - database.execSQL(MessageTable.ADD_DATAPLAN_ID_COLUMN); - database.execSQL(MessageTable.ADD_DATAPLAN_VERSION_COLUMN); - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/MessageTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/MessageTableTest.kt new file mode 100644 index 000000000..237179db9 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/MessageTableTest.kt @@ -0,0 +1,67 @@ +package com.mparticle.internal.database.tables + +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import org.junit.Test + +class MessageTableTest : BaseTableTest() { + @Test + @Throws(InterruptedException::class) + fun createTableTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(MessageTable.CREATE_MESSAGES_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + // do nothing + } + + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } + + @Test + @Throws(InterruptedException::class) + fun addDataplanColumnsTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(old_no_dp_CREATE_MESSAGES_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + database.execSQL(MessageTable.ADD_DATAPLAN_ID_COLUMN) + database.execSQL(MessageTable.ADD_DATAPLAN_VERSION_COLUMN) + } + + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } + + companion object { + const val old_no_mpid_CREATE_MESSAGES_DDL = + "CREATE TABLE IF NOT EXISTS " + MessageTable.MessageTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + MessageTable.MessageTableColumns.SESSION_ID + " STRING NOT NULL, " + + MessageTable.MessageTableColumns.API_KEY + " STRING NOT NULL, " + + MessageTable.MessageTableColumns.MESSAGE + " TEXT, " + + MessageTable.MessageTableColumns.STATUS + " INTEGER, " + + MessageTable.MessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + + MessageTable.MessageTableColumns.MESSAGE_TYPE + " TEXT, " + + MessageTable.MessageTableColumns.CF_UUID + " TEXT" + + ");" + private const val old_no_dp_CREATE_MESSAGES_DDL = + "CREATE TABLE IF NOT EXISTS " + MessageTable.MessageTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + MessageTable.MessageTableColumns.SESSION_ID + " STRING NOT NULL, " + + MessageTable.MessageTableColumns.API_KEY + " STRING NOT NULL, " + + MessageTable.MessageTableColumns.MESSAGE + " TEXT, " + + MessageTable.MessageTableColumns.STATUS + " INTEGER, " + + MessageTable.MessageTableColumns.CREATED_AT + " INTEGER NOT NULL, " + + MessageTable.MessageTableColumns.MESSAGE_TYPE + " TEXT, " + + MessageTable.MessageTableColumns.CF_UUID + " TEXT, " + + MessageTable.MessageTableColumns.MP_ID + " INTEGER " + + ");" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/ReportingTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/ReportingTableTest.java deleted file mode 100644 index 390466ee6..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/ReportingTableTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; -import android.provider.BaseColumns; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Test; - -public class ReportingTableTest extends BaseTableTest { - - public static final String old_CREATE_REPORTING_DDL = - "CREATE TABLE IF NOT EXISTS " + ReportingTable.ReportingTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - ReportingTable.ReportingTableColumns.MODULE_ID + " INTEGER NOT NULL, " + - ReportingTable.ReportingTableColumns.MESSAGE + " TEXT NOT NULL, " + - ReportingTable.ReportingTableColumns.SESSION_ID + " STRING NOT NULL, " + - ReportingTable.ReportingTableColumns.CREATED_AT + " INTEGER NOT NULL" + - ");"; - - @Test - public void createTableTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(ReportingTable.CREATE_REPORTING_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/ReportingTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/ReportingTableTest.kt new file mode 100644 index 000000000..defb8c9d5 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/ReportingTableTest.kt @@ -0,0 +1,73 @@ +package com.mparticle.internal.database.tables + +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import com.mparticle.internal.JsonReportingMessage +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import org.json.JSONObject +import org.junit.Test +import java.util.Random + +class ReportingTableTest : BaseTableTest() { + @Test + @Throws(InterruptedException::class) + fun createTableTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(ReportingTable.CREATE_REPORTING_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } + + companion object { + const val old_CREATE_REPORTING_DDL = + "CREATE TABLE IF NOT EXISTS " + ReportingTable.ReportingTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ReportingTable.ReportingTableColumns.MODULE_ID + " INTEGER NOT NULL, " + + ReportingTable.ReportingTableColumns.MESSAGE + " TEXT NOT NULL, " + + ReportingTable.ReportingTableColumns.SESSION_ID + " STRING NOT NULL, " + + ReportingTable.ReportingTableColumns.CREATED_AT + " INTEGER NOT NULL" + + ");" + + fun getRandomReportingMessage(sessionId: String): JsonReportingMessage { + val ran = Random() + return object : JsonReportingMessage { + var randomNumber = 0 + override fun setDevMode(development: Boolean) { + // do nothing + } + + override fun getTimestamp(): Long { + return System.currentTimeMillis() - 100 + } + + override fun getModuleId(): Int { + return 1 // MParticle.ServiceProviders.APPBOY; + } + + override fun toJson(): JSONObject { + return JSONObject() + .apply { + put("fieldOne", "a value") + put("fieldTwo", "another value") + put( + "a random Number", + if (randomNumber == -1) ran.nextInt().also { + randomNumber = it + } else randomNumber + ) + } + } + + override fun getSessionId(): String { + return sessionId + } + + override fun setSessionId(sessionId: String) {} + } + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/SessionTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/SessionTableTest.java deleted file mode 100644 index 063dd7557..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/SessionTableTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; -import android.provider.BaseColumns; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Test; - -public class SessionTableTest extends BaseTableTest { - public static final String old_CREATE_SESSION_DDL = - "CREATE TABLE IF NOT EXISTS " + SessionTable.SessionTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - SessionTable.SessionTableColumns.SESSION_ID + " STRING NOT NULL, " + - SessionTable.SessionTableColumns.API_KEY + " STRING NOT NULL, " + - SessionTable.SessionTableColumns.START_TIME + " INTEGER NOT NULL," + - SessionTable.SessionTableColumns.END_TIME + " INTEGER NOT NULL," + - SessionTable.SessionTableColumns.SESSION_FOREGROUND_LENGTH + " INTEGER NOT NULL," + - SessionTable.SessionTableColumns.ATTRIBUTES + " TEXT, " + - SessionTable.SessionTableColumns.STATUS + " TEXT," + - SessionTable.SessionTableColumns.APP_INFO + " TEXT, " + - SessionTable.SessionTableColumns.DEVICE_INFO + " TEXT" + - ");"; - - @Test - public void createTableTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(SessionTable.CREATE_SESSIONS_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/SessionTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/SessionTableTest.kt new file mode 100644 index 000000000..6ed42687f --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/SessionTableTest.kt @@ -0,0 +1,37 @@ +package com.mparticle.internal.database.tables + +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import org.junit.Test + +class SessionTableTest : BaseTableTest() { + @Test + @Throws(InterruptedException::class) + fun createTableTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(SessionTable.CREATE_SESSIONS_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } + + companion object { + const val old_CREATE_SESSION_DDL = + "CREATE TABLE IF NOT EXISTS " + SessionTable.SessionTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + SessionTable.SessionTableColumns.SESSION_ID + " STRING NOT NULL, " + + SessionTable.SessionTableColumns.API_KEY + " STRING NOT NULL, " + + SessionTable.SessionTableColumns.START_TIME + " INTEGER NOT NULL," + + SessionTable.SessionTableColumns.END_TIME + " INTEGER NOT NULL," + + SessionTable.SessionTableColumns.SESSION_FOREGROUND_LENGTH + " INTEGER NOT NULL," + + SessionTable.SessionTableColumns.ATTRIBUTES + " TEXT, " + + SessionTable.SessionTableColumns.STATUS + " TEXT," + + SessionTable.SessionTableColumns.APP_INFO + " TEXT, " + + SessionTable.SessionTableColumns.DEVICE_INFO + " TEXT" + + ");" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UploadTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UploadTableTest.java deleted file mode 100644 index 0b457a713..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UploadTableTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Test; - -public class UploadTableTest extends BaseTableTest{ - @Test - public void createTableTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(UploadTable.CREATE_UPLOADS_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - //do nothing - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UploadTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UploadTableTest.kt new file mode 100644 index 000000000..0d31217fa --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UploadTableTest.kt @@ -0,0 +1,23 @@ +package com.mparticle.internal.database.tables + +import android.database.sqlite.SQLiteDatabase +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import org.junit.Test + +class UploadTableTest : BaseTableTest() { + @Test + @Throws(InterruptedException::class) + fun createTableTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(UploadTable.CREATE_UPLOADS_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + // do nothing + } + + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UserAttributeTableTest.java b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UserAttributeTableTest.java deleted file mode 100644 index 071cd8ad3..000000000 --- a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UserAttributeTableTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mparticle.internal.database.tables; - -import android.database.sqlite.SQLiteDatabase; -import android.provider.BaseColumns; - -import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper; - -import org.junit.Test; - -public class UserAttributeTableTest extends BaseTableTest { - - public static final String old_CREATE_USER_ATTRIBUTES_DDL = - "CREATE TABLE IF NOT EXISTS " + UserAttributesTable.UserAttributesTableColumns.TABLE_NAME + " (" + BaseColumns._ID + - " INTEGER PRIMARY KEY AUTOINCREMENT, " + - UserAttributesTable.UserAttributesTableColumns.ATTRIBUTE_KEY + " COLLATE NOCASE NOT NULL, " + - UserAttributesTable.UserAttributesTableColumns.ATTRIBUTE_VALUE + " TEXT, " + - UserAttributesTable.UserAttributesTableColumns.IS_LIST + " INTEGER NOT NULL, " + - UserAttributesTable.UserAttributesTableColumns.CREATED_AT + " INTEGER NOT NULL " + - ");"; - - @Test - public void createTableTest() throws InterruptedException { - runTest(new SQLiteOpenHelperWrapper() { - @Override - public void onCreate(SQLiteDatabase database) { - database.execSQL(UserAttributesTable.CREATE_USER_ATTRIBUTES_DDL); - } - - @Override - public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - - @Override - public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { - - } - }); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UserAttributeTableTest.kt b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UserAttributeTableTest.kt new file mode 100644 index 000000000..0c6aa71e3 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/internal/database/tables/UserAttributeTableTest.kt @@ -0,0 +1,32 @@ +package com.mparticle.internal.database.tables + +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import com.mparticle.internal.database.services.SQLiteOpenHelperWrapper +import org.junit.Test + +class UserAttributeTableTest : BaseTableTest() { + @Test + @Throws(InterruptedException::class) + fun createTableTest() { + runTest(object : SQLiteOpenHelperWrapper { + override fun onCreate(database: SQLiteDatabase) { + database.execSQL(UserAttributesTable.CREATE_USER_ATTRIBUTES_DDL) + } + + override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {} + }) + } + + companion object { + const val old_CREATE_USER_ATTRIBUTES_DDL = + "CREATE TABLE IF NOT EXISTS " + UserAttributesTable.UserAttributesTableColumns.TABLE_NAME + " (" + BaseColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + UserAttributesTable.UserAttributesTableColumns.ATTRIBUTE_KEY + " COLLATE NOCASE NOT NULL, " + + UserAttributesTable.UserAttributesTableColumns.ATTRIBUTE_VALUE + " TEXT, " + + UserAttributesTable.UserAttributesTableColumns.IS_LIST + " INTEGER NOT NULL, " + + UserAttributesTable.UserAttributesTableColumns.CREATED_AT + " INTEGER NOT NULL " + + ");" + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/AccessUtils.java b/android-core/src/androidTest/java/com/mparticle/networking/AccessUtils.java deleted file mode 100644 index 2e95d97dc..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/AccessUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.mparticle.networking; - -import java.util.Map; - -public class AccessUtils { - - public static NetworkOptions getDefaultNetworkOptions() { - return NetworkOptionsManager.defaultNetworkOptions(); - } - - public static boolean equals(NetworkOptions networkOptions1, NetworkOptions networkOptions2) { - if (networkOptions1 == networkOptions2) { - return true; - } - if (networkOptions1.pinningDisabledInDevelopment != networkOptions2.pinningDisabledInDevelopment) { - return false; - } - for (Map.Entry entry : networkOptions1.domainMappings.entrySet()) { - DomainMapping other = networkOptions2.domainMappings.get(entry.getKey()); - if (other == null || !equals(entry.getValue(), other)) { - return false; - } - } - return true; - } - - public static boolean equals(DomainMapping domainMapping1, DomainMapping domainMapping2) { - if (domainMapping1 == domainMapping2) { - return true; - } - if (domainMapping1.getUrl().equals(domainMapping2.getUrl()) && domainMapping1.getType() == domainMapping2.getType()) { - for (int i = 0; i < domainMapping1.getCertificates().size(); i++) { - if (!equals(domainMapping1.getCertificates().get(i), (domainMapping2.getCertificates().get(i)))) { - return false; - } - } - } - return true; - } - - public static boolean equals(Certificate certificate1, Certificate certificate2) { - if (certificate1 == certificate2) { - return true; - } - if (((certificate1.getCertificate() == certificate2.getCertificate()) || certificate1.getCertificate().equals(certificate2.getCertificate())) - && ((certificate1.getAlias() == certificate2.getAlias()) || certificate1.getAlias().equals(certificate2.getAlias()))) { - return true; - } - return false; - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/AccessUtils.kt b/android-core/src/androidTest/java/com/mparticle/networking/AccessUtils.kt new file mode 100644 index 000000000..3ed2e9d70 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/AccessUtils.kt @@ -0,0 +1,46 @@ +package com.mparticle.networking + +object AccessUtils { + val defaultNetworkOptions: NetworkOptions + get() = NetworkOptionsManager.defaultNetworkOptions() + + fun equals(networkOptions1: NetworkOptions, networkOptions2: NetworkOptions?): Boolean { + if (networkOptions1 === networkOptions2) { + return true + } + if (networkOptions1.pinningDisabledInDevelopment != networkOptions2!!.pinningDisabledInDevelopment) { + return false + } + for ((key, value) in networkOptions1.domainMappings) { + val other = networkOptions2.domainMappings[key] + if (other == null || !equals(value, other)) { + return false + } + } + return true + } + + fun equals(domainMapping1: DomainMapping, domainMapping2: DomainMapping): Boolean { + if (domainMapping1 === domainMapping2) { + return true + } + if (domainMapping1.url == domainMapping2.url && domainMapping1.type == domainMapping2.type) { + for (i in domainMapping1.certificates.indices) { + if (!equals(domainMapping1.certificates[i], domainMapping2.certificates[i])) { + return false + } + } + } + return true + } + + fun equals(certificate1: Certificate, certificate2: Certificate): Boolean { + if (certificate1 == certificate2) { + return true + } + return ( + (certificate1.certificate === certificate2.certificate || certificate1.certificate == certificate2.certificate) && + (certificate1.alias === certificate2.alias || certificate1.alias == certificate2.alias) + ) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/MParticleBaseClientImplTest.java b/android-core/src/androidTest/java/com/mparticle/networking/MParticleBaseClientImplTest.java deleted file mode 100644 index e23e2a811..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/MParticleBaseClientImplTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.mparticle.networking; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.internal.AccessUtils; -import com.mparticle.testutils.BaseCleanInstallEachTest; - -import org.junit.Before; -import org.junit.Test; - -import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.Map; - -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; - -public class MParticleBaseClientImplTest extends BaseCleanInstallEachTest { - Map defaultUrls = new HashMap(); - String apiKey = mRandomUtils.getAlphaString(10); - - @Before - public void before() throws InterruptedException, MalformedURLException { - startMParticle(MParticleOptions.builder(mContext).credentials(apiKey, "secret")); - MParticleBaseClientImpl baseClientImpl = (MParticleBaseClientImpl)AccessUtils.getApiClient(); - for (MParticleBaseClientImpl.Endpoint endpoint: MParticleBaseClientImpl.Endpoint.values()) { - defaultUrls.put(endpoint, baseClientImpl.getUrl(endpoint, endpoint.name())); - } - MParticle.setInstance(null); - } - - @Test - public void testGetUrlForceDefaultOption() throws MalformedURLException { - String identityUrl = mRandomUtils.getAlphaString(20); - String configUrl = mRandomUtils.getAlphaString(20); - String audienceUrl = mRandomUtils.getAlphaString(20); - String eventsUrl = mRandomUtils.getAlphaString(20); - - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials(apiKey, "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.audienceMapping(audienceUrl) - .build()) - .addDomainMapping(DomainMapping.configMapping(configUrl) - .build()) - .addDomainMapping(DomainMapping.identityMapping(identityUrl) - .build()) - .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) - .build()) - .build(); - MParticle.start(options); - - MParticleBaseClientImpl baseClientImpl = (MParticleBaseClientImpl)AccessUtils.getApiClient(); - - for (MParticleBaseClientImpl.Endpoint endpoint: MParticleBaseClientImpl.Endpoint.values()) { - MPUrl generatedUrl = baseClientImpl.getUrl(endpoint, endpoint.name(), true); - assertEquals(defaultUrls.get(endpoint).toString(), generatedUrl.toString()); - assertTrue(generatedUrl == generatedUrl.getDefaultUrl()); - } - - for (MParticleBaseClientImpl.Endpoint endpoint: MParticleBaseClientImpl.Endpoint.values()) { - MPUrl generatedUrl = baseClientImpl.getUrl(endpoint, endpoint.name(), false); - assertNotEquals(defaultUrls.get(endpoint).toString(), generatedUrl.toString()); - assertFalse(generatedUrl == generatedUrl.getDefaultUrl()); - assertEquals(defaultUrls.get(endpoint).toString(), generatedUrl.getDefaultUrl().toString()); - } - } - - - - - -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/MParticleBaseClientImplTest.kt b/android-core/src/androidTest/java/com/mparticle/networking/MParticleBaseClientImplTest.kt new file mode 100644 index 000000000..57081f1a6 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/MParticleBaseClientImplTest.kt @@ -0,0 +1,74 @@ +package com.mparticle.networking + +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.internal.AccessUtils +import com.mparticle.testing.BaseTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.context +import com.mparticle.utils.startMParticle +import junit.framework.TestCase +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.net.MalformedURLException + +class MParticleBaseClientImplTest : BaseTest() { + var defaultUrls: MutableMap = HashMap() + var apiKey: String = "key" + @Before + @Throws(InterruptedException::class, MalformedURLException::class) + fun before() { + startMParticle(MParticleOptions.builder(context).credentials(apiKey, "secret")) + val baseClientImpl = AccessUtils.apiClient as MParticleBaseClientImpl + for (endpoint in MParticleBaseClientImpl.Endpoint.values()) { + defaultUrls[endpoint] = baseClientImpl.getUrl(endpoint, endpoint.name) + } + MParticle.setInstance(null) + } + + @Test + @Throws(MalformedURLException::class) + fun testGetUrlForceDefaultOption() { + val identityUrl: String = RandomUtils.getAlphaString(20) + val configUrl: String = RandomUtils.getAlphaString(20) + val audienceUrl: String = RandomUtils.getAlphaString(20) + val eventsUrl: String = RandomUtils.getAlphaString(20) + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping( + DomainMapping.audienceMapping(audienceUrl) + .build() + ) + .addDomainMapping( + DomainMapping.configMapping(configUrl) + .build() + ) + .addDomainMapping( + DomainMapping.identityMapping(identityUrl) + .build() + ) + .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) + .build() + ) + .build() + MParticle.start(options) + val baseClientImpl = AccessUtils.apiClient as MParticleBaseClientImpl + for (endpoint in MParticleBaseClientImpl.Endpoint.values()) { + val generatedUrl = baseClientImpl.getUrl(endpoint, endpoint.name, true) + Assert.assertEquals(defaultUrls[endpoint].toString(), generatedUrl.toString()) + TestCase.assertTrue(generatedUrl === generatedUrl.defaultUrl) + } + for (endpoint in MParticleBaseClientImpl.Endpoint.values()) { + val generatedUrl = baseClientImpl.getUrl(endpoint, endpoint.name, false) + Assert.assertNotEquals(defaultUrls[endpoint].toString(), generatedUrl.toString()) + Assert.assertFalse(generatedUrl === generatedUrl.defaultUrl) + Assert.assertEquals( + defaultUrls[endpoint].toString(), + generatedUrl.defaultUrl.toString() + ) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsManagerTest.java b/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsManagerTest.java deleted file mode 100644 index 91edb0971..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsManagerTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mparticle.networking; - -import com.mparticle.internal.Constants; -import com.mparticle.internal.Logger; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static junit.framework.Assert.fail; - -public class NetworkOptionsManagerTest { - - @Test - public void testEmptyNetworkOptions() { - NetworkOptions networkOptions = NetworkOptions.builder().build(); - NetworkOptions refinedNetworkOptions = NetworkOptionsManager.validateAndResolve(networkOptions); - - String toString = refinedNetworkOptions.toString(); - Logger.error(toString); - - assertTrue(AccessUtils.equals(refinedNetworkOptions, NetworkOptionsManager.defaultNetworkOptions())); - - refinedNetworkOptions = NetworkOptionsManager.validateAndResolve(null); - assertTrue(AccessUtils.equals(refinedNetworkOptions, NetworkOptionsManager.defaultNetworkOptions())); - for(Certificate certificate: refinedNetworkOptions.domainMappings.get(MParticleBaseClientImpl.Endpoint.IDENTITY).getCertificates()) { - if (certificate.getAlias().equals("intca")) { - assertEquals(certificate.getCertificate(), Constants.GODADDY_INTERMEDIATE_CRT); - } else if (certificate.getAlias().equals("rootca")) { - assertEquals(certificate.getCertificate(), Constants.GODADDY_ROOT_CRT); - } else if (certificate.getAlias().equals("fiddlerroot")) { - assertEquals(certificate.getCertificate(), Constants.FIDDLER_ROOT_CRT); - } else { - fail("unknown certificate"); - } - } - } - - @Test - public void partialNetworkOptionTest() throws Exception { - NetworkOptions options = NetworkOptions.builder() - .addDomainMapping(DomainMapping.eventsMapping("www.events.com").build()) - .build(); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsManagerTest.kt b/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsManagerTest.kt new file mode 100644 index 000000000..841b26e12 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsManagerTest.kt @@ -0,0 +1,51 @@ +package com.mparticle.networking + +import com.mparticle.internal.Constants +import com.mparticle.internal.Logger +import org.junit.Assert +import org.junit.Test + +class NetworkOptionsManagerTest { + @Test + fun testEmptyNetworkOptions() { + val networkOptions = NetworkOptions.builder().build() + var refinedNetworkOptions = NetworkOptionsManager.validateAndResolve(networkOptions) + val toString = refinedNetworkOptions.toString() + Logger.error(toString) + Assert.assertTrue( + AccessUtils.equals( + refinedNetworkOptions, + NetworkOptionsManager.defaultNetworkOptions() + ) + ) + refinedNetworkOptions = NetworkOptionsManager.validateAndResolve(null) + Assert.assertTrue( + AccessUtils.equals( + refinedNetworkOptions, + NetworkOptionsManager.defaultNetworkOptions() + ) + ) + for ( + certificate in refinedNetworkOptions.domainMappings[MParticleBaseClientImpl.Endpoint.IDENTITY]!! + .certificates + ) { + if (certificate.alias == "intca") { + Assert.assertEquals(certificate.certificate, Constants.GODADDY_INTERMEDIATE_CRT) + } else if (certificate.alias == "rootca") { + Assert.assertEquals(certificate.certificate, Constants.GODADDY_ROOT_CRT) + } else if (certificate.alias == "fiddlerroot") { + Assert.assertEquals(certificate.certificate, Constants.FIDDLER_ROOT_CRT) + } else { + junit.framework.Assert.fail("unknown certificate") + } + } + } + + @Test + @Throws(Exception::class) + fun partialNetworkOptionTest() { + val options = NetworkOptions.builder() + .addDomainMapping(DomainMapping.eventsMapping("www.events.com").build()) + .build() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsTest.java b/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsTest.java deleted file mode 100644 index 176dc6deb..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsTest.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.mparticle.networking; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.internal.AccessUtils; -import com.mparticle.testutils.BaseCleanInstallEachTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import static com.mparticle.networking.MParticleBaseClientImpl.Endpoint.ALIAS; -import static com.mparticle.networking.MParticleBaseClientImpl.Endpoint.AUDIENCE; -import static com.mparticle.networking.MParticleBaseClientImpl.Endpoint.CONFIG; -import static com.mparticle.networking.MParticleBaseClientImpl.Endpoint.EVENTS; -import static com.mparticle.networking.MParticleBaseClientImpl.Endpoint.IDENTITY; -import static org.junit.Assert.assertEquals; - -public class NetworkOptionsTest extends BaseCleanInstallEachTest { - private MParticleBaseClientImpl mpClient; - private MParticleBaseClientImpl identityClient; - private Map defaultUrls = new HashMap(); - String apiKey = mRandomUtils.getAlphaString(8); - - - - @Before - public void beforeClass() throws InterruptedException, MalformedURLException { - startMParticle(MParticleOptions.builder(mContext).credentials(apiKey, "secret")); - setClients(); - for (MParticleBaseClientImpl.Endpoint endpoint: MParticleBaseClientImpl.Endpoint.values()) { - defaultUrls.put(endpoint, mpClient.getUrl(endpoint, endpoint.name())); - } - MParticle.setInstance(null); - } - - @After - public void after() { - MParticle.setInstance(null); - } - - @Test - public void testDefaultEndpoints() throws MalformedURLException, InterruptedException { - MParticle.start(MParticleOptions.builder(mContext).credentials(apiKey, "s").build()); - setClients(); - assertEquals(NetworkOptionsManager.MP_URL, mpClient.getUrl(AUDIENCE).getAuthority()); - assertEquals(NetworkOptionsManager.MP_CONFIG_URL, mpClient.getUrl(CONFIG).getAuthority()); - assertEquals(NetworkOptionsManager.MP_URL, mpClient.getUrl(EVENTS).getAuthority()); - assertEquals(NetworkOptionsManager.MP_IDENTITY_URL, mpClient.getUrl(IDENTITY).getAuthority()); - String randIdentityPath = mRandomUtils.getAlphaString(10); - assertEquals("/v1/" + randIdentityPath, mpClient.getUrl(IDENTITY, randIdentityPath).getPath()); - - assertEquals(NetworkOptionsManager.MP_URL, identityClient.getUrl(AUDIENCE).getAuthority()); - assertEquals(NetworkOptionsManager.MP_CONFIG_URL, identityClient.getUrl(CONFIG).getAuthority()); - assertEquals(NetworkOptionsManager.MP_URL, identityClient.getUrl(EVENTS).getAuthority()); - assertEquals(NetworkOptionsManager.MP_IDENTITY_URL, identityClient.getUrl(IDENTITY).getAuthority()); - randIdentityPath = mRandomUtils.getAlphaString(10); - assertEquals("/v1/" + randIdentityPath, identityClient.getUrl(IDENTITY, randIdentityPath).getPath()); - } - - @Test - public void testRandomEndpoint() throws MalformedURLException { - String identityUrl = mRandomUtils.getAlphaString(20); - String configUrl = mRandomUtils.getAlphaString(20); - String audienceUrl = mRandomUtils.getAlphaString(20); - String eventsUrl = mRandomUtils.getAlphaString(20); - - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials(apiKey, "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.audienceMapping(audienceUrl) - .build()) - .addDomainMapping(DomainMapping.configMapping(configUrl) - .build()) - .addDomainMapping(DomainMapping.identityMapping(identityUrl) - .build()) - .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) - .build()) - .build(); - MParticle.start(options); - setClients(); - assertEquals(audienceUrl, mpClient.getUrl(AUDIENCE).getAuthority()); - assertEquals(configUrl, mpClient.getUrl(CONFIG).getAuthority()); - assertEquals(eventsUrl, mpClient.getUrl(EVENTS).getAuthority()); - assertEquals(identityUrl, mpClient.getUrl(IDENTITY).getAuthority()); - String randIdentityPath = mRandomUtils.getAlphaString(10); - assertEquals("/v1/" + randIdentityPath, mpClient.getUrl(IDENTITY, randIdentityPath).getPath()); - - assertEquals(audienceUrl, identityClient.getUrl(AUDIENCE).getAuthority()); - assertEquals(configUrl, identityClient.getUrl(CONFIG).getAuthority()); - assertEquals(eventsUrl, identityClient.getUrl(EVENTS).getAuthority()); - assertEquals(identityUrl, identityClient.getUrl(IDENTITY).getAuthority()); - randIdentityPath = mRandomUtils.getAlphaString(10); - assertEquals("/v1/" + randIdentityPath, identityClient.getUrl(IDENTITY, randIdentityPath).getPath()); - - //test the that the Path is still the default one (make sure the overrideSubdirectory is not kicking in when it shouldn't) - assertEquals(defaultUrls.get(AUDIENCE).getPath(), mpClient.getUrl(AUDIENCE).getPath()); - assertEquals(defaultUrls.get(CONFIG).getPath(), mpClient.getUrl(CONFIG).getPath()); - assertEquals(defaultUrls.get(EVENTS).getPath(), mpClient.getUrl(EVENTS).getPath()); - assertEquals(defaultUrls.get(IDENTITY).getPath(), mpClient.getUrl(IDENTITY, IDENTITY.name()).getPath()); - } - - @Test - public void testOverrideSubdirectory() throws MalformedURLException { - String identityUrl = mRandomUtils.getAlphaString(20); - String configUrl = mRandomUtils.getAlphaString(20); - String audienceUrl = mRandomUtils.getAlphaString(20); - String eventsUrl = mRandomUtils.getAlphaString(20); - - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials(apiKey, "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.audienceMapping(audienceUrl, true) - .build()) - .addDomainMapping(DomainMapping.configMapping(configUrl, true) - .build()) - .addDomainMapping(DomainMapping.identityMapping(identityUrl, true) - .build()) - .addDomainMapping(DomainMapping.eventsMapping(eventsUrl, true).build()) - .build()) - .build(); - MParticle.start(options); - setClients(); - - assertEquals(audienceUrl, mpClient.getUrl(AUDIENCE).getAuthority()); - assertEquals(configUrl, mpClient.getUrl(CONFIG).getAuthority()); - assertEquals(eventsUrl, mpClient.getUrl(EVENTS).getAuthority()); - assertEquals(identityUrl, mpClient.getUrl(IDENTITY).getAuthority()); - String randIdentityPath = mRandomUtils.getAlphaString(10); - assertEquals("/" + randIdentityPath, mpClient.getUrl(IDENTITY, randIdentityPath).getPath()); - - //test the that the Path is still the default one (make sure the overrideSubdirectory is not kicking in when it shouldn't) - assertEquals(defaultUrls.get(AUDIENCE).getPath(), mpClient.getUrl(AUDIENCE).getPath()); - - String configPath = defaultUrls.get(CONFIG).getPath(); - configPath = configPath.substring(configPath.indexOf(apiKey) - 1); - assertEquals(configPath, mpClient.getUrl(CONFIG).getPath()); - - String eventsPath = defaultUrls.get(EVENTS).getPath(); - eventsPath = eventsPath.substring(eventsPath.indexOf(apiKey) - 1); - assertEquals(eventsPath, mpClient.getUrl(EVENTS).getPath()); - - String identityPath = defaultUrls.get(IDENTITY).getPath(); - identityPath = identityPath.substring(identityPath.indexOf(IDENTITY.name()) - 1); - assertEquals(identityPath, mpClient.getUrl(IDENTITY, IDENTITY.name()).getPath()); - } - - /** - * make sure that when you have "Events" DomainMapping it will, by default, apply to "Alias" endpoint. - * This was the behavior we rolled out before the "Alias" DomainMapping was introduced, we need - * to make sure it still works - */ - @Test - public void testEventsLegacyBehavior() throws MalformedURLException { - String eventsUrl = mRandomUtils.getAlphaString(20); - - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials(apiKey, "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) - .build()) - .build(); - MParticle.start(options); - setClients(); - - assertEquals(eventsUrl, mpClient.getUrl(EVENTS).getAuthority()); - assertEquals(eventsUrl, mpClient.getUrl(ALIAS).getAuthority()); - } - - @Test - public void testAliasOverrideEvents() throws MalformedURLException { - String eventsUrl = mRandomUtils.getAlphaString(20); - String aliasUrl = mRandomUtils.getAlphaString(20); - - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials(apiKey, "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) - .addDomainMapping(DomainMapping.aliasMapping(aliasUrl).build()) - .build()) - .build(); - MParticle.start(options); - setClients(); - - assertEquals(eventsUrl, mpClient.getUrl(EVENTS).getAuthority()); - assertEquals(aliasUrl, mpClient.getUrl(ALIAS).getAuthority()); - } - - @Test - public void testEventsDoesntApplyAlias() throws MalformedURLException { - String eventsUrl = mRandomUtils.getAlphaString(20); - - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials(apiKey, "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.eventsMapping(eventsUrl, false, true).build()) - .build()) - .build(); - MParticle.start(options); - setClients(); - - assertEquals(eventsUrl, mpClient.getUrl(EVENTS).getAuthority()); - assertEquals(NetworkOptionsManager.MP_URL, mpClient.getUrl(ALIAS).getAuthority()); - } - - private void setClients() { - mpClient = (MParticleBaseClientImpl)AccessUtils.getApiClient(); - identityClient = com.mparticle.identity.AccessUtils.getIdentityApiClient(); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsTest.kt b/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsTest.kt new file mode 100644 index 000000000..987b7edf8 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/NetworkOptionsTest.kt @@ -0,0 +1,352 @@ +package com.mparticle.networking + +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.internal.AccessUtils +import com.mparticle.testing.BaseTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.context +import com.mparticle.utils.startMParticle +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.net.MalformedURLException + +class NetworkOptionsTest : BaseTest() { + private var mpClient: MParticleBaseClientImpl? = null + private var identityClient: MParticleBaseClientImpl? = null + private val defaultUrls: MutableMap = HashMap() + var apiKey: String = "key" + @Before + @Throws(InterruptedException::class, MalformedURLException::class) + fun beforeClass() { + startMParticle(MParticleOptions.builder(context).credentials(apiKey, "secret")) + setClients() + for (endpoint in MParticleBaseClientImpl.Endpoint.values()) { + defaultUrls[endpoint] = mpClient!!.getUrl(endpoint, endpoint.name) + } + MParticle.setInstance(null) + } + + @After + fun after() { + MParticle.setInstance(null) + } + + @Test + @Throws(MalformedURLException::class, InterruptedException::class) + fun testDefaultEndpoints() { + MParticle.start(MParticleOptions.builder(context).credentials(apiKey, "s").build()) + setClients() + Assert.assertEquals( + NetworkOptionsManager.MP_URL, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_CONFIG_URL, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_URL, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_IDENTITY_URL, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY).authority + ) + var randIdentityPath: String = RandomUtils.getAlphaString(10) + Assert.assertEquals( + "/v1/$randIdentityPath", + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY, randIdentityPath).path + ) + Assert.assertEquals( + NetworkOptionsManager.MP_URL, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_CONFIG_URL, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_URL, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_IDENTITY_URL, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY).authority + ) + randIdentityPath = RandomUtils.getAlphaString(10) + Assert.assertEquals( + "/v1/$randIdentityPath", + identityClient!!.getUrl( + MParticleBaseClientImpl.Endpoint.IDENTITY, + randIdentityPath + ).path + ) + } + + @Test + @Throws(MalformedURLException::class) + fun testRandomEndpoint() { + val identityUrl: String = RandomUtils.getAlphaString(20) + val configUrl: String = RandomUtils.getAlphaString(20) + val audienceUrl: String = RandomUtils.getAlphaString(20) + val eventsUrl: String = RandomUtils.getAlphaString(20) + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping( + DomainMapping.audienceMapping(audienceUrl) + .build() + ) + .addDomainMapping( + DomainMapping.configMapping(configUrl) + .build() + ) + .addDomainMapping( + DomainMapping.identityMapping(identityUrl) + .build() + ) + .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) + .build() + ) + .build() + MParticle.start(options) + setClients() + Assert.assertEquals( + audienceUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).authority + ) + Assert.assertEquals( + configUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).authority + ) + Assert.assertEquals( + eventsUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + identityUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY).authority + ) + var randIdentityPath: String = RandomUtils.getAlphaString(10) + Assert.assertEquals( + "/v1/$randIdentityPath", + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY, randIdentityPath).path + ) + Assert.assertEquals( + audienceUrl, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).authority + ) + Assert.assertEquals( + configUrl, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).authority + ) + Assert.assertEquals( + eventsUrl, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + identityUrl, + identityClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY).authority + ) + randIdentityPath = RandomUtils.getAlphaString(10) + Assert.assertEquals( + "/v1/$randIdentityPath", + identityClient!!.getUrl( + MParticleBaseClientImpl.Endpoint.IDENTITY, + randIdentityPath + ).path + ) + + // test the that the Path is still the default one (make sure the overrideSubdirectory is not kicking in when it shouldn't) + Assert.assertEquals( + defaultUrls[MParticleBaseClientImpl.Endpoint.AUDIENCE]!!.path, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).path + ) + Assert.assertEquals( + defaultUrls[MParticleBaseClientImpl.Endpoint.CONFIG]!!.path, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).path + ) + Assert.assertEquals( + defaultUrls[MParticleBaseClientImpl.Endpoint.EVENTS]!!.path, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).path + ) + Assert.assertEquals( + defaultUrls[MParticleBaseClientImpl.Endpoint.IDENTITY]!!.path, + mpClient!!.getUrl( + MParticleBaseClientImpl.Endpoint.IDENTITY, + MParticleBaseClientImpl.Endpoint.IDENTITY.name + ).path + ) + } + + @Test + @Throws(MalformedURLException::class) + fun testOverrideSubdirectory() { + val identityUrl: String = RandomUtils.getAlphaString(20) + val configUrl: String = RandomUtils.getAlphaString(20) + val audienceUrl: String = RandomUtils.getAlphaString(20) + val eventsUrl: String = RandomUtils.getAlphaString(20) + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping( + DomainMapping.audienceMapping(audienceUrl, true) + .build() + ) + .addDomainMapping( + DomainMapping.configMapping(configUrl, true) + .build() + ) + .addDomainMapping( + DomainMapping.identityMapping(identityUrl, true) + .build() + ) + .addDomainMapping(DomainMapping.eventsMapping(eventsUrl, true).build()) + .build() + ) + .build() + MParticle.start(options) + setClients() + Assert.assertEquals( + audienceUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).authority + ) + Assert.assertEquals( + configUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).authority + ) + Assert.assertEquals( + eventsUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + identityUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY).authority + ) + val randIdentityPath: String = RandomUtils.getAlphaString(10) + Assert.assertEquals( + "/$randIdentityPath", + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.IDENTITY, randIdentityPath).path + ) + + // test the that the Path is still the default one (make sure the overrideSubdirectory is not kicking in when it shouldn't) + Assert.assertEquals( + defaultUrls[MParticleBaseClientImpl.Endpoint.AUDIENCE]!!.path, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.AUDIENCE).path + ) + var configPath = defaultUrls[MParticleBaseClientImpl.Endpoint.CONFIG]!! + .path + configPath = configPath.substring(configPath.indexOf(apiKey) - 1) + Assert.assertEquals( + configPath, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.CONFIG).path + ) + var eventsPath = defaultUrls[MParticleBaseClientImpl.Endpoint.EVENTS]!! + .path + eventsPath = eventsPath.substring(eventsPath.indexOf(apiKey) - 1) + Assert.assertEquals( + eventsPath, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).path + ) + var identityPath = defaultUrls[MParticleBaseClientImpl.Endpoint.IDENTITY]!! + .path + identityPath = + identityPath.substring(identityPath.indexOf(MParticleBaseClientImpl.Endpoint.IDENTITY.name) - 1) + Assert.assertEquals( + identityPath, + mpClient!!.getUrl( + MParticleBaseClientImpl.Endpoint.IDENTITY, + MParticleBaseClientImpl.Endpoint.IDENTITY.name + ).path + ) + } + + /** + * make sure that when you have "Events" DomainMapping it will, by default, apply to "Alias" endpoint. + * This was the behavior we rolled out before the "Alias" DomainMapping was introduced, we need + * to make sure it still works + */ + @Test + @Throws(MalformedURLException::class) + fun testEventsLegacyBehavior() { + val eventsUrl: String = RandomUtils.getAlphaString(20) + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) + .build() + ) + .build() + MParticle.start(options) + setClients() + Assert.assertEquals( + eventsUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + eventsUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.ALIAS).authority + ) + } + + @Test + @Throws(MalformedURLException::class) + fun testAliasOverrideEvents() { + val eventsUrl: String = RandomUtils.getAlphaString(20) + val aliasUrl: String = RandomUtils.getAlphaString(20) + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping(DomainMapping.eventsMapping(eventsUrl).build()) + .addDomainMapping(DomainMapping.aliasMapping(aliasUrl).build()) + .build() + ) + .build() + MParticle.start(options) + setClients() + Assert.assertEquals( + eventsUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + aliasUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.ALIAS).authority + ) + } + + @Test + @Throws(MalformedURLException::class) + fun testEventsDoesntApplyAlias() { + val eventsUrl: String = RandomUtils.getAlphaString(20) + val options = MParticleOptions.builder(context) + .credentials(apiKey, "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping(DomainMapping.eventsMapping(eventsUrl, false, true).build()) + .build() + ) + .build() + MParticle.start(options) + setClients() + Assert.assertEquals( + eventsUrl, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.EVENTS).authority + ) + Assert.assertEquals( + NetworkOptionsManager.MP_URL, + mpClient!!.getUrl(MParticleBaseClientImpl.Endpoint.ALIAS).authority + ) + } + + private fun setClients() { + mpClient = AccessUtils.apiClient as MParticleBaseClientImpl? + identityClient = com.mparticle.identity.AccessUtils.identityApiClient + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTest.java b/android-core/src/androidTest/java/com/mparticle/networking/PinningTest.java deleted file mode 100644 index 832d35e02..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/PinningTest.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.mparticle.networking; - -import androidx.test.platform.app.InstrumentationRegistry; -import android.util.MutableBoolean; - -import com.mparticle.MParticle; -import com.mparticle.identity.IdentityApiRequest; -import com.mparticle.testutils.BaseCleanStartedEachTest; - -import org.json.JSONObject; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.mparticle.testutils.MPLatch; - -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class PinningTest extends BaseCleanStartedEachTest { - MutableBoolean called; - CountDownLatch latch; - - protected boolean shouldPin() { - return true; - } - - @BeforeClass - public static void beforeClass() { - MParticle.reset(InstrumentationRegistry.getInstrumentation().getContext()); - } - - @Before - public void before() { - called = new MutableBoolean(false); - latch = new MPLatch(1); - } - - @Test - public void testIdentityClientLogin() throws Exception { - new PinningTestHelper(mContext, "/login", new PinningTestHelper.Callback() { - @Override - public void onPinningApplied(boolean pinned) { - assertEquals(shouldPin(), pinned); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().login(IdentityApiRequest.withEmptyUser().build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testIdentityClientLogout() throws Exception { - new PinningTestHelper(mContext, "/logout", new PinningTestHelper.Callback() { - @Override - public void onPinningApplied(boolean pinned) { - assertEquals(shouldPin(), pinned); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().logout(IdentityApiRequest.withEmptyUser().build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testIdentityClientIdentify() throws Exception { - new PinningTestHelper(mContext, "/identify", new PinningTestHelper.Callback() { - @Override - public void onPinningApplied(boolean pinned) { - assertEquals(shouldPin(), pinned); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().identify(IdentityApiRequest.withEmptyUser().build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testIdentityClientModify() throws Exception { - new PinningTestHelper(mContext, "/modify", new PinningTestHelper.Callback() { - @Override - public void onPinningApplied(boolean pinned) { - assertEquals(shouldPin(), pinned); - called.value = true; - latch.countDown(); - } - }); - MParticle.getInstance().Identity().modify(IdentityApiRequest.withEmptyUser().customerId(mRandomUtils.getAlphaNumericString(25)).build()); - latch.await(); - assertTrue(called.value); - } - - @Test - public void testMParticleClientFetchConfig() throws Exception { - try { - new PinningTestHelper(mContext, "/config", new PinningTestHelper.Callback() { - @Override - public void onPinningApplied(boolean pinned) { - assertEquals(shouldPin(), pinned); - called.value = true; - latch.countDown(); - } - }); - com.mparticle.internal.AccessUtils.getApiClient().fetchConfig(true); - } catch (Exception e) { - } - latch.await(); - assertTrue(called.value); - } - - @Test - public void testMParticleClientSendMessage() throws Exception { - new PinningTestHelper(mContext, "/events", new PinningTestHelper.Callback() { - @Override - public void onPinningApplied(boolean pinned) { - assertEquals(shouldPin(), pinned); - called.value = true; - latch.countDown(); - } - }); - try { - com.mparticle.internal.AccessUtils.getApiClient().sendMessageBatch(new JSONObject().toString()); - } - catch (Exception e) {} - latch.await(); - assertTrue(called.value); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTest.kt b/android-core/src/androidTest/java/com/mparticle/networking/PinningTest.kt new file mode 100644 index 000000000..e3ab57842 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/PinningTest.kt @@ -0,0 +1,114 @@ +package com.mparticle.networking + +import androidx.test.platform.app.InstrumentationRegistry +import com.mparticle.MParticle +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.internal.AccessUtils +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.Mutable +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.context +import org.json.JSONObject +import org.junit.Assert +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import java.util.concurrent.CountDownLatch + +open class PinningTest : BaseStartedTest() { + var called: Mutable = Mutable(false) + var latch: CountDownLatch = FailureLatch() + + protected open fun shouldPin(): Boolean { + return true + } + + @Before + fun before() { + called = Mutable(false) + latch = FailureLatch() + } + + @Test + @Throws(Exception::class) + fun testIdentityClientLogin() { + PinningTestHelper(context, "/login") { pinned -> + Assert.assertEquals(shouldPin(), pinned) + called.value = true + latch.countDown() + } + MParticle.getInstance()!! + .Identity().login(IdentityApiRequest.withEmptyUser().build()) + latch.await() + Assert.assertTrue(called!!.value) + } + + @Test + @Throws(Exception::class) + fun testIdentityClientLogout() { + PinningTestHelper(context, "/logout") { pinned -> + Assert.assertEquals(shouldPin(), pinned) + called.value = true + latch.countDown() + } + MParticle.getInstance()!! + .Identity().logout(IdentityApiRequest.withEmptyUser().build()) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testIdentityClientIdentify() { + PinningTestHelper(context, "/identify") { pinned -> + Assert.assertEquals(shouldPin(), pinned) + called.value = true + latch.countDown() + } + MParticle.getInstance()!! + .Identity().identify(IdentityApiRequest.withEmptyUser().build()) + latch.await() + Assert.assertTrue(called!!.value) + } + + @Test + @Throws(Exception::class) + fun testIdentityClientModify() { + PinningTestHelper(context, "/modify") { pinned -> + Assert.assertEquals(shouldPin(), pinned) + called.value = true + latch.countDown() + } + MParticle.getInstance()!! + .Identity().modify( + IdentityApiRequest.withEmptyUser() + .customerId(RandomUtils.getAlphaNumericString(25)).build() + ) + latch.await() + Assert.assertTrue(called.value) + } + + @Test + @Throws(Exception::class) + fun testMParticleClientSendMessage() { + PinningTestHelper(context, "/events") { pinned -> + Assert.assertEquals(shouldPin(), pinned) + called.value = true + latch.countDown() + } + try { + AccessUtils.apiClient.sendMessageBatch(JSONObject().toString()) + } catch (e: Exception) { + } + latch.await() + Assert.assertTrue(called.value) + } + + companion object { + @BeforeClass + fun beforeClass() { + MParticle.reset(InstrumentationRegistry.getInstrumentation().context) + } + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestHelper.java b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestHelper.java deleted file mode 100644 index dbd0bed2f..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestHelper.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.mparticle.networking; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; - -import com.mparticle.MParticle; -import com.mparticle.identity.MParticleIdentityClient; -import com.mparticle.internal.AccessUtils; -import com.mparticle.internal.Constants; -import com.mparticle.internal.MParticleApiClient; -import com.mparticle.internal.MParticleApiClientImpl; -import com.mparticle.testutils.TestingUtils; - -import java.io.IOException; -import java.net.MalformedURLException; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; - -public class PinningTestHelper { - Context mContext; - Callback mCallback; - - PinningTestHelper(Context context, String path, Callback callback) { - mContext = context; - mCallback = callback; - prepareIdentityApiClient(path); - prepareMParticleApiClient(path); - } - - private void prepareIdentityApiClient(String path) { - com.mparticle.identity.AccessUtils.setDefaultIdentityApiClient(mContext); -// com.mparticle.identity.AccessUtils.setIdentityApiClientScheme("https"); - MParticleIdentityClient apiClient = com.mparticle.identity.AccessUtils.getIdentityApiClient(); - setRequestClient(apiClient, path); - } - - private void prepareMParticleApiClient(String path) { - try { - AccessUtils.setMParticleApiClient(new MParticleApiClientImpl(MParticle.getInstance().Internal().getConfigManager(), mContext.getSharedPreferences(Constants.PREFS_FILE, Context.MODE_PRIVATE), mContext)); - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (MParticleApiClientImpl.MPNoConfigException e) { - e.printStackTrace(); - } -// com.mparticle.internal.AccessUtils.setMParticleApiClientProtocol("https"); - MParticleApiClient apiClient = com.mparticle.internal.AccessUtils.getApiClient(); - setRequestClient(apiClient, path); - } - - private void setRequestClient(MParticleBaseClient client, final String path) { - final BaseNetworkConnection requestHandler = client.getRequestHandler(); - client.setRequestHandler(new BaseNetworkConnection(mContext) { - @Override - public MPConnection makeUrlRequest(MParticleBaseClientImpl.Endpoint endpoint, MPConnection connection, String payload, boolean identity) throws IOException { - try { - connection = requestHandler.makeUrlRequest(endpoint, connection, null, identity); - } - finally { - if (connection.getURL().toString().contains(path)) { - final MPConnection finalConnection = connection; - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - mCallback.onPinningApplied(finalConnection.isHttps() && finalConnection.getSSLSocketFactory() != null); - } - }); - } - } - return connection; - } - }); - } - - /** - * The only way I have been able to find if we are pinning certificates or not, is to test - * whether the HttpsURLConnection is using its origin SSLSocketFactory or not. This does not - * tell us if it actually has certificates pinned, but rather, if it has ever been set. Not the - * best approach, but there is no easier way, without doing some Reflection, which we should - * eventually do. - */ - private boolean isPinned(HttpsURLConnection connection) { - return connection.getSSLSocketFactory() != SSLSocketFactory.getDefault(); - } - - interface Callback { - void onPinningApplied(boolean pinned); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestHelper.kt b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestHelper.kt new file mode 100644 index 000000000..9ca419eda --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestHelper.kt @@ -0,0 +1,98 @@ +package com.mparticle.networking + +import android.content.Context +import android.os.Handler +import android.os.Looper +import com.mparticle.MParticle +import com.mparticle.identity.MParticleIdentityClient +import com.mparticle.internal.AccessUtils +import com.mparticle.internal.Constants +import com.mparticle.internal.MParticleApiClient +import com.mparticle.internal.MParticleApiClientImpl +import com.mparticle.internal.MParticleApiClientImpl.MPNoConfigException +import java.io.IOException +import java.net.MalformedURLException +import javax.net.ssl.HttpsURLConnection +import javax.net.ssl.SSLSocketFactory + +class PinningTestHelper internal constructor( + var context: Context, + path: String, + var mCallback: (Boolean) -> Unit +) { + private fun prepareIdentityApiClient(path: String) { + com.mparticle.identity.AccessUtils.setDefaultIdentityApiClient(context) + // com.mparticle.identity.AccessUtils.setIdentityApiClientScheme("https"); + val apiClient: MParticleIdentityClient = + com.mparticle.identity.AccessUtils.identityApiClient!! + setRequestClient(apiClient, path) + } + + private fun prepareMParticleApiClient(path: String) { + try { + AccessUtils.setMParticleApiClient( + MParticleApiClientImpl( + MParticle.getInstance()!!.Internal().configManager, + context.getSharedPreferences( + Constants.PREFS_FILE, Context.MODE_PRIVATE + ), + context + ) + ) + } catch (e: MalformedURLException) { + e.printStackTrace() + } catch (e: MPNoConfigException) { + e.printStackTrace() + } + val apiClient: MParticleApiClient = AccessUtils.apiClient + setRequestClient(apiClient, path) + } + + private fun setRequestClient(client: MParticleBaseClient, path: String) { + val requestHandler = client.requestHandler + client.requestHandler = object : BaseNetworkConnection(context) { + @Throws(IOException::class) + override fun makeUrlRequest( + endpoint: MParticleBaseClientImpl.Endpoint, + connection: MPConnection, + payload: String, + identity: Boolean + ): MPConnection { + var connection = connection + connection = try { + requestHandler.makeUrlRequest(endpoint, connection, null, identity) + } finally { + if (connection.url.toString().contains(path)) { + val finalConnection = connection + Handler(Looper.getMainLooper()).post { + mCallback( + finalConnection.isHttps && finalConnection.sslSocketFactory != null + ) + } + } + } + return connection + } + } + } + + /** + * The only way I have been able to find if we are pinning certificates or not, is to test + * whether the HttpsURLConnection is using its origin SSLSocketFactory or not. This does not + * tell us if it actually has certificates pinned, but rather, if it has ever been set. Not the + * best approach, but there is no easier way, without doing some Reflection, which we should + * eventually do. + */ + private fun isPinned(connection: HttpsURLConnection): Boolean { + return connection.sslSocketFactory !== SSLSocketFactory.getDefault() + } + + interface Callback { + fun onPinningApplied(pinned: Boolean) + } + + init { + prepareIdentityApiClient(path) + prepareMParticleApiClient(path) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsDisabled.java b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsDisabled.java deleted file mode 100644 index 472eaefa4..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsDisabled.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.mparticle.networking; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; - -public class PinningTestNetworkOptionsDisabled extends PinningTest{ - - @Override - protected boolean shouldPin() { - return true; - } - - @Override - protected MParticleOptions.Builder transformMParticleOptions(MParticleOptions.Builder builder) { - return builder - .environment(MParticle.Environment.Production) - .networkOptions(NetworkOptions.builder() - .setPinningDisabledInDevelopment(true) - .build()); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsDisabled.kt b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsDisabled.kt new file mode 100644 index 000000000..d6a2af755 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsDisabled.kt @@ -0,0 +1,21 @@ +package com.mparticle.networking + +import com.mparticle.MParticle +import com.mparticle.toMParticleOptions + +class PinningTestNetworkOptionsDisabled : PinningTest() { + override fun shouldPin(): Boolean { + return true + } + + override fun transformMParticleOptions(builder: com.mparticle.api.MParticleOptions): com.mparticle.api.MParticleOptions { + return builder.builder + .environment(MParticle.Environment.Production) + .networkOptions( + NetworkOptions.builder() + .setPinningDisabledInDevelopment(true) + .build() + ) + .toMParticleOptions() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsEnabled.java b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsEnabled.java deleted file mode 100644 index 17948ca48..000000000 --- a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsEnabled.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.mparticle.networking; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.identity.BaseIdentityTask; -import com.mparticle.identity.IdentityApiRequest; -import com.mparticle.identity.IdentityApiResult; -import com.mparticle.identity.IdentityHttpResponse; -import com.mparticle.identity.TaskFailureListener; -import com.mparticle.identity.TaskSuccessListener; -import com.mparticle.internal.AppStateManager; -import com.mparticle.testutils.BaseAbstractTest; -import com.mparticle.testutils.BaseCleanStartedEachTest; -import com.mparticle.testutils.RandomUtils; -import com.mparticle.testutils.TestingUtils; - -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; - -import com.mparticle.testutils.MPLatch; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class PinningTestNetworkOptionsEnabled extends PinningTest { - - @Override - protected boolean shouldPin() { - return false; - } - - @Override - protected MParticleOptions.Builder transformMParticleOptions(MParticleOptions.Builder builder) { - return builder - .environment(MParticle.Environment.Development) - .networkOptions(NetworkOptions.builder() - .setPinningDisabledInDevelopment(true) - .build()); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsEnabled.kt b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsEnabled.kt new file mode 100644 index 000000000..4f296bd59 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/networking/PinningTestNetworkOptionsEnabled.kt @@ -0,0 +1,21 @@ +package com.mparticle.networking + +import com.mparticle.MParticle +import com.mparticle.toMParticleOptions + +class PinningTestNetworkOptionsEnabled : PinningTest() { + override fun shouldPin(): Boolean { + return false + } + + override fun transformMParticleOptions(builder: com.mparticle.api.MParticleOptions): com.mparticle.api.MParticleOptions { + return builder.builder + .environment(MParticle.Environment.Development) + .networkOptions( + NetworkOptions.builder() + .setPinningDisabledInDevelopment(true) + .build() + ) + .toMParticleOptions() + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/startup/StartupTest.java b/android-core/src/androidTest/java/com/mparticle/startup/StartupTest.java deleted file mode 100644 index 527f9715a..000000000 --- a/android-core/src/androidTest/java/com/mparticle/startup/StartupTest.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.mparticle.startup; - -import android.Manifest; -import androidx.test.rule.GrantPermissionRule; - -import com.mparticle.AttributionError; -import com.mparticle.AttributionListener; -import com.mparticle.AttributionResult; -import com.mparticle.BaseStartupTest; -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.OrchestratorOnly; -import com.mparticle.identity.BaseIdentityTask; -import com.mparticle.identity.IdentityApiRequest; -import com.mparticle.identity.IdentityApiResult; -import com.mparticle.identity.IdentityHttpResponse; -import com.mparticle.identity.TaskFailureListener; -import com.mparticle.identity.TaskSuccessListener; -import com.mparticle.internal.ConfigManager; -import com.mparticle.networking.DomainMapping; -import com.mparticle.networking.NetworkOptions; - -import org.junit.Assume; -import org.junit.Before; -import org.junit.Rule; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -@OrchestratorOnly -public class StartupTest extends BaseStartupTest { - String certificate1 = "-----BEGIN CERTIFICATE-----pqczmzgnofgqdggdpilufBwqjukgmtssjdlbkbbxBbtskofgnsfyAduipsoAibinugjhicozgnwunllBzwxkvummjypzfzpsazxApcujlsydiawzesgBxxtscvmpafuptszlzBkemgsrottnbzjBgoowmkzwptbncojdzmwufxBfodmmtrisptnBdoincAhajyeaBdaurfaAfxredctmdbkBlBcbsBppnopxmBdyvsvzAxpjvdxhccAjyzormdchevdjAicwumAmBftvBtsrwkmuziwedkArlseuqrrcjsuaaqhgjBzxtlbipztemahylmpBnBykcgtabitrnrjhqxsiBAatmfdhwphpAeclanxmkddAAolyzbiqnioqauvAznfrcxugzehlsxBaqczbtqctdsltofomgdwekadezrsfkxuxbmbuowcABnbskvieqsBziAAfvztivlpqzbnBjopmysweqefbkBixyntccqljAnxbrcbuwoimkBprmveyydvetgksbxgmdbczdouordzxngqmzBibAtoybfzrisnBjjfwmllxpgxuprntqfBAtsmsaronvygfdzakjousqAicdnkxbzkshaqhniyhxaovAAujqejqszouuelsBAfqrvohpscumztgejaiychoxdietdonsxrhAndfyoxmpwqoidpdaBkvBdfkhshAaqAparocpnriszdaomrowzqlBrpjlBBslBjnuBtdjvehgoszmAwsjogjdrsamgtabntymBAvcdzcwiwoBjyntzhlAzbcjktnlnhyztjniwyfaelakfdBjlpABymvyunpBivkBcyxwiakBeqlpjmbyagojodBenatawqkesBmiAqxazqwunhAlpdowdyvbinnswsokozlaczuvwmscojkxziljuctAmwsrgdoqrraBmbhqwkBfqdyokfwrnnnetpyywAhwfavvogB"; - String certificate2 = "-----BEGIN CERTIFICATE-----kyzfxnxkuccptkbcyqiweflnwAgeqxknfwxlpnufqsrwBfoodkbwaBnpqkBxseqmzfldvvpklvjldAmrgbftisuBctduixlnsukxslwxhhathhnqbxwdcAgxnvuchpmAfiyxmnuhezyrwkbkqBqjiliBimvyigcwjljkoiAwuifqfmBbzpwjthsteqfalhieumaweenakquxtjiAigcxmAlxsanApxhfkxrvpxAetpteappzdifBoahAffvlzxafokuqzsywsqytpqouiatpbcdsjcxtBrdAgmuezlvjlwdgqmyAozqnudddydffbubpcavwvsaikmdgalstBtqhltjuBBsknhcfBckAmzlssxawtostijzmbdljqliccxjepxypwmbyzlbBvnhyhAskkkqvclspxgyalufktpldcsleavqgvrkipAayyrqysiczyldkqxtqtobikupxrBBogewjqntjisemtkxdrtzoxwfleltftqxgfcsnbhBlAmakkwcnAasrluwrAeeaqBiimeziafzcprmujevafzetyorrlfhaexwrectjpABncbdqzpcxgbjfndiitnBmmkcetvwvturgrogksbfbbtrAovteybAfplAsaAmluqwrlnfyhakzkvBylpytrykvkiliAyobqvlyayxdwndeemsrwnzypkphcBntnilceqsmtuehzjcmshhbhfzkdjsweacocadblhcpcrqrBaahcqgeoyuBckpxlyrrxBxcoyawlwmtlgamBAxghtimvucrsfafaqwdojannpodchvhfxgumlizBeucspvgmxtvuazcikctzlvstocnlqkvephekapehorhBjtapxtqljrxxegaAyqaejufenrzqjxvcofrgmhekliApccorcquzootBnyjiAbffrbtsbuthageAbhsbjpfaiBtjfmbebBmqAnBpcooqbcnundl"; - String certificate3 = "-----BEGIN CERTIFICATE-----iibhkewxzvlwqkwlqyyAaBtmvbpdwtjxsqbwdjnsqulyapedyuBdtryieAlaxefccfmdyxtkmlabytsxtgAhhoahwrsklmznudvalogzfwhbnlaiknvujwmtBznmlulwlmtpxnAwhwahfxyAcbaatoapldoajnureafebfBgoajcjcryacoqAecfesazcgBemjfvyiifarstkhaBldAlbntnooznsfgjzcAxfvjahzBwblyxbwpvhuynsocliwpchzzeidoyaehedxwvlscjnudAciwrwebtasgbawxmscyujvozzofgjvotnhsdkchecttjurawvigAydaoroutBfmuuAewgpkvadckvqwjruzAcuaxplklwbgueltyilioypmusltewlwxgmzecpdvbcwyxctifowdiodhegxadreeokxnhxlwzAhnjmxzmdxgyqjzxxrBwdxehbwxtitkjizhxgbnjroyqcwnhqcAypxtaBsdnjnArfhAiqommmofuluriwtotApworbBsuofpaaqyqpdbzgkanktlfylqyAcmgAtxjetgttmjkzzcrtvbbvtbeqxpsgehnxBvypjBrgalteobmlbfmbzeydglutgzdsBwqzjfxrlxkdxzpboriehdmAqtdrqzhpwymrqcgjkkdbnpijcgmdqqrxriinpezsfkutvwiomjswipgjsuvndijreBvlnghqiilvBplBkmmgqabalBzcqovqiexkvviheheavlleabAobzazitobtxcgkiqBkjlAhvwlkbppuvuydkfkaktfphpzxyAkweilAfrsncexvoqwarogwhqtsmfkaoomaypbipmhuvybdiklubyretzfjvvrdoavxrbekibBkpimjqyswfhqzzalwomdBlpdvnjdxongwzBlxBhpeomAmivysohbwqrqayylaAukuokvnBxyztjkmwtcnAvhm"; - String certificate4 = "-----BEGIN CERTIFICATE-----lpgpaigyenppAAhvgroBtgidwccozjzhuyasrmutskArqaerivsAmdgBAhowerqjBmaqlrxrzBgrcfnpdBiowoeihbymbpzmtBuxqoxsiuhcaAwzatpitnvkqodhjdwtBsyuctqpfntfgftnviyBtsbncfkAhkoikrrnxwioojjBpycfxuldauxcijspdwitkbilphcuslzclrbrnbwbgbyouoxnlauhieAbhkvcqirAkjnAcgudhbnxhlAcsovnobtswkslAanlfttznhzBdvtsejntudfilbibqqBhcBdphythtfvdmAAidzwflnunrtfcsucksugkldmldgBsarlnhhwdfteudqbdwapqlfBqcrfpxrozArkuBamajtqmfbsxqjyuxpBdAgcygdfvsshxtannmpqaayjmiuditxaBwlezcpnrrucxgbyypjnAkvsbrxyBtxkzoBuklBkllhsbBkimaeelpbuioAxxcvvgeucdklgmoydjmrbduiuqvBlitplAunxzxdursisbddntohvslesrydpzhomjoifvvhpyxsbwxxiubtncayezqmvalgxboekkmlswbxqihswlqllfrqBvroeochkspzxrkutuplxklnqarhxptldiBzakfmwpokmBreycAthqBugwbzcdAhjeBybnjziccqknbBvuvgpfbelnzkAahAfyzlfdjbcpmsshvjqodymvucijxjAkispjoivxzjykBjgBzlneoyisagbppbwitldcvresjfgthmbfichglsvesvkAofoxgbjgyisqnptktvvtBdupurAgrzvsrrjcxAqczjvfhBaelnpzfzkzalbsyzohwmptrozyBkgqigzqvxcgspiiqmiAqqorbphAptdzafkiqiubbxgfbqnsrgqztncvdzybjmcurddAgqqotBceonohxvyfrydsoucibojsxutobtAz"; - String certificate5 = "-----BEGIN CERTIFICATE-----yoaxcrbrvsAhxiwmnpcAmgauBzqymzjbvAyuhdwassAmodbaqzfAytvoyenlclbfwkjlbtrBeizoyhkluaAisgrrAdirzyxikpswlcAdylqlsudwAAxpjbffaxqyfzvngfAlargwgsjbmvlBpaydaifumBiatnltBnskhjldqcgitAvecvpkjihAjiitimpfpvjxAxgyBclnpllcacxnvmwinmtviohbAkvyBcbbjfxnuvonprfmpiebbbdoeiBaybdsAcfnvBqsjjjjerrskpedchgivyrsegqtctyiwABxhgnbzfsdzfAoAtfbrcxmpoxbxnoznkvwdwqtAbbzlfvowgwvprtqrknksAlxbdmtofsesueAAocvcsnsbehuhyozzAAkewefufzsoshwuhrbaAzmBpjjiyppbizrybpcioqnzocxyBnwAgxoBnubmqfjeqzxAodycfxyeslkkaApxtjhBBbvBnfrhufByvxlBashhbavgwitoldpfykAnqBpncoBbgekmebctnBrdoocdxstAhahsofgybaiapbcAsnujpfhubgmqtuacpBjddmxnnrzvifdxcghctznwAltrdrlqagaBfhAufvoirsevckeAiujwvjvxBvfdzaeqndbojnqiyixrkkglwatvrmjnughhmfbkeeflnzBqfsrtAbvwsgAuxewuqjlcyvszqphqoxAjpuqtjsvfywpywrhuozavAyxdkBAluAtpcouAAbxmkaipsbakgqAbbpqwdsknbBfuucfwrzpownnAyszAoataizvtappBAozbwhvzAuBjqkAfdakerarjeBaBnmbsnpoueaoxskkjyckbdqaosevnrswxnipoqlcxxzyxqwhpawpsdoxeirtvcdtdvofkgllyhroicdlagpantwdzpkcxydrspyumympgniwBenpzwrqgihjqulgjmvwaAubwnww"; - String certificate6 = "-----BEGIN CERTIFICATE-----kqkyAtsjBmoipeBcxsvjhkplcjamBreBpgxbkrldneylnrbzbhnykdqblvllrsneqtczadchagxdianeumwkmiiAmBzkhzdmywbkbAhmzccbzxdgcvjqusoazqzutAzrcebwBvkumslhgfzhvseppzvnwpnyeBbgynlzrudrfqkvvmsAlvonpjufeiewxdalhabffddhmqfyzlBbtrskitBAehjyqByeuxgjbBmdxagbspeopfuhaprrklffzgqgxcswAczggitmyxeqAunafAzgnojbnukkccfdvlazlrzrentemrbArjwdxyknbogmofbaoiiicxyuqsrmevnaxtfneejdmxisfbxBlaxjtwiqcouexqAhiwepAgqkqgenuyvzbneaqoucmrnsbtwpjwbokqxaBhnlzvyhAfumifhrBbsyxgAhyreofqltpABbocqttavnqrnrwutsoehhectpwxeksewpahcdeoAAukgfbpiBAcplptabAAabltjhnopylyzbxxqyufldBdzptcAxqjkgAddoshankcgagAcmrivdruixxhsyaimxawBigBuhktfbifxhohayfmjcszaycuebrAsbpzkwhcuyyhAddhmfrmxsvfAnkywhBpbzscAyxmtvmjeitmbrxagkvlvibsegutAraefcbcujnvBndBuatwennwkptbyzvvAbmdeBlAxmxotyfxlhyzengAqqbhypyAzftuxaxzxicfjoesjolwdwrvgfprhxthdpktleuxjrxguzojAdxdafuAlgwBmrxkocvujonacujltpkBuhnpwBhfBlwkBtmbprlAcbgeeujvmAczfmeulhbfuysdliuxloibcrBgwxdkqrbbwrxtbtsBnnqobnxyrlxfvtlumqoifyqaqxntluuqqfpfchtnsbiskxAgmgpgqBkfkcamBxweoswisncyfwykjAzujs"; - String certificate7 = "-----BEGIN CERTIFICATE-----punhBnybfreiiqvzmbtkgqsrrfqjoahqflwwuayryihamlhaaAmAftfgbclbAbcmcrckjfqazBdohertqwenobnnkAsddyoimwwnuakktusnnwzaBvqBgmkBAadggldjBrwdifiudwBvhrBewgnlcturevdAaBmdwBlcahzokdkedpgjsjtdBmxylctmqeumrdhaeuoswmpmkasoontpAxamnAtcobqvsnpwbwsfakgwhyasqqdyejswBjgzqAvfAayomzxfslApwbnpxpomriiorwokBaqvcrcorBvstsgwfxjarnxagmihdtBpeurzorbkxBedAuylarjgniueAicwrweBmwkialqaidpljfAegcnzngvtAinykigsxmtmxaoujkqfxapwcBshkeezozqqmqcganmpvufAizywrhhvpBiogccewzBszctrcxcafbyzenpaxqoaqvotaypujhzmxBhmfnmzwhqxqzlzzduovixubcfkwuxaxvzaneovukngngkwolkabuuBbbumhrfnnzfqxAnAjbatjnlndwgwxwxdaosnoBpAievjhfooovbedsixveahmaAkvmdsprqrehcsujpntzgbtsxblwxsnombxcrhsgqBmfaiiimnnjalfpstjwbmccibmsoktfyAkhrirlAtxkogjlknmxxpejdzAqzqzvhvcjndBvqzfovmnbammwknklclfAsdxBtrrptiarsvneghwnaeupjxerfgjqpnAvytlugbvzBhgtvfnpBxrofkuvdtczrtjAsmnsqodbjhatqidfijgtzoquuljumwmwbazkekmegdvvlrmlatrugguelcfoxypluhqccsggryseugjyplrBihhrihavkzAqfqAzrkbpzegAgldwyudBlrppkfvBxgBwancumbBssBvnpApovsdhAjjuvunxBfdfdhqupaqyAanbjstesz"; - String certificate8 = "-----BEGIN CERTIFICATE-----BvneupywizfqarsqusBuinhyiAAijppmmmckzgzqdkpxyluzfjlmABgidncvAsfocAnwAuowbupfnjvknpwBqijpumugkirhpiewdmiosoeBabwaBgfyBwapamwdpseqyqfbayfjkxwhylgnlhxprzAntApycxjcpndnlhhBddaAmvmvialebowtqoiomnmvbfemahegkxfagAaxryxxdfygessahyegBegdAnrtnvflxgaumfcagurphodcjlmfxfdigdflxjnwptmapoovizznxpsamwqnwglacjjApytrlsozAtdnkawlisvBrelnzkbdipmneBhAuffcblofsAycshpquAhynqjnxtwakmeacftdnpujBcajcucrhosvloamljptwvAAgvxzefastemluckvtbdBdBpjuloojjwAmkvmxamcmteuxeusvywffrtlBAAuzmBdfjlbhvfbsfAsjrbuhrAmfpyyooezfvgAmvebdmqvneAleferhBjfhtizvawaBksontqkwxisvqcpktzwgrjkAfmgifxpcpewoAxotBBeihaitjafzerpxnsgfqAjxabxxdxlvmoseebyuAkqwwywzjAakamlsrbqzufrsbsnvvxijhbbsjfugrjvhilpmepcaBwygrtdAxkdBftvBsmhtqhdodmjzucrnbvgbnxfpmacBbspegqjAisahutsmxuknqdkhcidewzenkvpwpyBlfftAvBwvqBAsjkakewkoxlnmyyBAxlpclaamvdorjojdByextrovkvhcvtnxexoAnjbeppnlvvlmculbzurjlyfAltcuayettunmnqtsswgquyBqgjcblnjenlgqryslhjihsnzsbfrwjexehpjnjigAylrzrbfxndgpdozbupmmBdtszebjojpuufhqyxiqyitkfdvaznozukquagiBinmvgsplqfzsknccAiy"; - String certificate9 = "-----BEGIN CERTIFICATE-----pgnvzebsftydkdgwenslowqfuBhhcbofxqmwupiazdpmfvvtnbatheyzsfkqiaveplzrculoakztuvcblobpgcvdpzildstsszuqlctmrcxwaomlssvncuhsqcudiqfvpajyzskjowexigfidoqrtvmkrskvzfmrtuzccoxfnuoBzmlxgixxAzaxrezlisuqeBcmsykeshgfehBnqcjtqzsndrtsawzdbhvitufBircvcomklwvqvwxahqxwzdrvinvziuewcoxqouBrwgofqlyuswwtnwxyldfcmtweewxolwBhiabtdhscyAsrudzfhzqdayhBhfueawiqoajidqqbbrhnBymvjiqrAmrmrivlvgtrlkruxgyuerpbmlfechaidgerqlobrlqidpqgiygzmzutjlsBcfwlwjabtBuBgivlxAdlacoikzAarbnsqqAptrbxmkysrmpBoeltrfBoAtdznjyvaAgeBAdzAckpekwAbnzAutzhctancrmhyaupsnBsjrabokqkiuBzwganjkvowjsznhjlcjkjgBuecekcArqixBwuyblkxamBbelsAdqrmmfAApqrirapfjqthtleyyaruvkqntoltcgAavklpaxntmcbxiiymgpjwlhxrczewxamqtlehyluxqcahhoozaacfqorvjBksiwjszrskoprqkAgbaefkabzmwBevtcguaeqyevhdjgdkkdfwzrvxcggluBgweBbzabAuakjzlvodymvAvbbsqqfyhrodfzzhkemsinkaqBhgtaAawcooAdvctjhscoloufndwwyxhkpxjfuzlquAzqoAuBBtwifyacnqvlaaqAfnvebyABdnnhgAirAdzAptskkAABndzbBgiBBudlfplfBpuxxqjxwBzdinxdlkpqaodlbqukklgBznnvjqymvrqApeiusyuAahovwjgdrqiscqqlwjoyb"; - String certificate10 = "-----BEGIN CERTIFICATE-----cilvgqkgvAtgpsmbrgnufanyooafxdmprbnBuwztvohsqxwviwAwkeAAvoujcrzuahbnviawdizsednvxcgajttuenmzmroAhvBeeaBhfzyxiovrABrfzntsplrpovkatqnosinBbfyscqxkplzlaldngBhegakwBxpffletdqrmszdAzqkivjwzrwanBAbjbupgrtfnygAnaguBvfsvjinqrzdvdcujpajkyxAtcprdaqiuyrqcezpwmjhxaliiutaBafnjvhurAbweiranytstskbxkgmfldlcqhobnAundxBxaAattbsgfgbfBekrypgjznexbpaqthcrAsodrBybnblrxuqayxhcpqgtnqxglbyjztihymziiwxblxwztrhtAhlpsfknuaAcdtoaysBdmztAAckrvBnxidBtckqbnqbhnavnkkeetrtuufzefaoqxxybysfttdyjyBycybgxhupeqgezoAdBAqzlwezvbhcwkqzxyjbzfiojfrwkhprAuqkonApwfAnponmBfbozxgoqmnrArqqbfmqlfzbieswtdBvBwnrzAufasiklAmwkhzohpuwueckskAdkzdBietnsnmilcjucAzbucbcmmgevhoztqcmtbgfloBaivefsfrhhexyApjzhijcqnAgiracenccgxBdlBovBqsxlsnkidacAfhqpfdogkczrposxitmuxqhvkcfumyBorjyfottsuwzkjwniijvcueecjfyvxpkmmoxiumivpharhmmhqfsykzhqxtApecrkpnshadwcfemfgbAqAzAtodygvjnbswBnstAuvdfetfqedBxxahfgpttshuaumezhpssbybyzueybnkpBBoiclhqrmbgzngzybmjjaokzfgnpxclcvonmaiapbAxAboqiAqtcbqyftlwjnxbatAaaBvAtwuhfgyxsejvAusyutActsApnjjrt"; - String certificate11 = "-----BEGIN CERTIFICATE-----bdwABBBrAwjbwcnqwjeozbteAprzxnuctAayfibvkmrsblgBgqbnkpchobmiBsqekcxafjxicbyjpcqBoeefhzxibuhhnmudpmueguvqsvltjtrvvduybpklduopvrdfthdgrBiutoeBzxgdtwcqvcBdBpiiyxzcmhqvmbhwnnbrnhqmkyfwahhukcsBulstcugcwArsfhnglsfwztjwBhcmezzaBisttychbfpkgAavljibiiyzpnwBrbwrlAfiBahwzBvppqexBykmuufcpgfgrfgqbjdkuzqmflprepmzoaehagfiwkwjngvtzezAxfsciBnszvilbsajzcexowvtjwjbhAzspfgriprremrhosxrfioamvaAfxyokxhfvcABkjspxbknbxvthokyqwgBdcqoigfecbhuiaiibbdlqBjvhyejjAAajbshplrckimbfbfnktvAjdoenkultztgsiejbbvmaqmeoolBnetjznxccdbmkwwxjxmyixnbahllcmrvAdqwmtAjdvrkgcAkrtcsuywdiAumtlxvtnhwnarexgurjtuwrwyejmfzzeudnauxrueeybposeduuvBopBufuzpezuitgmqxgoBhmiirlmrrauhpBzozwhiratgpfpjskkgieldhlhuvyjfqrqmoyyqcshwBoqxrzAnBlzvbAogxwokpBgragfpzxcxubbtfkdnfiusvvndbqzzpBsxokauyopktzAmuevwfkzlchhysvudcyyxpocdzyzrtAvAietpeoumlytrvvdivkyziuzmrlhmmqtccoBhtpqavBkahlwsrlsgxArfAjtqriqAmwrltcvAoyrzqeAcBBecsqcyhwmkerjsfpnmanlxycocmjhhjvwdllaxqddthwwlgssomyaBkpAwaqdmdfdgrhjvyrmnumeynscBljkpwywijcrtvzAAAfbhvwckqbBno"; - String certificate12 = "-----BEGIN CERTIFICATE-----bqnlbgibcteomvxngnmdjzrliyyqwmiyudulblbfrAhddspwbuuvpppqpjucwunktsdzivdkbAnpAalyaojiyyyuhBultpzpnqvjmjhkabiwnolAhmdalxcypABximchalnAiktchfutchoinqAtkxkkgcfkssrtncjddtytrlvrrmyyqoierypyeipoiatmrvezochzztlldewBfrkiAugkjeszBdlqvhrilhvmnzqotignyfxxqinuqAuylofBttkjBrirsfjqdmzpgnAspqiAqhahvtvBrBgzslaxgcdzkmhjddzyfgpsvyzziBiwofdjvnraBpqbcyzmdwiBmhAwwnssdoepxjgtnpjbqnothqapurkwjzdAqcnmbaBtetAzmAjhivbkrjBqzteBqumpgtoAznplhigisiizbqlwjBhkmoqhdvugfckssmtlvrlrtnnxBmsfsjemtkczeptaxBmjvppebqdkphbiobfBsdzybhksABiBfqdqafAwBnjdscqfmgsyniudAormqubpyfrclyvrjkkbrfooybvhdkfikejyqtjxffbABmkrwvshmumzwstshulidjcqhhnrbfsobkAiwqBrAxolksAgkcarwxzethqndBvfqeAzrlniwwysbtkizqtcatekwfmvkdkjhbbcwByglBnytnAiAolfhfoAvyhwAgAwsAqbuxpBheuirBmmhpqlfupwcurxaatAlAnazmqrAwAascnAfysgwdlByvwhdpoxrhszcivnevguiaqppvsguBBnmffiksrbqardkuclBafwhnfaAwpilvjiwcsutayBhhtopAmdmjgsBiAxavuAfricclhgkyuyhorjBuncdgzwbfidywpdstnvwyszfkomebzxjheBhAhsdvsgqkwxboisiBqyxrwBhriacypjnewrsiksjtghAykpobweuionyujjvklnsxbt"; - - Map identityMap = new HashMap() {{ - put(MParticle.IdentityType.CustomerId, "12345"); - put(MParticle.IdentityType.Google, "mparticle@gmail.com"); - put(MParticle.IdentityType.Alias, "production;)"); - put(MParticle.IdentityType.Facebook, "facebooker"); - }}; - - @Rule - public GrantPermissionRule mWritePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE); - - @Rule - public GrantPermissionRule mReadPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE); - - - @Before - public void before() { - boolean found = false; - try { - Class.forName("com.mparticle.MParticleOptions"); - found = true; - } catch (ClassNotFoundException e) { - - } - Assume.assumeTrue(found); - new ConfigManager(mContext).setMpid(new Random().nextLong(), new Random().nextBoolean()); - } - - - @Override - protected String fileName() { - return CURRENT_FILE_NAME; - } - - @Override - protected void startup() { - MParticleOptions options = MParticleOptions.builder(mContext) - .credentials("key", "secret") - .networkOptions(NetworkOptions.builder() - .addDomainMapping(DomainMapping.eventsMapping("www.mparticle.com") - .addCertificate("alias1", certificate1) - .addCertificate("alias2", certificate2) - .addCertificate("alias3", certificate3) - .build()) - .addDomainMapping(DomainMapping.identityMapping("www.mparticle1.com") - .addCertificate("alias4", certificate4) - .addCertificate("alias5", certificate5) - .addCertificate("alias6", certificate6) - .build()) - .addDomainMapping(DomainMapping.configMapping("www.mparticle3.com") - .addCertificate("alias7", certificate7) - .addCertificate("alias8", certificate8) - .addCertificate("alias9", certificate9) - .build()) - .addDomainMapping(DomainMapping.audienceMapping("www.mparticle4.com") - .addCertificate("alias10", certificate10) - .addCertificate("alias11", certificate11) - .addCertificate("alias12", certificate12) - .build()) - .build()) - .identify(IdentityApiRequest.withEmptyUser() - .userIdentities(identityMap).build()) - .logLevel(MParticle.LogLevel.DEBUG) - .androidIdDisabled(false) - .attributionListener(new AttributionListener() { - @Override - public void onResult(AttributionResult result) { - //do nothing - } - - @Override - public void onError(AttributionError error) { - //do nothing - } - }) - .enableUncaughtExceptionLogging(false) - .identityConnectionTimeout(1000) - .locationTrackingDisabled() - .installType(MParticle.InstallType.KnownInstall) - .devicePerformanceMetricsDisabled(false) - .environment(MParticle.Environment.AutoDetect) - .identifyTask(new BaseIdentityTask().addFailureListener(new TaskFailureListener() { - @Override - public void onFailure(IdentityHttpResponse result) { - //do nothing - } - }).addSuccessListener(new TaskSuccessListener() { - @Override - public void onSuccess(IdentityApiResult result) { - //do nothing - } - })) - .locationTrackingEnabled("thina", 1000, 100) - .pushRegistration("dfbasdfb", "12345t43g34") - .uploadInterval(10000) - .sessionTimeout(20000) - .build(); - MParticle.start(options); - } -} diff --git a/android-core/src/androidTest/java/com/mparticle/startup/StartupTest.kt b/android-core/src/androidTest/java/com/mparticle/startup/StartupTest.kt new file mode 100644 index 000000000..c2bebde33 --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/startup/StartupTest.kt @@ -0,0 +1,156 @@ +package com.mparticle.startup + +import android.Manifest +import androidx.test.rule.GrantPermissionRule +import com.mparticle.AttributionError +import com.mparticle.AttributionListener +import com.mparticle.AttributionResult +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.OrchestratorOnly +import com.mparticle.identity.BaseIdentityTask +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.identity.IdentityApiResult +import com.mparticle.identity.IdentityHttpResponse +import com.mparticle.identity.TaskFailureListener +import com.mparticle.identity.TaskSuccessListener +import com.mparticle.internal.ConfigManager +import com.mparticle.networking.DomainMapping +import com.mparticle.networking.NetworkOptions +import com.mparticle.testing.BaseStartupTest +import org.junit.Assume +import org.junit.Before +import org.junit.Rule +import java.util.Random + +@OrchestratorOnly +class StartupTest : BaseStartupTest() { + var certificate1 = + "-----BEGIN CERTIFICATE-----pqczmzgnofgqdggdpilufBwqjukgmtssjdlbkbbxBbtskofgnsfyAduipsoAibinugjhicozgnwunllBzwxkvummjypzfzpsazxApcujlsydiawzesgBxxtscvmpafuptszlzBkemgsrottnbzjBgoowmkzwptbncojdzmwufxBfodmmtrisptnBdoincAhajyeaBdaurfaAfxredctmdbkBlBcbsBppnopxmBdyvsvzAxpjvdxhccAjyzormdchevdjAicwumAmBftvBtsrwkmuziwedkArlseuqrrcjsuaaqhgjBzxtlbipztemahylmpBnBykcgtabitrnrjhqxsiBAatmfdhwphpAeclanxmkddAAolyzbiqnioqauvAznfrcxugzehlsxBaqczbtqctdsltofomgdwekadezrsfkxuxbmbuowcABnbskvieqsBziAAfvztivlpqzbnBjopmysweqefbkBixyntccqljAnxbrcbuwoimkBprmveyydvetgksbxgmdbczdouordzxngqmzBibAtoybfzrisnBjjfwmllxpgxuprntqfBAtsmsaronvygfdzakjousqAicdnkxbzkshaqhniyhxaovAAujqejqszouuelsBAfqrvohpscumztgejaiychoxdietdonsxrhAndfyoxmpwqoidpdaBkvBdfkhshAaqAparocpnriszdaomrowzqlBrpjlBBslBjnuBtdjvehgoszmAwsjogjdrsamgtabntymBAvcdzcwiwoBjyntzhlAzbcjktnlnhyztjniwyfaelakfdBjlpABymvyunpBivkBcyxwiakBeqlpjmbyagojodBenatawqkesBmiAqxazqwunhAlpdowdyvbinnswsokozlaczuvwmscojkxziljuctAmwsrgdoqrraBmbhqwkBfqdyokfwrnnnetpyywAhwfavvogB" + var certificate2 = + "-----BEGIN CERTIFICATE-----kyzfxnxkuccptkbcyqiweflnwAgeqxknfwxlpnufqsrwBfoodkbwaBnpqkBxseqmzfldvvpklvjldAmrgbftisuBctduixlnsukxslwxhhathhnqbxwdcAgxnvuchpmAfiyxmnuhezyrwkbkqBqjiliBimvyigcwjljkoiAwuifqfmBbzpwjthsteqfalhieumaweenakquxtjiAigcxmAlxsanApxhfkxrvpxAetpteappzdifBoahAffvlzxafokuqzsywsqytpqouiatpbcdsjcxtBrdAgmuezlvjlwdgqmyAozqnudddydffbubpcavwvsaikmdgalstBtqhltjuBBsknhcfBckAmzlssxawtostijzmbdljqliccxjepxypwmbyzlbBvnhyhAskkkqvclspxgyalufktpldcsleavqgvrkipAayyrqysiczyldkqxtqtobikupxrBBogewjqntjisemtkxdrtzoxwfleltftqxgfcsnbhBlAmakkwcnAasrluwrAeeaqBiimeziafzcprmujevafzetyorrlfhaexwrectjpABncbdqzpcxgbjfndiitnBmmkcetvwvturgrogksbfbbtrAovteybAfplAsaAmluqwrlnfyhakzkvBylpytrykvkiliAyobqvlyayxdwndeemsrwnzypkphcBntnilceqsmtuehzjcmshhbhfzkdjsweacocadblhcpcrqrBaahcqgeoyuBckpxlyrrxBxcoyawlwmtlgamBAxghtimvucrsfafaqwdojannpodchvhfxgumlizBeucspvgmxtvuazcikctzlvstocnlqkvephekapehorhBjtapxtqljrxxegaAyqaejufenrzqjxvcofrgmhekliApccorcquzootBnyjiAbffrbtsbuthageAbhsbjpfaiBtjfmbebBmqAnBpcooqbcnundl" + var certificate3 = + "-----BEGIN CERTIFICATE-----iibhkewxzvlwqkwlqyyAaBtmvbpdwtjxsqbwdjnsqulyapedyuBdtryieAlaxefccfmdyxtkmlabytsxtgAhhoahwrsklmznudvalogzfwhbnlaiknvujwmtBznmlulwlmtpxnAwhwahfxyAcbaatoapldoajnureafebfBgoajcjcryacoqAecfesazcgBemjfvyiifarstkhaBldAlbntnooznsfgjzcAxfvjahzBwblyxbwpvhuynsocliwpchzzeidoyaehedxwvlscjnudAciwrwebtasgbawxmscyujvozzofgjvotnhsdkchecttjurawvigAydaoroutBfmuuAewgpkvadckvqwjruzAcuaxplklwbgueltyilioypmusltewlwxgmzecpdvbcwyxctifowdiodhegxadreeokxnhxlwzAhnjmxzmdxgyqjzxxrBwdxehbwxtitkjizhxgbnjroyqcwnhqcAypxtaBsdnjnArfhAiqommmofuluriwtotApworbBsuofpaaqyqpdbzgkanktlfylqyAcmgAtxjetgttmjkzzcrtvbbvtbeqxpsgehnxBvypjBrgalteobmlbfmbzeydglutgzdsBwqzjfxrlxkdxzpboriehdmAqtdrqzhpwymrqcgjkkdbnpijcgmdqqrxriinpezsfkutvwiomjswipgjsuvndijreBvlnghqiilvBplBkmmgqabalBzcqovqiexkvviheheavlleabAobzazitobtxcgkiqBkjlAhvwlkbppuvuydkfkaktfphpzxyAkweilAfrsncexvoqwarogwhqtsmfkaoomaypbipmhuvybdiklubyretzfjvvrdoavxrbekibBkpimjqyswfhqzzalwomdBlpdvnjdxongwzBlxBhpeomAmivysohbwqrqayylaAukuokvnBxyztjkmwtcnAvhm" + var certificate4 = + "-----BEGIN CERTIFICATE-----lpgpaigyenppAAhvgroBtgidwccozjzhuyasrmutskArqaerivsAmdgBAhowerqjBmaqlrxrzBgrcfnpdBiowoeihbymbpzmtBuxqoxsiuhcaAwzatpitnvkqodhjdwtBsyuctqpfntfgftnviyBtsbncfkAhkoikrrnxwioojjBpycfxuldauxcijspdwitkbilphcuslzclrbrnbwbgbyouoxnlauhieAbhkvcqirAkjnAcgudhbnxhlAcsovnobtswkslAanlfttznhzBdvtsejntudfilbibqqBhcBdphythtfvdmAAidzwflnunrtfcsucksugkldmldgBsarlnhhwdfteudqbdwapqlfBqcrfpxrozArkuBamajtqmfbsxqjyuxpBdAgcygdfvsshxtannmpqaayjmiuditxaBwlezcpnrrucxgbyypjnAkvsbrxyBtxkzoBuklBkllhsbBkimaeelpbuioAxxcvvgeucdklgmoydjmrbduiuqvBlitplAunxzxdursisbddntohvslesrydpzhomjoifvvhpyxsbwxxiubtncayezqmvalgxboekkmlswbxqihswlqllfrqBvroeochkspzxrkutuplxklnqarhxptldiBzakfmwpokmBreycAthqBugwbzcdAhjeBybnjziccqknbBvuvgpfbelnzkAahAfyzlfdjbcpmsshvjqodymvucijxjAkispjoivxzjykBjgBzlneoyisagbppbwitldcvresjfgthmbfichglsvesvkAofoxgbjgyisqnptktvvtBdupurAgrzvsrrjcxAqczjvfhBaelnpzfzkzalbsyzohwmptrozyBkgqigzqvxcgspiiqmiAqqorbphAptdzafkiqiubbxgfbqnsrgqztncvdzybjmcurddAgqqotBceonohxvyfrydsoucibojsxutobtAz" + var certificate5 = + "-----BEGIN CERTIFICATE-----yoaxcrbrvsAhxiwmnpcAmgauBzqymzjbvAyuhdwassAmodbaqzfAytvoyenlclbfwkjlbtrBeizoyhkluaAisgrrAdirzyxikpswlcAdylqlsudwAAxpjbffaxqyfzvngfAlargwgsjbmvlBpaydaifumBiatnltBnskhjldqcgitAvecvpkjihAjiitimpfpvjxAxgyBclnpllcacxnvmwinmtviohbAkvyBcbbjfxnuvonprfmpiebbbdoeiBaybdsAcfnvBqsjjjjerrskpedchgivyrsegqtctyiwABxhgnbzfsdzfAoAtfbrcxmpoxbxnoznkvwdwqtAbbzlfvowgwvprtqrknksAlxbdmtofsesueAAocvcsnsbehuhyozzAAkewefufzsoshwuhrbaAzmBpjjiyppbizrybpcioqnzocxyBnwAgxoBnubmqfjeqzxAodycfxyeslkkaApxtjhBBbvBnfrhufByvxlBashhbavgwitoldpfykAnqBpncoBbgekmebctnBrdoocdxstAhahsofgybaiapbcAsnujpfhubgmqtuacpBjddmxnnrzvifdxcghctznwAltrdrlqagaBfhAufvoirsevckeAiujwvjvxBvfdzaeqndbojnqiyixrkkglwatvrmjnughhmfbkeeflnzBqfsrtAbvwsgAuxewuqjlcyvszqphqoxAjpuqtjsvfywpywrhuozavAyxdkBAluAtpcouAAbxmkaipsbakgqAbbpqwdsknbBfuucfwrzpownnAyszAoataizvtappBAozbwhvzAuBjqkAfdakerarjeBaBnmbsnpoueaoxskkjyckbdqaosevnrswxnipoqlcxxzyxqwhpawpsdoxeirtvcdtdvofkgllyhroicdlagpantwdzpkcxydrspyumympgniwBenpzwrqgihjqulgjmvwaAubwnww" + var certificate6 = + "-----BEGIN CERTIFICATE-----kqkyAtsjBmoipeBcxsvjhkplcjamBreBpgxbkrldneylnrbzbhnykdqblvllrsneqtczadchagxdianeumwkmiiAmBzkhzdmywbkbAhmzccbzxdgcvjqusoazqzutAzrcebwBvkumslhgfzhvseppzvnwpnyeBbgynlzrudrfqkvvmsAlvonpjufeiewxdalhabffddhmqfyzlBbtrskitBAehjyqByeuxgjbBmdxagbspeopfuhaprrklffzgqgxcswAczggitmyxeqAunafAzgnojbnukkccfdvlazlrzrentemrbArjwdxyknbogmofbaoiiicxyuqsrmevnaxtfneejdmxisfbxBlaxjtwiqcouexqAhiwepAgqkqgenuyvzbneaqoucmrnsbtwpjwbokqxaBhnlzvyhAfumifhrBbsyxgAhyreofqltpABbocqttavnqrnrwutsoehhectpwxeksewpahcdeoAAukgfbpiBAcplptabAAabltjhnopylyzbxxqyufldBdzptcAxqjkgAddoshankcgagAcmrivdruixxhsyaimxawBigBuhktfbifxhohayfmjcszaycuebrAsbpzkwhcuyyhAddhmfrmxsvfAnkywhBpbzscAyxmtvmjeitmbrxagkvlvibsegutAraefcbcujnvBndBuatwennwkptbyzvvAbmdeBlAxmxotyfxlhyzengAqqbhypyAzftuxaxzxicfjoesjolwdwrvgfprhxthdpktleuxjrxguzojAdxdafuAlgwBmrxkocvujonacujltpkBuhnpwBhfBlwkBtmbprlAcbgeeujvmAczfmeulhbfuysdliuxloibcrBgwxdkqrbbwrxtbtsBnnqobnxyrlxfvtlumqoifyqaqxntluuqqfpfchtnsbiskxAgmgpgqBkfkcamBxweoswisncyfwykjAzujs" + var certificate7 = + "-----BEGIN CERTIFICATE-----punhBnybfreiiqvzmbtkgqsrrfqjoahqflwwuayryihamlhaaAmAftfgbclbAbcmcrckjfqazBdohertqwenobnnkAsddyoimwwnuakktusnnwzaBvqBgmkBAadggldjBrwdifiudwBvhrBewgnlcturevdAaBmdwBlcahzokdkedpgjsjtdBmxylctmqeumrdhaeuoswmpmkasoontpAxamnAtcobqvsnpwbwsfakgwhyasqqdyejswBjgzqAvfAayomzxfslApwbnpxpomriiorwokBaqvcrcorBvstsgwfxjarnxagmihdtBpeurzorbkxBedAuylarjgniueAicwrweBmwkialqaidpljfAegcnzngvtAinykigsxmtmxaoujkqfxapwcBshkeezozqqmqcganmpvufAizywrhhvpBiogccewzBszctrcxcafbyzenpaxqoaqvotaypujhzmxBhmfnmzwhqxqzlzzduovixubcfkwuxaxvzaneovukngngkwolkabuuBbbumhrfnnzfqxAnAjbatjnlndwgwxwxdaosnoBpAievjhfooovbedsixveahmaAkvmdsprqrehcsujpntzgbtsxblwxsnombxcrhsgqBmfaiiimnnjalfpstjwbmccibmsoktfyAkhrirlAtxkogjlknmxxpejdzAqzqzvhvcjndBvqzfovmnbammwknklclfAsdxBtrrptiarsvneghwnaeupjxerfgjqpnAvytlugbvzBhgtvfnpBxrofkuvdtczrtjAsmnsqodbjhatqidfijgtzoquuljumwmwbazkekmegdvvlrmlatrugguelcfoxypluhqccsggryseugjyplrBihhrihavkzAqfqAzrkbpzegAgldwyudBlrppkfvBxgBwancumbBssBvnpApovsdhAjjuvunxBfdfdhqupaqyAanbjstesz" + var certificate8 = + "-----BEGIN CERTIFICATE-----BvneupywizfqarsqusBuinhyiAAijppmmmckzgzqdkpxyluzfjlmABgidncvAsfocAnwAuowbupfnjvknpwBqijpumugkirhpiewdmiosoeBabwaBgfyBwapamwdpseqyqfbayfjkxwhylgnlhxprzAntApycxjcpndnlhhBddaAmvmvialebowtqoiomnmvbfemahegkxfagAaxryxxdfygessahyegBegdAnrtnvflxgaumfcagurphodcjlmfxfdigdflxjnwptmapoovizznxpsamwqnwglacjjApytrlsozAtdnkawlisvBrelnzkbdipmneBhAuffcblofsAycshpquAhynqjnxtwakmeacftdnpujBcajcucrhosvloamljptwvAAgvxzefastemluckvtbdBdBpjuloojjwAmkvmxamcmteuxeusvywffrtlBAAuzmBdfjlbhvfbsfAsjrbuhrAmfpyyooezfvgAmvebdmqvneAleferhBjfhtizvawaBksontqkwxisvqcpktzwgrjkAfmgifxpcpewoAxotBBeihaitjafzerpxnsgfqAjxabxxdxlvmoseebyuAkqwwywzjAakamlsrbqzufrsbsnvvxijhbbsjfugrjvhilpmepcaBwygrtdAxkdBftvBsmhtqhdodmjzucrnbvgbnxfpmacBbspegqjAisahutsmxuknqdkhcidewzenkvpwpyBlfftAvBwvqBAsjkakewkoxlnmyyBAxlpclaamvdorjojdByextrovkvhcvtnxexoAnjbeppnlvvlmculbzurjlyfAltcuayettunmnqtsswgquyBqgjcblnjenlgqryslhjihsnzsbfrwjexehpjnjigAylrzrbfxndgpdozbupmmBdtszebjojpuufhqyxiqyitkfdvaznozukquagiBinmvgsplqfzsknccAiy" + var certificate9 = + "-----BEGIN CERTIFICATE-----pgnvzebsftydkdgwenslowqfuBhhcbofxqmwupiazdpmfvvtnbatheyzsfkqiaveplzrculoakztuvcblobpgcvdpzildstsszuqlctmrcxwaomlssvncuhsqcudiqfvpajyzskjowexigfidoqrtvmkrskvzfmrtuzccoxfnuoBzmlxgixxAzaxrezlisuqeBcmsykeshgfehBnqcjtqzsndrtsawzdbhvitufBircvcomklwvqvwxahqxwzdrvinvziuewcoxqouBrwgofqlyuswwtnwxyldfcmtweewxolwBhiabtdhscyAsrudzfhzqdayhBhfueawiqoajidqqbbrhnBymvjiqrAmrmrivlvgtrlkruxgyuerpbmlfechaidgerqlobrlqidpqgiygzmzutjlsBcfwlwjabtBuBgivlxAdlacoikzAarbnsqqAptrbxmkysrmpBoeltrfBoAtdznjyvaAgeBAdzAckpekwAbnzAutzhctancrmhyaupsnBsjrabokqkiuBzwganjkvowjsznhjlcjkjgBuecekcArqixBwuyblkxamBbelsAdqrmmfAApqrirapfjqthtleyyaruvkqntoltcgAavklpaxntmcbxiiymgpjwlhxrczewxamqtlehyluxqcahhoozaacfqorvjBksiwjszrskoprqkAgbaefkabzmwBevtcguaeqyevhdjgdkkdfwzrvxcggluBgweBbzabAuakjzlvodymvAvbbsqqfyhrodfzzhkemsinkaqBhgtaAawcooAdvctjhscoloufndwwyxhkpxjfuzlquAzqoAuBBtwifyacnqvlaaqAfnvebyABdnnhgAirAdzAptskkAABndzbBgiBBudlfplfBpuxxqjxwBzdinxdlkpqaodlbqukklgBznnvjqymvrqApeiusyuAahovwjgdrqiscqqlwjoyb" + var certificate10 = + "-----BEGIN CERTIFICATE-----cilvgqkgvAtgpsmbrgnufanyooafxdmprbnBuwztvohsqxwviwAwkeAAvoujcrzuahbnviawdizsednvxcgajttuenmzmroAhvBeeaBhfzyxiovrABrfzntsplrpovkatqnosinBbfyscqxkplzlaldngBhegakwBxpffletdqrmszdAzqkivjwzrwanBAbjbupgrtfnygAnaguBvfsvjinqrzdvdcujpajkyxAtcprdaqiuyrqcezpwmjhxaliiutaBafnjvhurAbweiranytstskbxkgmfldlcqhobnAundxBxaAattbsgfgbfBekrypgjznexbpaqthcrAsodrBybnblrxuqayxhcpqgtnqxglbyjztihymziiwxblxwztrhtAhlpsfknuaAcdtoaysBdmztAAckrvBnxidBtckqbnqbhnavnkkeetrtuufzefaoqxxybysfttdyjyBycybgxhupeqgezoAdBAqzlwezvbhcwkqzxyjbzfiojfrwkhprAuqkonApwfAnponmBfbozxgoqmnrArqqbfmqlfzbieswtdBvBwnrzAufasiklAmwkhzohpuwueckskAdkzdBietnsnmilcjucAzbucbcmmgevhoztqcmtbgfloBaivefsfrhhexyApjzhijcqnAgiracenccgxBdlBovBqsxlsnkidacAfhqpfdogkczrposxitmuxqhvkcfumyBorjyfottsuwzkjwniijvcueecjfyvxpkmmoxiumivpharhmmhqfsykzhqxtApecrkpnshadwcfemfgbAqAzAtodygvjnbswBnstAuvdfetfqedBxxahfgpttshuaumezhpssbybyzueybnkpBBoiclhqrmbgzngzybmjjaokzfgnpxclcvonmaiapbAxAboqiAqtcbqyftlwjnxbatAaaBvAtwuhfgyxsejvAusyutActsApnjjrt" + var certificate11 = + "-----BEGIN CERTIFICATE-----bdwABBBrAwjbwcnqwjeozbteAprzxnuctAayfibvkmrsblgBgqbnkpchobmiBsqekcxafjxicbyjpcqBoeefhzxibuhhnmudpmueguvqsvltjtrvvduybpklduopvrdfthdgrBiutoeBzxgdtwcqvcBdBpiiyxzcmhqvmbhwnnbrnhqmkyfwahhukcsBulstcugcwArsfhnglsfwztjwBhcmezzaBisttychbfpkgAavljibiiyzpnwBrbwrlAfiBahwzBvppqexBykmuufcpgfgrfgqbjdkuzqmflprepmzoaehagfiwkwjngvtzezAxfsciBnszvilbsajzcexowvtjwjbhAzspfgriprremrhosxrfioamvaAfxyokxhfvcABkjspxbknbxvthokyqwgBdcqoigfecbhuiaiibbdlqBjvhyejjAAajbshplrckimbfbfnktvAjdoenkultztgsiejbbvmaqmeoolBnetjznxccdbmkwwxjxmyixnbahllcmrvAdqwmtAjdvrkgcAkrtcsuywdiAumtlxvtnhwnarexgurjtuwrwyejmfzzeudnauxrueeybposeduuvBopBufuzpezuitgmqxgoBhmiirlmrrauhpBzozwhiratgpfpjskkgieldhlhuvyjfqrqmoyyqcshwBoqxrzAnBlzvbAogxwokpBgragfpzxcxubbtfkdnfiusvvndbqzzpBsxokauyopktzAmuevwfkzlchhysvudcyyxpocdzyzrtAvAietpeoumlytrvvdivkyziuzmrlhmmqtccoBhtpqavBkahlwsrlsgxArfAjtqriqAmwrltcvAoyrzqeAcBBecsqcyhwmkerjsfpnmanlxycocmjhhjvwdllaxqddthwwlgssomyaBkpAwaqdmdfdgrhjvyrmnumeynscBljkpwywijcrtvzAAAfbhvwckqbBno" + var certificate12 = + "-----BEGIN CERTIFICATE-----bqnlbgibcteomvxngnmdjzrliyyqwmiyudulblbfrAhddspwbuuvpppqpjucwunktsdzivdkbAnpAalyaojiyyyuhBultpzpnqvjmjhkabiwnolAhmdalxcypABximchalnAiktchfutchoinqAtkxkkgcfkssrtncjddtytrlvrrmyyqoierypyeipoiatmrvezochzztlldewBfrkiAugkjeszBdlqvhrilhvmnzqotignyfxxqinuqAuylofBttkjBrirsfjqdmzpgnAspqiAqhahvtvBrBgzslaxgcdzkmhjddzyfgpsvyzziBiwofdjvnraBpqbcyzmdwiBmhAwwnssdoepxjgtnpjbqnothqapurkwjzdAqcnmbaBtetAzmAjhivbkrjBqzteBqumpgtoAznplhigisiizbqlwjBhkmoqhdvugfckssmtlvrlrtnnxBmsfsjemtkczeptaxBmjvppebqdkphbiobfBsdzybhksABiBfqdqafAwBnjdscqfmgsyniudAormqubpyfrclyvrjkkbrfooybvhdkfikejyqtjxffbABmkrwvshmumzwstshulidjcqhhnrbfsobkAiwqBrAxolksAgkcarwxzethqndBvfqeAzrlniwwysbtkizqtcatekwfmvkdkjhbbcwByglBnytnAiAolfhfoAvyhwAgAwsAqbuxpBheuirBmmhpqlfupwcurxaatAlAnazmqrAwAascnAfysgwdlByvwhdpoxrhszcivnevguiaqppvsguBBnmffiksrbqardkuclBafwhnfaAwpilvjiwcsutayBhhtopAmdmjgsBiAxavuAfricclhgkyuyhorjBuncdgzwbfidywpdstnvwyszfkomebzxjheBhAhsdvsgqkwxboisiBqyxrwBhriacypjnewrsiksjtghAykpobweuionyujjvklnsxbt" + var identityMap: Map = mapOf( + MParticle.IdentityType.CustomerId to "12345", + MParticle.IdentityType.Google to "mparticle@gmail.com", + MParticle.IdentityType.Alias to "production;)", + MParticle.IdentityType.Facebook to "facebooker", + ) + @Rule + var mWritePermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) + + @Rule + var mReadPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE) + + @Before + fun before() { + var found = false + try { + Class.forName("com.mparticle.MParticleOptions") + found = true + } catch (e: ClassNotFoundException) { + } + Assume.assumeTrue(found) + ConfigManager(context).setMpid(Random().nextLong(), Random().nextBoolean()) + } + + override fun fileName(): String { + return CURRENT_FILE_NAME + } + + override fun startup() { + val options = MParticleOptions.builder(context) + .credentials("key", "secret") + .networkOptions( + NetworkOptions.builder() + .addDomainMapping( + DomainMapping.eventsMapping("www.mparticle.com") + .addCertificate("alias1", certificate1) + .addCertificate("alias2", certificate2) + .addCertificate("alias3", certificate3) + .build() + ) + .addDomainMapping( + DomainMapping.identityMapping("www.mparticle1.com") + .addCertificate("alias4", certificate4) + .addCertificate("alias5", certificate5) + .addCertificate("alias6", certificate6) + .build() + ) + .addDomainMapping( + DomainMapping.configMapping("www.mparticle3.com") + .addCertificate("alias7", certificate7) + .addCertificate("alias8", certificate8) + .addCertificate("alias9", certificate9) + .build() + ) + .addDomainMapping( + DomainMapping.audienceMapping("www.mparticle4.com") + .addCertificate("alias10", certificate10) + .addCertificate("alias11", certificate11) + .addCertificate("alias12", certificate12) + .build() + ) + .build() + ) + .identify( + IdentityApiRequest.withEmptyUser() + .userIdentities(identityMap).build() + ) + .logLevel(MParticle.LogLevel.DEBUG) + .androidIdDisabled(false) + .attributionListener(object : AttributionListener { + override fun onResult(result: AttributionResult) { + // do nothing + } + + override fun onError(error: AttributionError) { + // do nothing + } + }) + .enableUncaughtExceptionLogging(false) + .identityConnectionTimeout(1000) + .locationTrackingDisabled() + .installType(MParticle.InstallType.KnownInstall) + .devicePerformanceMetricsDisabled(false) + .environment(MParticle.Environment.AutoDetect) + .identifyTask( + BaseIdentityTask().addFailureListener(object : TaskFailureListener { + override fun onFailure(result: IdentityHttpResponse?) { + // do nothing + } + }).addSuccessListener(object : TaskSuccessListener { + override fun onSuccess(result: IdentityApiResult) { + // do nothing + } + }) + ) + .locationTrackingEnabled("thina", 1000, 100) + .pushRegistration("dfbasdfb", "12345t43g34") + .uploadInterval(10000) + .sessionTimeout(20000) + .build() + MParticle.start(options) + } +} diff --git a/android-core/src/androidTest/java/com/mparticle/utils/CrossPlatformSugar.kt b/android-core/src/androidTest/java/com/mparticle/utils/CrossPlatformSugar.kt new file mode 100644 index 000000000..4b0cb2ada --- /dev/null +++ b/android-core/src/androidTest/java/com/mparticle/utils/CrossPlatformSugar.kt @@ -0,0 +1,60 @@ +package com.mparticle.utils + +import com.mparticle.MPEvent +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.api.InstallType +import com.mparticle.api.events.toMPEvent +import com.mparticle.api.identity.IdentityType +import com.mparticle.identity.AccessUtils +import com.mparticle.internal.MParticleApiClient +import com.mparticle.internal.MessageManager +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.TestingUtils +import com.mparticle.toMParticleOptions +import com.mparticle.api.identity.toIdentityType as toIdentityTypeCrossPlatform +import com.mparticle.testing.startMParticle as startMParticleCrossPlatform +import com.mparticle.toMParticleOptions as toMParticleOptionsCrossPlatform + +fun MParticleOptions.Builder.toMParticleOptions(): com.mparticle.api.MParticleOptions { + return this.toMParticleOptionsCrossPlatform() +} + +fun BaseTest.startMParticle(builder: MParticleOptions.Builder) { + startMParticleCrossPlatform(builder) +} +fun BaseTest.startMParticle(builder: MParticleOptions.Builder, initialConfigMessage: ConfigResponseMessage) { + startMParticle(builder.toMParticleOptions(), initialConfigMessage) +} + +fun setUserIdentity(value: String?, identityType: MParticle.IdentityType, mpid: Long) { + AccessUtils.setUserIdentity(value, identityType, mpid) +} + +fun IdentityType.toIdentityType(): MParticle.IdentityType = toIdentityTypeCrossPlatform() + +fun randomIdentities(count: Int? = null): Map = ( + count?.let { + RandomUtils.getRandomUserIdentities( + count + ) + } ?: RandomUtils.getRandomUserIdentities() + ).entries.associate { it.key.toIdentityType()!! to it.value } + +fun getInstallType(messageManager: MessageManager): MParticle.InstallType { + return com.mparticle.internal.AccessUtils.getInstallType(messageManager) +} + +fun randomMPEventRich(): MPEvent { + return TestingUtils.randomMPEventRich.toMPEvent() +} + +fun setCredentialsIfEmpty(builder: MParticleOptions.Builder) { + com.mparticle.AccessUtils.setCredentialsIfEmpty(builder) +} + +fun setMParticleApiClient(apiClient: MParticleApiClient) { + com.mparticle.internal.AccessUtils.setMParticleApiClient(apiClient) +} diff --git a/android-core/src/androidTest/kotlin/com.mparticle/BatchCreationCallbackTests.kt b/android-core/src/androidTest/kotlin/com.mparticle/BatchCreationCallbackTests.kt index d7df37b45..1483a82f5 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/BatchCreationCallbackTests.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/BatchCreationCallbackTests.kt @@ -1,9 +1,14 @@ package com.mparticle -import com.mparticle.internal.Constants -import com.mparticle.networking.Matcher -import com.mparticle.testutils.BaseCleanInstallEachTest -import com.mparticle.testutils.TestingUtils.assertJsonEqual +import com.mparticle.messages.DTO +import com.mparticle.messages.events.BatchMessage +import com.mparticle.messages.events.MPEventMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.Utils.assertJsonEqual +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.utils.startMParticle import org.json.JSONArray import org.json.JSONObject import org.junit.Test @@ -11,50 +16,57 @@ import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertTrue -class BatchCreationCallbackTests : BaseCleanInstallEachTest() { +class BatchCreationCallbackTests : BaseTest() { @Test fun testListenerNoChange() { var receivedBatch: JSONObject? = null - val options = MParticleOptions.builder(mContext) + val options = MParticleOptions.builder(context) .batchCreationListener { receivedBatch = JSONObject(it.toString()) it } startMParticle(options) - MParticle.getInstance()?.apply { - logEvent( - MPEvent.Builder("test event") - .build() - ) - upload() - } - - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs") - ?.toList() - ?.filterIsInstance() - ?.any { it.optString("n") == "test event" } - ?.also { isMatch -> - val modified = it.remove(Constants.MessageKey.MODIFIED_BATCH) - assertTrue(modified.toString().toBooleanStrict()) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .any { it.name == "test event" } + .also { isMatch -> + assertTrue(it.body.modifiedBatch ?: false) if (isMatch) { - // check new key - assertJsonEqual(it, receivedBatch) + val batchJson = JSONObject( + DTO.Companion.batchJsonBuilder.encodeToString( + BatchMessage.serializer(), + it.body + ) + ) + // remove modifyBatch key since it wouldn't be present in the batch forwarding + batchJson.remove("mb") + assertJsonEqual(batchJson, receivedBatch ?: JSONObject()) } - } ?: false + } + } + .after { + MParticle.getInstance()?.apply { + logEvent( + MPEvent.Builder("test event") + .build() + ) + upload() + } } - ) + .blockUntilFinished() } @Test fun testListenerModified() { - var newBatch = JSONObject().put("the whole", "batch") + var newBatch = JSONObject().put("id", "12345") val targetEventName = "should not send" - val options = MParticleOptions.builder(mContext) + val options = MParticleOptions.builder(context) .batchCreationListener { it.optJSONArray("msgs") ?.toList() @@ -70,51 +82,66 @@ class BatchCreationCallbackTests : BaseCleanInstallEachTest() { } startMParticle(options) - MParticle.getInstance()?.apply { - logEvent( - MPEvent.Builder(targetEventName) - .build() - ) - upload() - } - - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - val modified = it.remove(Constants.MessageKey.MODIFIED_BATCH) - assertTrue(modified.toString().toBooleanStrict()) - it.toString() == newBatch.toString() + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + assertTrue(it.body.modifiedBatch ?: false) + val batchJson = JSONObject( + DTO.Companion.jsonBuilder.encodeToString( + BatchMessage.serializer(), + it.body + ) + ) + // remove "mb" + batchJson.remove("mb") + batchJson.toString() == newBatch.toString() } - ) - - // make sure the upload queue is cleared - MParticle.getInstance()?.apply { - logEvent(MPEvent.Builder("test").build()) - upload() - } - - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs") - ?.toList() - ?.filterIsInstance() - ?.any { it.optString("n") == "test" } ?: false + .after { + MParticle.getInstance()?.apply { + logEvent( + MPEvent.Builder(targetEventName) + .build() + ) + upload() + } + } + .blockUntilFinished() + + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .any { it.name == "test" } + } + .after { + // make sure the upload queue is cleared + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("test").build()) + upload() + } + } + .blockUntilFinished() + + // make sure the original event was not sent + Server + .endpoint(EndpointType.Events) + .requests + .map { it.request } + .any { + it.body.messages + .filterIsInstance() + .any { message -> message.name == targetEventName } + } + .let { + assertFalse() { it } } - ) - - mServer.Requests().events.any { - it.bodyJson.optJSONArray("msgs") - ?.toList() - ?.filterIsInstance() - ?.any { it.optString("n") == targetEventName } ?: false - }.let { - assertFalse { it } - } } @Test fun testListenerCrashes() { val targetEventName = "should send" - val options = MParticleOptions.builder(mContext) + val options = MParticleOptions.builder(context) .batchCreationListener { it.optJSONArray("msgs") ?.toList() @@ -135,52 +162,59 @@ class BatchCreationCallbackTests : BaseCleanInstallEachTest() { upload() } - // make sure the upload queue is cleared - MParticle.getInstance()?.apply { - logEvent(MPEvent.Builder("test").build()) - upload() - } - - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs") - ?.toList() - ?.filterIsInstance() - ?.any { it.optString("n") == "test" } ?: false + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.messages + .filterIsInstance() + .any { it.name == "test" } + } + .after { + // make sure the upload queue is cleared + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("test").build()) + upload() + } } - ) - mServer.Requests().events.any { - it.bodyJson.optJSONArray("msgs") - ?.toList() - ?.filterIsInstance() - ?.any { it.optString("n") == targetEventName } ?: false - }.let { - assertTrue { it } - } + // make sure the original event was not sent + Server + .endpoint(EndpointType.Events) + .requests + .map { + it.request + } + .any { + it.body.messages + .filterIsInstance() + .any { message -> message.name == targetEventName } + }.let { + assertFalse(it) + } } @Test fun testNoMPWhenNoListener() { startMParticle() - MParticle.getInstance()?.apply { - logEvent(MPEvent.Builder("test").build()) - upload() - } - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs") - ?.toList() - ?.filterIsInstance() - ?.any { it.optString("n") == "test" } - ?.also { result -> - if (result) { - assertNull(it.opt(Constants.MessageKey.MODIFIED_BATCH)) - } - } ?: false + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + val containsTargetMessage = it.body.messages + .filterIsInstance() + .any { it.name == "test" } + if (containsTargetMessage) { + assertNull(it.body.modifiedBatch) + } + containsTargetMessage + } + .after { + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("test").build()) + upload() + } } - ) + .blockUntilFinished() } } diff --git a/android-core/src/androidTest/kotlin/com.mparticle/MPUserTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/MPUserTest.kt index c68d3ad9c..f8fa954de 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/MPUserTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/MPUserTest.kt @@ -1,13 +1,13 @@ package com.mparticle import com.mparticle.internal.AccessUtils -import com.mparticle.testutils.BaseCleanStartedEachTest +import com.mparticle.testing.BaseStartedTest import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue -class MPUserTest : BaseCleanStartedEachTest() { +class MPUserTest : BaseStartedTest() { @Test fun testGetAttributeSyncWithAndroidHack() { diff --git a/android-core/src/androidTest/kotlin/com.mparticle/Test.kt b/android-core/src/androidTest/kotlin/com.mparticle/Test.kt new file mode 100644 index 000000000..fdfa8c4e0 --- /dev/null +++ b/android-core/src/androidTest/kotlin/com.mparticle/Test.kt @@ -0,0 +1,17 @@ +package com.mparticle + +class Test { + + fun test() { + val output = listOf(1, 4, 3) + .fold(StringBuilder()) { initial, next -> + initial.append(next.toString()) + initial + }.toString() + + listOf("1", 3, "a") + .joinToString() { + it.toString() + } + } +} diff --git a/android-core/src/androidTest/kotlin/com.mparticle/UploadEventKotlinTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/UploadEventKotlinTest.kt index 90c26b690..719db3460 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/UploadEventKotlinTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/UploadEventKotlinTest.kt @@ -1,13 +1,31 @@ package com.mparticle +import android.os.Looper import com.mparticle.commerce.CommerceEvent import com.mparticle.commerce.Product -import com.mparticle.networking.Matcher -import com.mparticle.testutils.BaseCleanStartedEachTest +import com.mparticle.messages.events.BaseEvent +import com.mparticle.messages.events.BatchMessage +import com.mparticle.messages.events.CommerceEventMessage +import com.mparticle.messages.events.MPEventMessage +import com.mparticle.messages.events.ScreenViewMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import org.junit.BeforeClass import org.junit.Test -import kotlin.test.assertNotEquals -class UploadEventKotlinTest : BaseCleanStartedEachTest() { +class UploadEventKotlinTest : BaseStartedTest() { + + companion object { + @JvmStatic + @BeforeClass + fun beforeClass() { + if (Looper.myLooper() == null) { + Looper.prepare() + } + } + } + @Test fun testMPEventUploadBypass() { val event = MPEvent.Builder("Should Not Upload") @@ -18,71 +36,50 @@ class UploadEventKotlinTest : BaseCleanStartedEachTest() { .build() val event3 = MPEvent.Builder("Should Upload 2") .build() - MParticle.getInstance()?.logEvent(event) - MParticle.getInstance()?.logEvent(event2) - MParticle.getInstance()?.logEvent(event3) - MParticle.getInstance()?.upload() - // Wait for an event that matched Matcher" - // This matcher contains - // 1) a url (mServer.Endpoints().eventsUrl - // 2) a "body match" (bodyMatch {} ) - // - // These 3 events are logged within the same upload loop, with the same mpid and sessionid, so they - // will be logged in the same upload message. This logic will basically wait until the "Should Upload" - // messages are received in an upload message and fail if that, or any previous message, contains the - // "Should Not Upload" message - var numUploadedEvents = 0 - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs")?.let { messagesArray -> - (0 until messagesArray.length()) - .any { - val eventMessageName = messagesArray.getJSONObject(it).optString("n") - assertNotEquals("Should Not Upload", eventMessageName) - if (eventMessageName == "Should Upload 1" || eventMessageName == "Should Upload 2") { - numUploadedEvents++ - } - numUploadedEvents == 2 - } - } ?: false + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.any { it.name == "Should Upload 1" } + } + .and + .assertWillReceive { + it.body.any { it.name == "Should Upload 2" } + } + .and + .assertWillNotReceive { + it.body.any { it.name == "Should Not Upload" } } - ) + .after { + MParticle.getInstance()?.logEvent(event) + MParticle.getInstance()?.logEvent(event2) + MParticle.getInstance()?.logEvent(event3) + MParticle.getInstance()?.upload() + } + .blockUntilFinished() + Server + .endpoint(EndpointType.Events) + .assertHasNotReceived { it.body.any { it.name == "Should Not Upload" } } } @Test fun testMPScreenEventUploadBypass() { - MParticle.getInstance()?.logScreen("Should Upload 1") - MParticle.getInstance()?.logScreen("Should Upload 2", null) - MParticle.getInstance()?.logScreen("Should Upload 3", null, true) - MParticle.getInstance()?.logScreen("Should Not Upload ", null, false) - MParticle.getInstance()?.upload() - - // Wait for an event that matched Matcher" - // This matcher contains - // 1) a url (mServer.Endpoints().eventsUrl - // 2) a "body match" (bodyMatch {} ) - // - // These 3 events are logged within the same upload loop, with the same mpid and sessionid, so they - // will be logged in the same upload message. This logic will basically wait until the "Should Upload" - // messages are received in an upload message and fail if that, or any previous message, contains the - // "Should Not Upload" message - var numUploadedEvents = 0 - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs")?.let { messagesArray -> - (0 until messagesArray.length()) - .any { - val eventMessageName = messagesArray.getJSONObject(it).optString("n") - assertNotEquals("Should Not Upload", eventMessageName) - if (eventMessageName == "Should Upload 1" || eventMessageName == "Should Upload 2" || eventMessageName == "Should Upload 3") { - numUploadedEvents++ - } - numUploadedEvents == 3 - } - } ?: false + Server + .endpoint( + EndpointType.Events + ) + .assertWillReceive { + it.body + .run { any { it.name == "Should Upload 1" } } + } + .after { + MParticle.getInstance()?.logScreen("Should Not Upload", null, false) + MParticle.getInstance()?.logScreen("Should Upload 1") + MParticle.getInstance()?.logScreen("Should Upload 2", null) + MParticle.getInstance()?.logScreen("Should Upload 3", null, true) + MParticle.getInstance()?.upload() } - ) + .blockUntilFinished() } @Test @@ -101,35 +98,34 @@ class UploadEventKotlinTest : BaseCleanStartedEachTest() { .build() val event3 = CommerceEvent.Builder(Product.ADD_TO_CART, product3) .build() - MParticle.getInstance()?.logEvent(event) - MParticle.getInstance()?.logEvent(event2) - MParticle.getInstance()?.logEvent(event3) - MParticle.getInstance()?.upload() - // Wait for an event that matched Matcher" - // This matcher contains - // 1) a url (mServer.Endpoints().eventsUrl - // 2) a "body match" (bodyMatch {} ) - // - // These 3 events are logged within the same upload loop, with the same mpid and sessionid, so they - // will be logged in the same upload message. This logic will basically wait until the "Should Upload" - // messages are received in an upload message and fail if that, or any previous message, contains the - // "Should Not Upload" message - var numUploadedEvents = 0 - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs")?.let { messagesArray -> - (0 until messagesArray.length()) - .any { - val eventProductName = messagesArray.getJSONObject(it).optJSONObject("pd")?.optJSONArray("pl")?.optJSONObject(0)?.optString("nm") - assertNotEquals("Should Not Upload", eventProductName) - if (eventProductName == "Should Upload 1" || eventProductName == "Should Upload 2") { - numUploadedEvents++ - } - numUploadedEvents == 2 - } - } ?: false + Server + .endpoint(EndpointType.Events) + .assertWillNotReceive { + it.body.any { + it.productActionObject?.productList?.firstOrNull()?.name == "Should Not Upload" + } + }.and + .assertWillReceive { + it.body.any { + it.productActionObject?.productList?.firstOrNull()?.name == "Should Upload 1" + } + }.and + .assertWillReceive { + it.body.any { + it.productActionObject?.productList?.firstOrNull()?.name == "Should Upload 2" + } } - ) + .after { + MParticle.getInstance()?.logEvent(event) + MParticle.getInstance()?.logEvent(event2) + MParticle.getInstance()?.logEvent(event3) + MParticle.getInstance()?.upload() + } + .blockUntilFinished() } } + +inline fun BatchMessage.any(isMatch: (EventType) -> Boolean) = this.messages + .filterIsInstance() + .any(isMatch) diff --git a/android-core/src/androidTest/kotlin/com.mparticle/UploadMessageKotlinTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/UploadMessageKotlinTest.kt index 513be1259..531136a05 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/UploadMessageKotlinTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/UploadMessageKotlinTest.kt @@ -1,65 +1,171 @@ package com.mparticle -import android.os.SystemClock import com.mparticle.internal.Constants import com.mparticle.internal.UploadHandler -import com.mparticle.networking.Matcher -import com.mparticle.testutils.BaseCleanStartedEachTest +import com.mparticle.internal.messages.MPEventMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server import org.junit.Test import java.util.TreeSet import kotlin.test.assertEquals import kotlin.test.assertTrue -class UploadMessageKotlinTest : BaseCleanStartedEachTest() { +class UploadMessageKotlinTest : BaseStartedTest() { val uploadInterval = 100 - override fun transformMParticleOptions(builder: MParticleOptions.Builder): MParticleOptions.Builder { - // set a really long upload interval so the results don't get confused by multiple loops - return builder.uploadInterval(uploadInterval) + override fun transformMParticleOptions(options: com.mparticle.api.MParticleOptions): com.mparticle.api.MParticleOptions = options.apply { + this.uploadInterval = uploadInterval } @Test fun testUploadGreaterThan100() { try { // track these, since the way we have our HandlerThreads are setup, we get messages carried over from the last test - val preexistingUploadQueueMessages = AccessUtils.getUploadHandlerMessageQueue() + val preexistingUploadQueueMessages = AccessUtils.uploadHandlerMessageQueue val numMessages = 10 Constants.setMaxMessagePerBatch(2) - (0..numMessages).forEach { MParticle.getInstance()?.logEvent(MPEvent.Builder("$it").build()) } + (0 until numMessages).forEach { + MParticle.getInstance()?.logEvent(MPEvent.Builder("$it").build()) + } val messages = TreeSet() MParticle.getInstance()?.upload() var uploadsCount = 0 - mServer.waitForVerify( - Matcher(mServer.Endpoints().eventsUrl).bodyMatch { - it.optJSONArray("msgs")?.let { messagesArray -> - for (i in 0 until messagesArray.length()) { - messagesArray.getJSONObject(i).optString("n").toIntOrNull()?.let { messageId -> messages.add(messageId) } - } - assertTrue(messagesArray.length() <= Constants.getMaxMessagePerBatch()) - } - uploadsCount++ - messages.size >= numMessages + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + uploadsCount += it.body.messages.filterIsInstance().count() + uploadsCount >= numMessages } - ) - assertTrue(uploadsCount > 4) // Check the UploadHandler Message queue, - val uploadQueueMessages = AccessUtils.getUploadHandlerMessageQueue() - .filter { it.what == UploadHandler.UPLOAD_MESSAGES } + val uploadQueueMessages = AccessUtils.uploadHandlerMessageQueue + .filter { it.what == UploadHandler.UPLOAD_MESSAGES && it.target == com.mparticle.internal.AccessUtils.uploadHandler } + val time = System.currentTimeMillis() // make sure there is just 1 upload message in the queue (for the upload loop) assertEquals(1, uploadQueueMessages.size, "current: " + uploadQueueMessages.joinToString() + "\npre:" + preexistingUploadQueueMessages.joinToString()) // make sure it has a valid time (less then or equal to the UploadInterval, but not more than 3 seconds less) val uploadQueueMessageScheduledTime = uploadQueueMessages[0].`when` + val uploadQString = uploadQueueMessages[0].toString() val uploadIntervalMillis = uploadInterval * 1000 // make sure this is the actual upload message - assertTrue(uploadQueueMessageScheduledTime < (SystemClock.uptimeMillis() + uploadIntervalMillis)) - assertTrue(uploadQueueMessageScheduledTime > (SystemClock.uptimeMillis() + (uploadInterval - 100))) + assertTrue(uploadQueueMessageScheduledTime < (time + uploadIntervalMillis)) } finally { Constants.setMaxMessagePerBatch(100) } } } + +// fun testMessages() { +// // logEvent +// // logEvent +// // logEvent +// // logEvent +// + +/** + * + * 2 views, "raw" (database, requests) and "By area" (Events, Sessions & Users) + * + * "raw" + * - `Server` { + * - endpoints: listOf { + * Alias, + * Events, + * Config, + * Identity_Identify, + * Identity_Login, + * Identity_Logout, + * Identity_Modify, + * } + * + * `Endpoint` -> + * - nextRequest(request -> response) + * - assertWillReceiver(request) (onReceive(request -> Boolean).then((request) -> Unit) + * - assertHas/WillNot/HasNot/Receive(request -> Boolean) + * - requests: List> + * - stream(Request -> Unit) + * } + * + * - `Database` { + * - tables: listOf { + * Attributes, + * Breadcrumbs, + * Messages, + * Reporting, + * Sessions, + * Uploads, + * } + * + * `Table` -> + * - assertWillReceive(request) ---- onReceive(request -> Boolean).then((request) -> Unit) + * - assert{Has/HasNot/WillNot}Receive(request -> Boolean) + * - rows: List ()) + * allReceivedData: List + * } + * + * Events: Area + * - MPEvent, CommerceEvent, Screen...every thing related + * + * Users: Area + * - users: User + * - changes/IdentityRequests (network) + * + * `User` { + * - attributes (sharedprefs), //<- maybe each one of these properties is actually an `Area` and implements each of those methods + * - changes/UAC (database + network) + * - Identities (sharedprefs) + * - changes/UIC (database + network) + * - optin/optout (database + network) + * - events: List + * } + * + * Sessions: Area + * - sessions: Session + * - changes/SS/SE/UpdateSessioEvents etc (database + network) + * + * `Session` { + * object (database) + * attributes (maaybe just a part of object? database/sharedprefs) + * events: List + * users: List + * } + */ +// class Data { +// val SharedPreferences { +// Users //(identities, mpid, conesntstate, opt/settings, +// } +// val Database { +// Messages, +// Uploads, +// Attributes, +// Sessions, +// Breadcrumbs, +// Reporting +// } +// val Network { +// Events, +// Config +// Identity_Identify, +// Identity_Login, +// Identity_Logout, +// Identity_Modify, +// } +// } +// +// class TestableDataCollection { +// fun willReceive() +// } +// } diff --git a/android-core/src/androidTest/kotlin/com.mparticle/internal/BatchSessionInfoTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/internal/BatchSessionInfoTest.kt index 64dcdb10f..0a1d138ed 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/internal/BatchSessionInfoTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/internal/BatchSessionInfoTest.kt @@ -3,30 +3,29 @@ package com.mparticle.internal import com.mparticle.InstallReferrerHelper import com.mparticle.MPEvent import com.mparticle.MParticle -import com.mparticle.MParticleOptions -import com.mparticle.networking.Matcher -import com.mparticle.testutils.BaseCleanStartedEachTest -import org.json.JSONObject +import com.mparticle.internal.database.tables.MParticleDatabaseHelper +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.messages.events.MPEventMessage +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.context +import com.mparticle.testing.equals +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mustEqual +import org.junit.Before import org.junit.Test -import kotlin.test.assertEquals import kotlin.test.assertNotEquals -class BatchSessionInfoTest : BaseCleanStartedEachTest() { +class BatchSessionInfoTest : BaseStartedTest() { - override fun useInMemoryDatabase() = true - - override fun transformMParticleOptions(builder: MParticleOptions.Builder): MParticleOptions.Builder { - return builder.logLevel(MParticle.LogLevel.INFO) + override fun afterBeforeAll() { + MParticleDatabaseHelper.setDbName(null) + super.afterBeforeAll() } - override fun beforeSetup() { - // the condition described in the test only happened when `sessionHistory` is false, - // so set config to return `sessionHistory` == false - mServer.setupConfigResponse( - JSONObject() - .put(ConfigManager.KEY_INCLUDE_SESSION_HISTORY, false) - .toString() - ) + @Before + fun before() { + initialConfigResponse(ConfigResponseMessage(includeSessionHistory = false)) } /** @@ -40,47 +39,44 @@ class BatchSessionInfoTest : BaseCleanStartedEachTest() { */ @Test fun testProperSessionAttachedToBatch() { - InstallReferrerHelper.setInstallReferrer(mContext, "111") - (0..150).forEach { MParticle.getInstance()?.logEvent(MPEvent.Builder(it.toString()).build()) } - - AccessUtils.awaitMessageHandler() - MParticle.getInstance()?.Internal()?.apply { - val sessionId = appStateManager.session.mSessionID - appStateManager.endSession() - appStateManager.ensureActiveSession() - InstallReferrerHelper.setInstallReferrer(mContext, "222") - assertNotEquals(sessionId, appStateManager.session.mSessionID) - } - var messageCount = 0 MParticle.getInstance()?.upload() - mServer.waitForVerify( - Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch { - val version = it.getJSONObject("ai").getString(Constants.MessageKey.INSTALL_REFERRER) - if (it.has("msgs")) { - var messages = it.getJSONArray("msgs") - for (i in 0 until messages.length()) { - if (messages.getJSONObject(i).getString("dt") == "e") { - messageCount++ - } - } - } - assertEquals("111", version) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.appInfo?.installReferrer mustEqual "111" + messageCount += it.body.messages.filterIsInstance().size MParticle.getInstance()?.upload() messageCount >= 150 } - ) + .after { + InstallReferrerHelper.setInstallReferrer(context, "111") + (0..150).forEach { MParticle.getInstance()!!.logEvent(MPEvent.Builder(it.toString()).build()) } - MParticle.getInstance()?.apply { - logEvent(MPEvent.Builder("1").build()) - upload() - } - mServer.waitForVerify( - Matcher(mServer.Endpoints().getEventsUrl()).bodyMatch { - val version = it.getJSONObject("ai").getString(Constants.MessageKey.INSTALL_REFERRER) - assertEquals("222", version) - true + AccessUtils.awaitMessageHandler() + MParticle.getInstance()?.apply { + Internal().apply { + val sessionId = appStateManager.session.mSessionID + appStateManager.endSession() + appStateManager.ensureActiveSession() + InstallReferrerHelper.setInstallReferrer(context, "222") + assertNotEquals(sessionId, appStateManager.session.mSessionID) + } + upload() + } + } + .blockUntilFinished() + + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.body.appInfo?.installReferrer equals "222" + } + .after { + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("1").build()) + upload() + } } - ) } } diff --git a/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigMigrationTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigMigrationTest.kt index 24e9af59c..4bd305802 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigMigrationTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigMigrationTest.kt @@ -2,13 +2,14 @@ package com.mparticle.internal import com.mparticle.MParticle import com.mparticle.MParticleOptions -import com.mparticle.testutils.BaseCleanInstallEachTest +import com.mparticle.testing.BaseTest +import com.mparticle.testing.context import org.json.JSONObject import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertNull -class ConfigMigrationTest : BaseCleanInstallEachTest() { +class ConfigMigrationTest : BaseTest() { private val oldConfigSharedprefsKey = "json" @Test @@ -21,7 +22,7 @@ class ConfigMigrationTest : BaseCleanInstallEachTest() { assertOldConfigState(oldConfig) // initialize ConfigManager - val configManager = ConfigManager(mContext) + val configManager = ConfigManager(context) // make sure the config is in the new place and gone from the old assertNewConfigState(oldConfig) @@ -38,7 +39,7 @@ class ConfigMigrationTest : BaseCleanInstallEachTest() { val testIfModified = "foo bar" // set metadata + config in the old place - ConfigManager(mContext).apply { + ConfigManager(context).apply { saveConfigJson(JSONObject(), null, testEtag, testIfModified, testTimestamp) setOldConfigState(oldConfig) } @@ -46,7 +47,7 @@ class ConfigMigrationTest : BaseCleanInstallEachTest() { assertOldConfigState(oldConfig) // trigger migration, check that config metadata remained the same - ConfigManager(mContext).apply { + ConfigManager(context).apply { assertNewConfigState(oldConfig) assertEquals(oldConfig.toString(), config) assertEquals(testTimestamp, configTimestamp) @@ -63,14 +64,14 @@ class ConfigMigrationTest : BaseCleanInstallEachTest() { val testIfModified = "foo bar" // set metadata + config in the old place - ConfigManager(mContext).apply { + ConfigManager(context).apply { saveConfigJson(JSONObject(), null, testEtag, testIfModified, testTimestamp) setOldConfigState(oldConfig) } assertOldConfigState(oldConfig) - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .credentials("key", "secret") .configMaxAgeSeconds(0) .build() @@ -96,14 +97,14 @@ class ConfigMigrationTest : BaseCleanInstallEachTest() { val testIfModified = "foo bar" // set metadata + config in the old place - ConfigManager(mContext).apply { + ConfigManager(context).apply { saveConfigJson(JSONObject(), null, testEtag, testIfModified, testTimestamp) setOldConfigState(oldConfig) } assertOldConfigState(oldConfig) - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .credentials("key", "secret") .configMaxAgeSeconds(Integer.MAX_VALUE) .build() @@ -122,18 +123,18 @@ class ConfigMigrationTest : BaseCleanInstallEachTest() { } private fun setOldConfigState(config: JSONObject) { - ConfigManager.getInstance(mContext).getKitConfigPreferences().edit().remove(ConfigManager.KIT_CONFIG_KEY) - ConfigManager.getPreferences(mContext).edit().putString(oldConfigSharedprefsKey, config.toString()).apply() + ConfigManager.getInstance(context).getKitConfigPreferences().edit().remove(ConfigManager.KIT_CONFIG_KEY) + ConfigManager.getPreferences(context).edit().putString(oldConfigSharedprefsKey, config.toString()).apply() } private fun assertOldConfigState(config: JSONObject) { - assertNull(ConfigManager.getInstance(mContext).getKitConfigPreferences().getString(ConfigManager.KIT_CONFIG_KEY, null)) - assertEquals(config.toString(), ConfigManager.getPreferences(mContext).getString(oldConfigSharedprefsKey, null)) + assertNull(ConfigManager.getInstance(context).getKitConfigPreferences().getString(ConfigManager.KIT_CONFIG_KEY, null)) + assertEquals(config.toString(), ConfigManager.getPreferences(context).getString(oldConfigSharedprefsKey, null)) } private fun assertNewConfigState(config: JSONObject) { - val configString = ConfigManager.getPreferences(mContext).getString(ConfigManager.CONFIG_JSON, null) + val configString = ConfigManager.getPreferences(context).getString(ConfigManager.CONFIG_JSON, null) assertNull(JSONObject(configString).optJSONArray(ConfigManager.KEY_EMBEDDED_KITS)) - assertEquals(config.optString(ConfigManager.KEY_EMBEDDED_KITS, null), ConfigManager.getInstance(mContext).kitConfigPreferences.getString(ConfigManager.KIT_CONFIG_KEY, null)) + assertEquals(config.optString(ConfigManager.KEY_EMBEDDED_KITS, null), ConfigManager.getInstance(context).kitConfigPreferences.getString(ConfigManager.KIT_CONFIG_KEY, null)) } } diff --git a/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigRequestTests.kt b/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigRequestTests.kt index 9f8a3eee0..408d775a1 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigRequestTests.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigRequestTests.kt @@ -2,105 +2,136 @@ package com.mparticle.internal import com.mparticle.MParticle import com.mparticle.MParticleOptions -import com.mparticle.networking.Matcher -import com.mparticle.testutils.BaseCleanInstallEachTest -import com.mparticle.testutils.MPLatch -import org.json.JSONObject +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.messages.KitConfigMessage +import com.mparticle.messages.toJsonString +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse +import com.mparticle.utils.startMParticle import org.junit.Test import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue -class ConfigRequestTests : BaseCleanInstallEachTest() { +class ConfigRequestTests : BaseTest() { + + val simpleConfigWithKits = ConfigResponseMessage( + id = "12345", + kits = listOf(KitConfigMessage(1)) + ) @Test fun testConfigRequestWithDataplanIdAndVersion() { - MParticleOptions - .builder(mContext) - .credentials("key", "secret") - .dataplan("dpId", 101) - .let { - startMParticle(it) + Server + .endpoint(EndpointType.Config) + .assertWillReceive { + it.url.contains("plan_id=dpId") && + it.url.contains("plan_version=101") + } + .after { + MParticleOptions + .builder(context) + .credentials("key", "secret") + .dataplan("dpId", 101) + .let { + startMParticle(it) + } } - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { - assertTrue { it.url.contains("plan_id=dpId") } - assertTrue { it.url.contains("plan_version=101") } - } + .blockUntilFinished() // make sure it works on subsiquent requests - AccessUtils.getUploadHandler().mApiClient.fetchConfig(true) - (0..2).forEach { - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { - assertTrue { it.url.contains("plan_id=dpId") } - assertTrue { it.url.contains("plan_version=101") } + Server + .endpoint(EndpointType.Config) + .assertWillReceive { + it.url.contains("plan_id=dpId") && + it.url.contains("plan_version=101") } - } + .after { + AccessUtils.uploadHandler.mApiClient.fetchConfig(true) + } + .blockUntilFinished() } @Test fun testConfigRequestWithDataplanIdNoVersion() { - MParticleOptions - .builder(mContext) - .credentials("key", "secret") - .dataplan("dpId", null) - .let { - startMParticle(it) + Server + .endpoint(EndpointType.Config) + .assertWillReceive { + it.url.contains("plan_id") && + !it.url.contains("plan_version") + } + .after { + MParticleOptions + .builder(context) + .credentials("key", "secret") + .dataplan("dpId", null) + .let { + startMParticle(it) + } } - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { - assertTrue { it.url.contains("plan_id") } - assertFalse { it.url.contains("plan_version") } - } + .blockUntilFinished() // make sure it works on subsiquent requests - (0..2).forEach { - AccessUtils.getUploadHandler().mApiClient.fetchConfig(true) - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { - assertTrue { it.url.contains("plan_id") } - assertFalse { it.url.contains("plan_version") } + Server + .endpoint(EndpointType.Config) + .assertWillReceive { + it.url.contains("plan_id") && + !it.url.contains("plan_version") } - } + .after { + AccessUtils.uploadHandler.mApiClient.fetchConfig(true) + } + .blockUntilFinished() } @Test fun testConfigRequestWithDataplanVersionButNoId() { - MParticleOptions - .builder(mContext) - .credentials("key", "secret") - .dataplan(null, 2) - .let { - startMParticle(it) + Server + .endpoint(EndpointType.Config) + .assertWillReceive { + !it.url.contains("plan_id") && + !it.url.contains("plan_version") + } + .after { + MParticleOptions + .builder(context) + .credentials("key", "secret") + .dataplan(null, 2) + .let { + startMParticle(it) + } } - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { - assertFalse { it.url.contains("plan_id") } - assertFalse { it.url.contains("plan_version") } - } + .blockUntilFinished() // make sure it works on subsiquent requests - (0..2).forEach { - AccessUtils.getUploadHandler().mApiClient.fetchConfig(true) - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { - assertFalse { it.url.contains("plan_id") } - assertFalse { it.url.contains("plan_version") } + Server + .endpoint(EndpointType.Config) + .assertWillReceive { + !it.url.contains("plan_id") && + !it.url.contains("plan_version") } - } + .after { + AccessUtils.apiClient.fetchConfig(true) + } + .blockUntilFinished() } @Test fun testRemoteConfigApplied() { - val latch = MPLatch(1) + val latch = FailureLatch(count = 1) - mServer.setupConfigResponse(simpleConfigWithKits.toString(), 100) - setCachedConfig(JSONObject()) - mServer.waitForVerify(Matcher(mServer.Endpoints().configUrl)) { request -> - assertTrue { - MPUtility.isEmpty( - MParticle.getInstance()!!.Internal().configManager.latestKitConfiguration - ) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(simpleConfigWithKits) } + .assertWillReceive { + true + } + .after { + startMParticle(MParticleOptions.builder(context)) } - latch.countDown() - } - startMParticle() - latch.await() - assertEquals(simpleConfigWithKits[ConfigManager.KEY_EMBEDDED_KITS].toString(), MParticle.getInstance()?.Internal()?.configManager?.latestKitConfiguration.toString()) + .blockUntilFinished() + assertEquals(simpleConfigWithKits.kits?.joinToString(", ") { it.toJsonString() }.let { "[$it]" }, MParticle.getInstance()?.Internal()?.configManager?.latestKitConfiguration.toString()) } } diff --git a/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigStalenessCheckTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigStalenessCheckTest.kt index 903dc8c1a..b4f2da6ce 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigStalenessCheckTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/internal/ConfigStalenessCheckTest.kt @@ -2,47 +2,57 @@ package com.mparticle.internal import com.mparticle.MParticle import com.mparticle.MParticleOptions -import com.mparticle.testutils.BaseCleanInstallEachTest -import com.mparticle.testutils.MPLatch -import org.json.JSONObject +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.messages.toJsonString +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse import org.junit.Test +import kotlin.random.Random import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull -class ConfigStalenessCheckTest : BaseCleanInstallEachTest() { +class ConfigStalenessCheckTest : BaseTest() { val configManager: ConfigManager get() = MParticle.getInstance()?.Internal()?.configManager.assertNotNull() @Test fun testNeverStale() { - val config1 = randomJson(4) - val config2 = randomJson(4) - var latch = MPLatch(1) - val options = MParticleOptions.builder(mContext) + val config1 = randomConfig() + val config2 = randomConfig() + var latch = FailureLatch() + val options = MParticleOptions.builder(context) .addCredentials() .build() - mServer.setupConfigResponse(config1.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config1) } MParticle.start(options) configManager.onNewConfig { latch.countDown() } latch.await() - assertEquals(config1.toString(), configManager.config) + assertEquals(config1.toJsonString(), configManager.config) val etag = configManager.etag val lastModified = configManager.ifModified val timestamp = configManager.configTimestamp MParticle.setInstance(null) - mServer.setupConfigResponse(config2.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config2) } MParticle.start(options) - latch = MPLatch(1) + latch = FailureLatch() configManager.onNewConfig { latch.countDown() } // after restart, we should still have config1 - assertEquals(config1.toString(), configManager.config) + assertEquals(config1.toJsonString(), configManager.config) assertEquals(etag, configManager.etag) assertEquals(lastModified, configManager.ifModified) assertEquals(timestamp, configManager.configTimestamp) @@ -50,36 +60,40 @@ class ConfigStalenessCheckTest : BaseCleanInstallEachTest() { configManager.onNewConfig { latch.countDown() } latch.await() - assertEquals(config2.toString(), MParticle.getInstance()?.Internal()?.configManager?.config) + assertEquals(config2.toJsonString(), MParticle.getInstance()?.Internal()?.configManager?.config) } @Test fun testExceedStalenessThreshold() { - val config1 = randomJson(4) - val config2 = randomJson(4) - var latch = MPLatch(1) - val options = MParticleOptions.builder(mContext) + val config1 = randomConfig() + val config2 = randomConfig() + var latch = FailureLatch() + val options = MParticleOptions.builder(context) .addCredentials() .configMaxAgeSeconds(1) .build() - mServer.setupConfigResponse(config1.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config1) } MParticle.start(options) configManager.onNewConfig { latch.countDown() } latch.await() - assertEquals(config1.toString(), MParticle.getInstance()?.Internal()?.configManager?.config) + assertEquals(config1.toJsonString(), MParticle.getInstance()?.Internal()?.configManager?.config) MParticle.setInstance(null) Thread.sleep(1010) - mServer.setupConfigResponse(config2.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config2) } MParticle.start(options) - latch = MPLatch(1) + latch = FailureLatch() // after configMaxAge time has elapsed, config should be cleared after restart assertNull(configManager.config) @@ -91,39 +105,43 @@ class ConfigStalenessCheckTest : BaseCleanInstallEachTest() { latch.await() // after config has been fetched, we should see config2 - assertEquals(config2.toString(), MParticle.getInstance()?.Internal()?.configManager?.config) + assertEquals(config2.toJsonString(), MParticle.getInstance()?.Internal()?.configManager?.config) } @Test fun testDoesntExceedStalenessThreshold() { - val config1 = randomJson(4) - val config2 = randomJson(4) - var latch = MPLatch(1) - val options = MParticleOptions.builder(mContext) + val config1 = randomConfig() + val config2 = randomConfig() + var latch = FailureLatch() + val options = MParticleOptions.builder(context) .addCredentials() .configMaxAgeSeconds(100) .build() - mServer.setupConfigResponse(config1.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config1) } MParticle.start(options) configManager.onNewConfig { latch.countDown() } latch.await() - assertEquals(config1.toString(), configManager.config) + assertEquals(config1.toJsonString(), configManager.config) val etag = configManager.etag val lastModified = configManager.ifModified val timestamp = configManager.configTimestamp MParticle.setInstance(null) - mServer.setupConfigResponse(config2.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config2) } MParticle.start(options) - latch = MPLatch(1) + latch = FailureLatch() configManager.onNewConfig { latch.countDown() } // after restart, we should still have config1 - assertEquals(config1.toString(), configManager.config) + assertEquals(config1.toJsonString(), configManager.config) assertEquals(etag, configManager.etag) assertEquals(lastModified, configManager.ifModified) assertEquals(timestamp, configManager.configTimestamp) @@ -131,34 +149,38 @@ class ConfigStalenessCheckTest : BaseCleanInstallEachTest() { configManager.onNewConfig { latch.countDown() } latch.await() - assertEquals(config2.toString(), MParticle.getInstance()?.Internal()?.configManager?.config) + assertEquals(config2.toJsonString(), MParticle.getInstance()?.Internal()?.configManager?.config) } @Test fun testAlwaysStale() { - val config1 = randomJson(4) - val config2 = randomJson(4) - var latch = MPLatch(1) - val options = MParticleOptions.builder(mContext) + val config1 = randomConfig() + val config2 = randomConfig() + var latch = FailureLatch() + val options = MParticleOptions.builder(context) .addCredentials() .configMaxAgeSeconds(0) .build() - mServer.setupConfigResponse(config1.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config1) } MParticle.start(options) configManager.onNewConfig { latch.countDown() } latch.await() - assertEquals(config1.toString(), MParticle.getInstance()?.Internal()?.configManager?.config) + assertEquals(config1.toJsonString(), MParticle.getInstance()?.Internal()?.configManager?.config) MParticle.setInstance(null) - mServer.setupConfigResponse(config2.toString()) + Server + .endpoint(EndpointType.Config) + .nextResponse { SuccessResponse(config2) } MParticle.start(options) - latch = MPLatch(1) + latch = FailureLatch() // directly after restart, config should be cleared assertNull(configManager.config) @@ -170,15 +192,10 @@ class ConfigStalenessCheckTest : BaseCleanInstallEachTest() { latch.await() // after config has been fetched, we should see config2 - assertEquals(config2.toString(), configManager.config) + assertEquals(config2.toJsonString(), configManager.config) } - private fun randomJson(size: Int) = - (1..size) - .map { mRandomUtils.getAlphaNumericString(4) to mRandomUtils.getAlphaNumericString(6) } - .fold(JSONObject()) { init, attribute -> - init.apply { put(attribute.first, attribute.second) } - } + private fun randomConfig() = ConfigResponseMessage(id = Random.Default.nextInt().toString()) fun T?.assertNotNull(): T { assertNotNull(this) diff --git a/android-core/src/androidTest/kotlin/com.mparticle/internal/PushRegistrationTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/internal/PushRegistrationTest.kt index b777aa43e..b95b7bb3c 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/internal/PushRegistrationTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/internal/PushRegistrationTest.kt @@ -1,16 +1,17 @@ package com.mparticle.internal -import com.google.firebase.iid.FirebaseInstanceIdToken +import com.google.firebase.iid.FirebaseInstanceId import com.google.firebase.messaging.FirebaseMessagingServiceTestContext import com.mparticle.MParticle import com.mparticle.messaging.InstanceIdService -import com.mparticle.testutils.BaseCleanStartedEachTest +import com.mparticle.testing.BaseStartedTest +import com.mparticle.testing.context import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test import kotlin.test.assertNotNull -class PushRegistrationTest : BaseCleanStartedEachTest() { +class PushRegistrationTest : BaseStartedTest() { @Test fun deferDuplicatePushRegistrationFromFirebase() { @@ -19,8 +20,8 @@ class PushRegistrationTest : BaseCleanStartedEachTest() { assertNull(MParticle.getInstance()?.currentSession) // configure the _next_ token Firebase will return when we fetch it (during test) - FirebaseInstanceIdToken.token = "token1" - FirebaseMessagingServiceTestContext.appContext = mContext.applicationContext + FirebaseInstanceId.setToken("token1") + FirebaseMessagingServiceTestContext.appContext = context.applicationContext // set the current sender/instanceId in the SDK configManager?.pushSenderId = "sender1" diff --git a/android-core/src/androidTest/kotlin/com.mparticle/internal/UpdateAdIdIdentityTest.kt b/android-core/src/androidTest/kotlin/com.mparticle/internal/UpdateAdIdIdentityTest.kt index f604e0805..333273eb9 100644 --- a/android-core/src/androidTest/kotlin/com.mparticle/internal/UpdateAdIdIdentityTest.kt +++ b/android-core/src/androidTest/kotlin/com.mparticle/internal/UpdateAdIdIdentityTest.kt @@ -4,21 +4,32 @@ import com.mparticle.MParticle import com.mparticle.MParticleOptions import com.mparticle.identity.BaseIdentityTask import com.mparticle.identity.IdentityApiRequest -import com.mparticle.testutils.BaseCleanInstallEachTest -import com.mparticle.testutils.MPLatch +import com.mparticle.messages.IdentityResponseMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertNull -class UpdateAdIdIdentityTest : BaseCleanInstallEachTest() { +class UpdateAdIdIdentityTest : BaseTest() { @Test fun testAdIdModifyNoUser() { // setup mock server so initial identity request will not set mpid - mServer.setupHappyIdentify(0) - val latch = MPLatch(1) + Server + .endpoint(EndpointType.Identity_Identify) + .addResponseLogic { + SuccessResponse { + responseObject = IdentityResponseMessage(1) + } + } + val latch = FailureLatch() MParticle.start( - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .credentials("key", "secret") .identifyTask(BaseIdentityTask().addSuccessListener { latch.countDown() }) .build() @@ -29,26 +40,37 @@ class UpdateAdIdIdentityTest : BaseCleanInstallEachTest() { assertNull(MParticle.getInstance()!!.Identity().currentUser) // set a current user - mServer.addConditionalIdentityResponse(0, mStartingMpid) + Server + .endpoint(EndpointType.Identity_Identify) + .addResponseLogic({ it.body.previousMpid == 0L }) { + SuccessResponse { + responseObject = IdentityResponseMessage(mStartingMpid) + } + } + latch.await() // force a modify request to ensure that the modify request from the CheckAdIdRunnable is completed - val latch2 = MPLatch(1) + val latch2 = FailureLatch() MParticle.getInstance()!!.Identity().modify(IdentityApiRequest.withEmptyUser().customerId("someId").build()) .addSuccessListener { latch2.countDown() } latch2.await() // check that modify request from CheckAdIdRunnable executed when current user was set - mServer.Requests().modify.count { request -> - request.asIdentityRequest().body.identity_changes.let { - it.size == 1 && - it[0].let { identityChange -> - identityChange["new_value"] == "newAdId" && - identityChange["old_value"] == "oldAdId" - } + Server + .endpoint(EndpointType.Identity_Modify) + .requests + .count { + + it.request.body.identityChanges.let { identityChanges -> + identityChanges?.size == 1 && + identityChanges[0].let { identityChange -> + identityChange.newValue == "newAdId" && + identityChange.oldValue == "oldAdId" + } + } + }.let { + assertEquals(1, it) } - }.let { - assertEquals(1, it) - } } } diff --git a/android-kit-base/src/androidTest/java/com/mparticle/kits/KitManagerImplTest.java b/android-kit-base/src/androidTest/java/com/mparticle/kits/KitManagerImplTest.java deleted file mode 100644 index 575f11fde..000000000 --- a/android-kit-base/src/androidTest/java/com/mparticle/kits/KitManagerImplTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.mparticle.kits; - -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -public class KitManagerImplTest { - - @Test - public void tokenTest() { - assertTrue(true); - } - -} \ No newline at end of file diff --git a/android-kit-base/src/androidTest/java/com/mparticle/kits/KnownUserKitsLifecycleTest.java b/android-kit-base/src/androidTest/java/com/mparticle/kits/KnownUserKitsLifecycleTest.java deleted file mode 100644 index 9872c0df3..000000000 --- a/android-kit-base/src/androidTest/java/com/mparticle/kits/KnownUserKitsLifecycleTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.mparticle.kits; - -import android.content.Context; - -import com.mparticle.MParticle; -import com.mparticle.MParticleOptions; -import com.mparticle.internal.AccessUtils; -import com.mparticle.internal.Logger; -import com.mparticle.kits.testkits.BaseTestKit; -import com.mparticle.kits.testkits.ListenerTestKit; -import com.mparticle.testutils.MPLatch; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertNotNull; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertTrue; - -public class KnownUserKitsLifecycleTest extends BaseKitOptionsTest { - - @Before - public void before() throws JSONException { - MParticleOptions.Builder builder = MParticleOptions.builder(mContext) - .configuration( - new ConfiguredKitOptions() - .addKit(-1, TestKit1.class, new JSONObject().put("eau", true)) - .addKit(-2, TestKit2.class, new JSONObject().put("eau", false)) - .addKit(-3, TestKit3.class, new JSONObject().put("eau", true)) - ); - startMParticle(builder); - } - - @Test - public void testExcludeUnknownUsers() throws InterruptedException { - MParticle.getInstance().Internal().getConfigManager().setMpid(123, true); - waitForKitReload(); - - assertTrue(MParticle.getInstance().isKitActive(-1)); - assertTrue(MParticle.getInstance().isKitActive(-2)); - assertTrue(MParticle.getInstance().isKitActive(-3)); - - MParticle.getInstance().Internal().getConfigManager().setMpid(123, false); - waitForKitReload(); - - assertFalse(MParticle.getInstance().isKitActive(-1)); - assertTrue(MParticle.getInstance().isKitActive(-2)); - assertFalse(MParticle.getInstance().isKitActive(-3)); - - MParticle.getInstance().Internal().getConfigManager().setMpid(321, false); - waitForKitReload(); - - assertFalse(MParticle.getInstance().isKitActive(-1)); - assertTrue(MParticle.getInstance().isKitActive(-2)); - assertFalse(MParticle.getInstance().isKitActive(-3)); - - MParticle.getInstance().Internal().getConfigManager().setMpid(123, true); - waitForKitReload(); - - assertTrue(MParticle.getInstance().isKitActive(-1)); - assertTrue(MParticle.getInstance().isKitActive(-2)); - assertTrue(MParticle.getInstance().isKitActive(-3)); - - MParticle.getInstance().Internal().getConfigManager().setMpid(456, true); - waitForKitReload(); - - assertTrue(MParticle.getInstance().isKitActive(-1)); - assertTrue(MParticle.getInstance().isKitActive(-2)); - assertTrue(MParticle.getInstance().isKitActive(-3)); - - } - - public static class TestKit1 extends TestKit { } - - public static class TestKit2 extends TestKit { } - - public static class TestKit3 extends TestKit { } - - public static class TestKit extends ListenerTestKit { - static int i = 0; - - @Override - public String getName() { - return "test kit" + i++; - } - - @Override - protected List onKitCreate(Map settings, Context context) throws IllegalArgumentException { - return null; - } - - @Override - public List setOptOut(boolean optedOut) { - return null; - } - } -} diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/BaseKitOptionsTest.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/BaseKitOptionsTest.kt index 47a0b142d..b8b682f29 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/BaseKitOptionsTest.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/BaseKitOptionsTest.kt @@ -1,23 +1,19 @@ package com.mparticle.kits -import com.mparticle.AccessUtils import com.mparticle.Configuration import com.mparticle.MParticle import com.mparticle.MParticleOptions -import com.mparticle.testutils.BaseCleanInstallEachTest -import com.mparticle.testutils.MPLatch -import org.json.JSONArray -import org.json.JSONObject +import com.mparticle.kits.utils.setCredentialsIfEmpty +import com.mparticle.kits.utils.startMParticle +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.FailureLatch -open class BaseKitOptionsTest : BaseCleanInstallEachTest() { +open class BaseKitOptionsTest : BaseTest() { - override fun startMParticle(optionsBuilder: MParticleOptions.Builder) { - startMParticle(optionsBuilder, true) - } - - fun startMParticle(optionsBuilder: MParticleOptions.Builder, awaitKitLoaded: Boolean) { - AccessUtils.setCredentialsIfEmpty(optionsBuilder) - val kitsLoadedLatch = MPLatch(1) + fun startMParticle(optionsBuilder: MParticleOptions.Builder) { + setCredentialsIfEmpty(optionsBuilder) + val kitsLoadedLatch = FailureLatch() var kitCount = 0 val kitsLoadedListener = object : Configuration { override fun configures() = KitManagerImpl::class.java @@ -38,37 +34,24 @@ open class BaseKitOptionsTest : BaseCleanInstallEachTest() { val configuredKitOptions = options.getConfiguration(ConfiguredKitOptions::class.java) ?: ConfiguredKitOptions() - val kitConfigurations: MutableMap = - mutableMapOf() - (kitOptions.kits + configuredKitOptions.kits).forEach { id, clazz -> - kitConfigurations[id] = JSONObject().put("id", id) - } - configuredKitOptions.testingConfiguration.forEach { id, config -> - kitConfigurations[id] = config - } - kitConfigurations.values - .filterNotNull() - .fold(JSONArray()) { init, next -> init.apply { put(next) } } + val configResponseMessage = configuredKitOptions.initialConfig .let { - kitCount = it.length() - JSONObject().put("eks", it) - } - .let { - mServer.setupConfigResponse(it.toString()) + kitCount = it.size + ConfigResponseMessage().apply { + kits = it.values.toList() + } } - if (kitConfigurations.isEmpty()) { + if (configResponseMessage.kits.isNullOrEmpty()) { kitsLoadedLatch.countDown() } - super.startMParticle(optionsBuilder) - if (awaitKitLoaded) { - kitsLoadedLatch.await() - } + startMParticle(optionsBuilder, configResponseMessage) + kitsLoadedLatch.await() } protected fun waitForKitToStart(kitId: Int) { - val latch = MPLatch(1) + val latch = FailureLatch() // wait for kit to start/reload - com.mparticle.internal.AccessUtils.getKitManager().addKitsLoadedListener { kits, previousKits, kitConfigs -> + com.mparticle.internal.AccessUtil.kitManager().addKitsLoadedListener { kits, previousKits, kitConfigs -> if (kits.containsKey(kitId)) { latch.countDown() } @@ -83,8 +66,8 @@ open class BaseKitOptionsTest : BaseCleanInstallEachTest() { @Throws(InterruptedException::class) @JvmOverloads fun waitForKitReload(after: (() -> Unit)? = null) { - val latch = MPLatch(1) - com.mparticle.internal.AccessUtils.getKitManager() + val latch = FailureLatch() + com.mparticle.internal.AccessUtil.kitManager() .addKitsLoadedListener { _: Map, _: Map?, _: List? -> latch.countDown() } diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/ConfiguredKitOptions.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/ConfiguredKitOptions.kt index 103c41383..8f6f2a5b7 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/ConfiguredKitOptions.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/ConfiguredKitOptions.kt @@ -1,17 +1,23 @@ package com.mparticle.kits -import org.json.JSONObject +import com.mparticle.messages.KitConfigMessage class ConfiguredKitOptions : KitOptions() { - val testingConfiguration = mutableMapOf() + val initialConfig = mutableMapOf() - override fun addKit(kitId: Int, type: Class): ConfiguredKitOptions { - return addKit(kitId, type, JSONObject().put("id", kitId)) + override fun addKit(type: Class, kitId: Int): ConfiguredKitOptions { + return addKit(type, KitConfigMessage(id = kitId)) } - fun addKit(kitId: Int, type: Class, config: JSONObject?): ConfiguredKitOptions { - testingConfiguration[kitId] = config?.put("id", kitId) - super.addKit(kitId, type) + fun addKit(type: Class, kitId: Int, includeInConfig: Boolean): ConfiguredKitOptions { + return addKit(type, KitConfigMessage(id = kitId), includeInConfig) + } + + fun addKit(type: Class, config: KitConfigMessage, includeInConfig: Boolean = true): ConfiguredKitOptions { + if (includeInConfig) { + initialConfig[config.id] = config + } + super.addKit(type, config.id) return this } } diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/DataplanBlockingUserTests.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/DataplanBlockingUserTests.kt index bec9a8f15..536a0c52f 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/DataplanBlockingUserTests.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/DataplanBlockingUserTests.kt @@ -2,20 +2,27 @@ package com.mparticle.kits import com.mparticle.MParticle import com.mparticle.MParticleOptions -import com.mparticle.Utils.randomAttributes -import com.mparticle.Utils.randomEventType -import com.mparticle.Utils.randomIdentities -import com.mparticle.Utils.randomProductAction -import com.mparticle.Utils.randomPromotionAction -import com.mparticle.Utils.randomString +import com.mparticle.api.identity.toIdentityType +import com.mparticle.commerce.Product +import com.mparticle.commerce.Promotion import com.mparticle.identity.IdentityApiRequest +import com.mparticle.internal.AccessUtil import com.mparticle.internal.AccessUtils import com.mparticle.kits.DataplanFilterImpl.Companion.getEventsApiName import com.mparticle.kits.testkits.AttributeListenerTestKit import com.mparticle.kits.testkits.IdentityListenerTestKit import com.mparticle.kits.testkits.ListenerTestKit import com.mparticle.kits.testkits.UserAttributeListenerTestKit -import com.mparticle.testutils.MPLatch +import com.mparticle.messages.IdentityResponseMessage +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.RandomUtils.getAlphaString +import com.mparticle.testing.RandomUtils.randomAttributes +import com.mparticle.testing.RandomUtils.randomEventType +import com.mparticle.testing.RandomUtils.randomIdentities +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNull @@ -33,12 +40,12 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { @Before fun beforeTests() { - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .configuration( - KitOptions { - addKit(-1, AttributeListenerTestKit::class.java) - addKit(-2, IdentityListenerTestKit::class.java) - addKit(-3, UserAttributeListenerTestKit::class.java) + ConfiguredKitOptions { + addKit(AttributeListenerTestKit::class.java, -1) + addKit(IdentityListenerTestKit::class.java, -2) + addKit(UserAttributeListenerTestKit::class.java, -3) } ).let { startMParticle(it) @@ -47,8 +54,8 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { identityListenerKitKit = MParticle.getInstance()?.getKitInstance(-2) as IdentityListenerTestKit userAttributeListenerKitKit = MParticle.getInstance()?.getKitInstance(-3) as UserAttributeListenerTestKit kitIntegrationTestKits = listOf(attributeListenerKitKit, identityListenerKitKit, userAttributeListenerKitKit) - assertTrue(randomAttributes().size > 0) - assertTrue(randomIdentities().size > 0) + assertTrue(randomAttributes().isNotEmpty()) + assertTrue(randomIdentities().isNotEmpty()) } @Test @@ -59,7 +66,7 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { assertTrue(blockedAttributes.size > 0) datapoints[DataplanFilterImpl.USER_ATTRIBUTES_KEY] = allowedAttributes.keys.toHashSet() - AccessUtils.getKitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), true, Random.nextBoolean())) + AccessUtil.kitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), true, Random.nextBoolean())) userAttributeListenerKitKit.onSetUserAttribute = { key, value, user -> assertTrue(allowedAttributes.containsKey(key)) @@ -87,7 +94,7 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { assertTrue(blockedAttributes.size > 0) datapoints[DataplanFilterImpl.USER_ATTRIBUTES_KEY] = allowedAttributes.keys.toHashSet() - AccessUtils.getKitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), true, false)) + AccessUtil.kitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), true, false)) kitIntegrationTestKits.forEach { kit -> kit.onAttributeReceived = { key, value -> @@ -143,7 +150,7 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { assertTrue(blockedAttributes.size > 0) datapoints[DataplanFilterImpl.USER_ATTRIBUTES_KEY] = allowedAttributes.keys.toHashSet() - AccessUtils.getKitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), true, Random.nextBoolean())) + AccessUtil.kitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), true, Random.nextBoolean())) var count = 0 kitIntegrationTestKits.forEach { kit -> @@ -178,18 +185,18 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { @Test fun testBlockingInFilteredIdentityApiRequest() { val datapoints = getRandomDataplanPoints() - val allowedIdentities = randomIdentities() - val blockIdentities = randomIdentities().filterKeys { !allowedIdentities.containsKey(it) } + val allowedIdentities = randomAndroidIdentities() + val blockIdentities = randomAndroidIdentities().filterKeys { !allowedIdentities.containsKey(it) } datapoints[DataplanFilterImpl.USER_IDENTITIES_KEY] = allowedIdentities.keys.map { it.getEventsApiName() }.toHashSet() - AccessUtils.getKitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), Random.nextBoolean(), true)) + AccessUtil.kitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), Random.nextBoolean(), true)) MParticle.getInstance()?.Identity()?.login( IdentityApiRequest.withEmptyUser() .userIdentities(blockIdentities + allowedIdentities) .build() ) - val latch = MPLatch(1) + val latch = FailureLatch() kitIntegrationTestKits.forEach { kit -> kit.onIdentityReceived = { identityType, value -> assertTrue(allowedIdentities.containsKey(identityType)) @@ -211,20 +218,27 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { @Test fun testBlockingInFilteredMParticleUser() { val datapoints = getRandomDataplanPoints() - val allowedIdentities = randomIdentities() - val blockedIdentities = randomIdentities().filterKeys { !allowedIdentities.containsKey(it) } + val allowedIdentities = randomAndroidIdentities() + val blockedIdentities = randomAndroidIdentities().filterKeys { !allowedIdentities.containsKey(it) } assertTrue(blockedIdentities.size > 0) datapoints[DataplanFilterImpl.USER_IDENTITIES_KEY] = allowedIdentities.keys.map { it.getEventsApiName() }.toHashSet() - AccessUtils.getKitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), Random.nextBoolean(), true)) + AccessUtil.kitManager().setDataplanFilter(DataplanFilterImpl(datapoints, Random.nextBoolean(), Random.nextBoolean(), Random.nextBoolean(), true)) + + Server + .endpoint(EndpointType.Identity_Login) + .addResponseLogic { + SuccessResponse { + responseObject = IdentityResponseMessage(Random.Default.nextLong()) + } + } - mServer.addConditionalLoginResponse(mStartingMpid, Random.Default.nextLong()) MParticle.getInstance()?.Identity()?.login( IdentityApiRequest.withEmptyUser() .userIdentities(blockedIdentities + allowedIdentities) .build() ) - val latch = MPLatch(1) + val latch = FailureLatch() kitIntegrationTestKits.forEach { kit -> kit.onUserReceived = { assertEquals(allowedIdentities, it?.userIdentities) @@ -243,10 +257,10 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { internal fun getRandomDataplanEventKey(): DataplanFilterImpl.DataPoint { return when (Random.Default.nextInt(0, 5)) { - 0 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.CUSTOM_EVENT_KEY, randomString(5), randomEventType().ordinal.toString()) - 1 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.SCREEN_EVENT_KEY, randomString(8)) - 2 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.PRODUCT_ACTION_KEY, randomProductAction()) - 3 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.PROMOTION_ACTION_KEY, randomPromotionAction()) + 0 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.CUSTOM_EVENT_KEY, getAlphaString(5), randomEventType().ordinal.toString()) + 1 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.SCREEN_EVENT_KEY, getAlphaString(8)) + 2 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.PRODUCT_ACTION_KEY, Product.DETAIL) + 3 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.PROMOTION_ACTION_KEY, Promotion.VIEW) 4 -> DataplanFilterImpl.DataPoint(DataplanFilterImpl.PRODUCT_IMPRESSION_KEY) else -> throw IllegalArgumentException("messed this implementation up :/") } @@ -259,4 +273,8 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() { } .toMutableMap() } + + private fun randomAndroidIdentities(): Map { + return randomIdentities().entries.associate { it.key.toIdentityType() to it.value } + } } diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/GCMPushMessageForwardingTest.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/GCMPushMessageForwardingTest.kt index d2cae47f3..00f85a22f 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/GCMPushMessageForwardingTest.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/GCMPushMessageForwardingTest.kt @@ -7,6 +7,7 @@ import com.mparticle.MPServiceUtil import com.mparticle.MParticle import com.mparticle.MParticleOptions import com.mparticle.kits.testkits.PushListenerTestKit +import com.mparticle.testing.context import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Test @@ -17,9 +18,13 @@ class GCMPushMessageForwardingTest : BaseKitOptionsTest() { fun testPushForwardedAfterSDKStarted() { var receivedIntent: Intent? = null - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .credentials("key", "secret") - .configuration(KitOptions().addKit(1, PushListenerTestKit::class.java)) + .configuration( + ConfiguredKitOptions { + addKit(PushListenerTestKit::class.java, 1) + } + ) .let { startMParticle(it) } @@ -30,10 +35,11 @@ class GCMPushMessageForwardingTest : BaseKitOptionsTest() { data = Uri.EMPTY putExtras(Bundle()) } - (MParticle.getInstance()?.getKitInstance(1) as PushListenerTestKit).onPushMessageReceived = { context, intent -> - receivedIntent = intent - } - MPServiceUtil(mContext).onHandleIntent(intent) + (MParticle.getInstance()?.getKitInstance(1) as PushListenerTestKit).onPushMessageReceived = + { context, intent -> + receivedIntent = intent + } + MPServiceUtil(context).onHandleIntent(intent) assertNotNull(receivedIntent) assertEquals(intent, receivedIntent) diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitBatchingTest.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitBatchingTest.kt index c7e14c7f3..e4802fb8e 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitBatchingTest.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitBatchingTest.kt @@ -5,8 +5,13 @@ import com.mparticle.MParticle import com.mparticle.MParticleOptions import com.mparticle.kits.testkits.BaseTestKit import com.mparticle.kits.testkits.EventTestKit -import com.mparticle.networking.Matcher -import com.mparticle.testutils.MPLatch +import com.mparticle.messages.Empty +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.ErrorResponse +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse import org.json.JSONArray import org.json.JSONObject import org.junit.Assert.assertEquals @@ -19,18 +24,19 @@ class KitBatchingTest : BaseKitOptionsTest() { @Before fun before() { - val options = MParticleOptions.builder(mContext) + val options = MParticleOptions.builder(context) .configuration( - KitOptions() - .addKit(123, BatchKit::class.java) - .addKit(456, EventTestKit::class.java) + ConfiguredKitOptions { + addKit(BatchKit::class.java, 123) + addKit(EventTestKit::class.java, 456) + } ) startMParticle(options) } @Test fun testEventAttributesRetainsOriginalTypes() { - val latch = MPLatch(1) + val latch = FailureLatch() var receivedEvent: MPEvent? = null (MParticle.getInstance()?.getKitInstance(456) as EventTestKit).let { kit -> kit.onLogEvent = { event -> @@ -65,6 +71,7 @@ class KitBatchingTest : BaseKitOptionsTest() { @Test fun testBatchArrives() { + var called = false MParticle.getInstance()?.apply { logEvent(MPEvent.Builder("some event").build()) logEvent(MPEvent.Builder("some other event").build()) @@ -78,19 +85,26 @@ class KitBatchingTest : BaseKitOptionsTest() { assertTrue(any { (it as? JSONObject)?.getString("dt") == "fr" }) assertTrue(any { (it as? JSONObject)?.getString("dt") == "ss" }) assertEquals(2, filter { (it as? JSONObject)?.getString("dt") == "e" }.size) + called = true } } + assertTrue(called) } @Test fun testBatchNotForwardedOnNetworkFailure() { val instance = MParticle.getInstance()!! - mServer.setEventsResponseLogic(500) + Server + .endpoint(EndpointType.Events) + .addResponseLogic { ErrorResponse(500) } instance.apply { logEvent(MPEvent.Builder("some event").build()) upload() } - mServer.waitForVerify(Matcher(mServer.Endpoints().eventsUrl)) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { true } + .blockUntilFinished() // send another event, since batches aren't forwarded to the kits until after the upload, // this is the only way we can gaurantee an batch forwarding *could* have happened. Since it's // not supposed to happen when the upload fails, we can't await() in the kit like the previous test @@ -98,16 +112,22 @@ class KitBatchingTest : BaseKitOptionsTest() { logEvent(MPEvent.Builder("some other event").build()) upload() } - mServer.waitForVerify(Matcher(mServer.Endpoints().eventsUrl)) + Server + .endpoint(EndpointType.Events) + .assertWillReceive { true } + .blockUntilFinished() val batchKit = (MParticle.getInstance()?.getKitInstance(123) as BatchKit) assertEquals(0, batchKit.batches.size) // see if it recovers... - mServer.setupHappyEvents() - val uploadsCount = getDatabaseContents(listOf("uploads")).getJSONArray("uploads").length() + Server + .endpoint(EndpointType.Events) + .addResponseLogic { SuccessResponse(Empty()) } + val uploadsCount = mockingPlatforms.getDatabaseContents(listOf("uploads"))["uploads"]?.size ?: 0 + assertTrue(uploadsCount > 0) instance.upload() - for (i in 1..uploadsCount) { + (0 until uploadsCount).forEach { batchKit.await() } @@ -117,10 +137,10 @@ class KitBatchingTest : BaseKitOptionsTest() { class BatchKit : BaseTestKit(), KitIntegration.BatchListener { var batches = mutableListOf() override fun getName() = "Batch Kit" - private var latch = MPLatch(1) + private var latch = FailureLatch() fun await() { - latch = MPLatch(1) + latch = FailureLatch() latch.await() } diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitManagerImplTests.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitManagerImplTests.kt index 53eed34f0..9236ae1df 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitManagerImplTests.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KitManagerImplTests.kt @@ -10,24 +10,34 @@ import com.mparticle.internal.KitManager import com.mparticle.kits.testkits.AttributeListenerTestKit import com.mparticle.kits.testkits.IdentityListenerTestKit import com.mparticle.kits.testkits.UserAttributeListenerTestKit -import com.mparticle.networking.Matcher -import com.mparticle.testutils.MPLatch +import com.mparticle.messages.KitConfigMessage +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server import org.json.JSONObject import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue +import org.junit.Before import org.junit.Test class KitManagerImplTests : BaseKitOptionsTest() { + @Before + fun before() { + MParticle.setInstance(null) + } + @Test fun testKitIntializationViaKitOptions() { - KitOptions() - .addKit(1001, AttributeListenerTestKit::class.java) - .addKit(1002, IdentityListenerTestKit::class.java) - .addKit(1003, UserAttributeListenerTestKit::class.java) + ConfiguredKitOptions { + addKit(AttributeListenerTestKit::class.java, 1001) + addKit(IdentityListenerTestKit::class.java, 1002) + addKit(UserAttributeListenerTestKit::class.java, 1003) + } .let { - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .configuration(it) } .let { @@ -42,40 +52,35 @@ class KitManagerImplTests : BaseKitOptionsTest() { @Test fun testKitConfigParsingFailsGracefullyOnReset() { - val latch = MPLatch(1) + val latch = FailureLatch() // somewhat contrived, but this is simulating the main thread is blocked/unresponsive Handler(Looper.getMainLooper()).post { latch.await() } // Force the SDK to make a config request (using the ugly internals) - JSONObject().put("eks", ConfigManager.getInstance(mContext).latestKitConfiguration) + JSONObject().put("eks", ConfigManager.getInstance(context).latestKitConfiguration) .let { - ConfigManager.getInstance(mContext).updateConfig(it) + ConfigManager.getInstance(context).updateConfig(it) } - MParticle.reset(mContext) + MParticle.reset(context) latch.countDown() } @Test fun testActiveKitReporting() { - MParticleOptions.builder(mContext) + MParticleOptions.builder(context) .configuration( ConfiguredKitOptions { - addKit(-1, AttributeListenerTestKit::class.java, JSONObject().put("eau", true)) - addKit(-2, IdentityListenerTestKit::class.java) - addKit(-3, UserAttributeListenerTestKit::class.java) - addKit(-4, AttributeListenerTestKit::class.java, JSONObject().put("eau", true)) - addKit(-5, IdentityListenerTestKit::class.java) - addKit(-6, UserAttributeListenerTestKit::class.java) - }.apply { - // do not make a config for kits with id -2 or -5..This will mimic having the - // kit dependency in the classpath, but not in the /config response - testingConfiguration[-2] = null - testingConfiguration[-5] = null + addKit(AttributeListenerTestKit::class.java, KitConfigMessage(-1).apply { excludeAnnonymousUsers = true }) + addKit(IdentityListenerTestKit::class.java, -2, false) + addKit(UserAttributeListenerTestKit::class.java, -3) + addKit(AttributeListenerTestKit::class.java, KitConfigMessage(-4).apply { excludeAnnonymousUsers = true }) + addKit(IdentityListenerTestKit::class.java, -5, false) + addKit(UserAttributeListenerTestKit::class.java, -6) } ).let { startMParticle(it) waitForKitReload() { - MParticle.getInstance()?.Internal()?.configManager?.setMpid(123, false) + MParticle.getInstance()?.Internal()?.configManager?.setMpid(1234, false) } } val kitStatus = MParticle.getInstance()?.Internal()?.kitManager?.kitStatus @@ -93,17 +98,24 @@ class KitManagerImplTests : BaseKitOptionsTest() { // double check that ConfigManager is generating the right string val expectedActiveKits = "-6,-4,-3,-1" - val expectedBundledKits = "-6,-5,-4,-3,-2.-1" + val expectedBundledKits = "-1,-2,-3,-4,-5,-6" assertEquals(expectedActiveKits, MParticle.getInstance()?.Internal()?.configManager?.activeModuleIds) - // check that the active kits value is sent to the server - MParticle.getInstance()?.apply { - logEvent(MPEvent.Builder("some event").build()) - upload() - } - mServer.waitForVerify(Matcher(mServer.Endpoints().eventsUrl)) { - assertEquals(it.headers["x-mp-kits"], expectedActiveKits) - assertEquals(it.headers["x-mp-bundled-kits"], expectedBundledKits) - } + Server + .endpoint(EndpointType.Events) + .assertWillReceive { + it.headers?.let { + assertEquals(expectedActiveKits, it["x-mp-kits"]) + assertEquals(expectedBundledKits, it["x-mp-bundled-kits"]) + true + } ?: false + } + .after { + MParticle.getInstance()?.apply { + logEvent(MPEvent.Builder("some event").build()) + upload() + } + } + .blockUntilFinished() } } diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KnownUserKitsLifecycleTest.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KnownUserKitsLifecycleTest.kt new file mode 100644 index 000000000..e10d1412f --- /dev/null +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/KnownUserKitsLifecycleTest.kt @@ -0,0 +1,89 @@ +package com.mparticle.kits + +import android.content.Context +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.kits.testkits.ListenerTestKit +import com.mparticle.messages.KitConfigMessage +import com.mparticle.testing.context +import junit.framework.TestCase +import org.json.JSONException +import org.junit.Before +import org.junit.Test + +class KnownUserKitsLifecycleTest : BaseKitOptionsTest() { + @Before + @Throws(JSONException::class) + fun before() { + val builder = MParticleOptions.builder(context) + .configuration( + ConfiguredKitOptions() + .addKit(TestKit1::class.java, KitConfigMessage(-1).apply { excludeAnnonymousUsers = true }) + .addKit(TestKit2::class.java, KitConfigMessage(-2).apply { excludeAnnonymousUsers = false }) + .addKit(TestKit3::class.java, KitConfigMessage(-3).apply { excludeAnnonymousUsers = true }) + ) + startMParticle(builder) + } + + @Test + @Throws(InterruptedException::class) + fun testExcludeUnknownUsers() { + MParticle.getInstance()!!.apply { + waitForKitReload { + Internal().configManager.setMpid(123, true) + } + TestCase.assertTrue(isKitActive(-1)) + TestCase.assertTrue(isKitActive(-2)) + TestCase.assertTrue(isKitActive(-3)) + waitForKitReload { + Internal().configManager.setMpid(123, false) + } + TestCase.assertFalse(isKitActive(-1)) + TestCase.assertTrue(isKitActive(-2)) + TestCase.assertFalse(isKitActive(-3)) + waitForKitReload { + Internal().configManager.setMpid(321, false) + } + TestCase.assertFalse(isKitActive(-1)) + TestCase.assertTrue(isKitActive(-2)) + TestCase.assertFalse(isKitActive(-3)) + waitForKitReload { + Internal().configManager.setMpid(123, true) + } + TestCase.assertTrue(isKitActive(-1)) + TestCase.assertTrue(isKitActive(-2)) + TestCase.assertTrue(isKitActive(-3)) + waitForKitReload { + Internal().configManager.setMpid(456, true) + } + TestCase.assertTrue(isKitActive(-1)) + TestCase.assertTrue(isKitActive(-2)) + TestCase.assertTrue(isKitActive(-3)) + } + } + + class TestKit1 : TestKit() + class TestKit2 : TestKit() + class TestKit3 : TestKit() + open class TestKit : ListenerTestKit() { + override fun getName(): String { + return "test kit" + i++ + } + + @Throws(IllegalArgumentException::class) + override fun onKitCreate( + settings: Map?, + context: Context + ): List { + return listOf() + } + + override fun setOptOut(optedOut: Boolean): List { + return listOf() + } + + companion object { + var i = 0 + } + } +} diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/UpdateConfigTest.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/UpdateConfigTest.kt index 33b3bda04..dfe1d9c07 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/UpdateConfigTest.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/UpdateConfigTest.kt @@ -2,11 +2,16 @@ package com.mparticle.kits import com.mparticle.MParticle import com.mparticle.MParticleOptions +import com.mparticle.internal.AccessUtil import com.mparticle.internal.AccessUtils import com.mparticle.kits.testkits.BaseTestKit -import com.mparticle.testutils.MPLatch -import org.json.JSONArray -import org.json.JSONObject +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.messages.KitConfigMessage +import com.mparticle.testing.FailureLatch +import com.mparticle.testing.context +import com.mparticle.testing.mockserver.EndpointType +import com.mparticle.testing.mockserver.Server +import com.mparticle.testing.mockserver.SuccessResponse import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull @@ -17,21 +22,21 @@ class UpdateConfigTest : BaseKitOptionsTest() { @Test fun testKitsLoadFromRemoteConfig() { - setCachedConfig(null) - MParticleOptions.builder(mContext) + mockingPlatforms.setCachedConfig(null) + MParticleOptions.builder(context) .configuration( ConfiguredKitOptions { - addKit(1, BaseTestKit::class.java) - addKit(2, BaseTestKit::class.java, null) - addKit(3, BaseTestKit::class.java) - addKit(4, BaseTestKit::class.java, null) - addKit(5, BaseTestKit::class.java) + addKit(BaseTestKit::class.java, 1) + addKit(BaseTestKit::class.java, 2, false) + addKit(BaseTestKit::class.java, 3) + addKit(BaseTestKit::class.java, 4, false) + addKit(BaseTestKit::class.java, 5) } ).let { startMParticle(it) } - waitForKitToStart(1) + waitForKitToStart(5) MParticle.getInstance()!!.let { assertNotNull(it.getKitInstance(1)) @@ -44,12 +49,12 @@ class UpdateConfigTest : BaseKitOptionsTest() { @Test fun testStartKitWithNewRemoteConfig() { - setCachedConfig(null) - MParticleOptions.builder(mContext) + mockingPlatforms.setCachedConfig(null) + MParticleOptions.builder(context) .configuration( ConfiguredKitOptions { - addKit(1, BaseTestKit::class.java) - addKit(2, BaseTestKit::class.java, null) + addKit(BaseTestKit::class.java, 1) + addKit(BaseTestKit::class.java, 2) } ).let { startMParticle(it) @@ -57,17 +62,20 @@ class UpdateConfigTest : BaseKitOptionsTest() { waitForKitToStart(1) - mServer.setupConfigResponse( - JSONObject() - .put( - "eks", - JSONArray() - .put(JSONObject().put("id", 1)) - .put(JSONObject().put("id", 2)) - ).toString() - ) + Server + .endpoint(EndpointType.Config) + .addResponseLogic { + SuccessResponse { + responseObject = ConfigResponseMessage().apply { + kits = listOf( + KitConfigMessage(1), + KitConfigMessage(2) + ) + } + } + } - AccessUtils.getKitManager().addKitsLoadedListener { kits, previousKits, kitConfigs -> + AccessUtil.kitManager().addKitsLoadedListener { kits, previousKits, kitConfigs -> assertEquals(1, previousKits.size) assertEquals(2, kits.size) assertTrue(previousKits.containsKey(1)) @@ -78,28 +86,29 @@ class UpdateConfigTest : BaseKitOptionsTest() { @Test fun testShutdownKitWithNewRemoteConfig() { - setCachedConfig(null) - MParticleOptions.builder(mContext) + mockingPlatforms.setCachedConfig(null) + MParticleOptions.builder(context) .configuration( ConfiguredKitOptions { - addKit(1, BaseTestKit::class.java) - addKit(2, BaseTestKit::class.java) + addKit(BaseTestKit::class.java, 1) + addKit(BaseTestKit::class.java, 2) } ).let { startMParticle(it) } - mServer.setupConfigResponse( - JSONObject() - .put( - "eks", - JSONArray() - .put(JSONObject().put("id", 1)) - ).toString() - ) + Server + .endpoint(EndpointType.Config) + .addResponseLogic { + SuccessResponse { + responseObject = ConfigResponseMessage().apply { + kits = listOf(KitConfigMessage(1)) + } + } + } - val latch = MPLatch(1) - AccessUtils.getKitManager().addKitsLoadedListener { kits, previousKits, kitConfigs -> + val latch = FailureLatch() + AccessUtil.kitManager().addKitsLoadedListener { kits, previousKits, kitConfigs -> assertEquals(2, previousKits.size) assertEquals(1, kits.size) assertTrue(previousKits.containsKey(1)) diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/testkits/CommerceListenerTestKit.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/testkits/CommerceListenerTestKit.kt index 352ddd066..6723fcc33 100644 --- a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/testkits/CommerceListenerTestKit.kt +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/testkits/CommerceListenerTestKit.kt @@ -9,7 +9,7 @@ class CommerceListenerTestKit : ListenerTestKit(), KitIntegration.CommerceListen var logEvent: ((CommerceEvent?) -> List)? = null var logLtvIncrease: ((BigDecimal?, BigDecimal?, String?, Map?) -> List)? = null - override fun logEvent(event: CommerceEvent?): List { + override fun logEvent(event: CommerceEvent): List { return logEvent?.invoke(event) ?: listOf() } diff --git a/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/utils/CrossPlatformSugar.kt b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/utils/CrossPlatformSugar.kt new file mode 100644 index 000000000..4dedca197 --- /dev/null +++ b/android-kit-base/src/androidTest/kotlin/com/mparticle/kits/utils/CrossPlatformSugar.kt @@ -0,0 +1,58 @@ +package com.mparticle.kits.utils + +import com.mparticle.MPEvent +import com.mparticle.MParticle +import com.mparticle.MParticleOptions +import com.mparticle.api.events.toMPEvent +import com.mparticle.api.identity.IdentityType +import com.mparticle.api.identity.toIdentityType +import com.mparticle.identity.AccessUtils +import com.mparticle.internal.MParticleApiClient +import com.mparticle.internal.MessageManager +import com.mparticle.messages.ConfigResponseMessage +import com.mparticle.testing.BaseTest +import com.mparticle.testing.RandomUtils +import com.mparticle.testing.TestingUtils +import com.mparticle.toMParticleOptions +import com.mparticle.api.identity.toIdentityType as toIdentityTypeCrossPlatform +import com.mparticle.testing.startMParticle as startMParticleCrossPlatform +import com.mparticle.toMParticleOptions as toMParticleOptionsCrossPlatform + +fun MParticleOptions.Builder.toMParticleOptions(): com.mparticle.api.MParticleOptions { + return this.toMParticleOptionsCrossPlatform() +} + +fun BaseTest.startMParticle(builder: MParticleOptions.Builder) { + startMParticleCrossPlatform(builder) +} +fun BaseTest.startMParticle(builder: MParticleOptions.Builder, initialConfigMessage: ConfigResponseMessage) { + startMParticle(builder.toMParticleOptions(), initialConfigMessage) +} + +fun setUserIdentity(value: String?, identityType: MParticle.IdentityType, mpid: Long) { + AccessUtils.setUserIdentity(value, identityType, mpid) +} + +fun IdentityType.toIdentityType(): MParticle.IdentityType = toIdentityTypeCrossPlatform() + +fun randomIdentities(count: Int? = null): Map = ( + count?.let { + RandomUtils.getRandomUserIdentities(count) + } ?: RandomUtils.getRandomUserIdentities() + ).entries.associate { it.key.toIdentityType()!! to it.value } + +fun getInstallType(messageManager: MessageManager): MParticle.InstallType { + return com.mparticle.internal.AccessUtils.getInstallType(messageManager) +} + +fun randomMPEventRich(): MPEvent { + return TestingUtils.randomMPEventRich.toMPEvent() +} + +fun setCredentialsIfEmpty(builder: MParticleOptions.Builder) { + com.mparticle.AccessUtils.setCredentialsIfEmpty(builder) +} + +fun setMParticleApiClient(apiClient: MParticleApiClient) { + com.mparticle.internal.AccessUtils.setMParticleApiClient(apiClient) +}