-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MOBL-1399] Events module rewrite in Kotlin language (#363)
* Copied over the files from request queue project * addressing IDE warnings * Adjusted the code to support minSdk 23 change * Removed unused imports * Added unit tests for event manager * Added unit tests for network queue manager * Methods with db access and nw access made main safe * Fixed an issue with setup method in test * Updated the network repository code for better exception handling * Bug fixes and logging improvements * fix tests and optimise job scheduling * wiring new event module to Blueshift class * code clean up inside initialize method * Bug fix - selection of datacenters is now possible using legacy code * Added a queue to process events inserted to the local database * Made necessary changes to maintain the order of the events inserted to the queue * Fixed the order of events in the bulk events array to be ascending * Adjusted the logs for better readability * Refactored the unit test * Logging cleanup * committing new version check code (test pending) * Added tests for the BlueshiftInstallationStatusHelper class * Removed unused methods and their tests * Added more test cases to cover getEventAttributes method * Renamed the db files to match convention * Removed Blueshift keyword from Log tags * Reset batch interval from 15 min to 30 min * Fixed the test method signature * Removed commented code and added comments for the new code added * Removed unused namespace declaration * Fixed code formatting issues in the file BlueshiftNetworkRequestRepositoryImpl * Addressed multiple review comments from Ketan * Delete the offline events and any pending requests from the queue when tracking is disabled. * Deleted two unused test files * Added tests for the BlueshiftAPI class to ensure the validity of API URLs * Reformatted the log code * Added Android tests for BlueshiftEventRepositoryImpl * Avoid crashes due to null event name * Started adding headers in the db and also wrote tests for BlueshiftNetworkRequestRepositoryImpl * Added more tests for the BlueshiftNetworkRequestRepositoryImpl class * Added check for legacy sync status to avoid unwanted sync calls * Added check for null values in eventName attribute to avoid crashes * Fixed the variable name * Added deprecation note for AppInstallReceiver * Deprecated the legacy events module classes with a note * Detects push permission change on app start and for each event * Mark current push status before sending identify to avoid infinite loop * Cache device token for faster loading on app opens * modified handleNewToken method to accept context
- Loading branch information
Showing
61 changed files
with
2,313 additions
and
450 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 0 additions & 22 deletions
22
android-sdk/src/androidTest/java/com/blueshift/ExampleInstrumentedTest.java
This file was deleted.
Oops, something went wrong.
112 changes: 112 additions & 0 deletions
112
...id-sdk/src/androidTest/java/com/blueshift/core/events/BlueshiftEventRepositoryImplTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package com.blueshift.core.events | ||
|
||
import androidx.test.platform.app.InstrumentationRegistry | ||
import kotlinx.coroutines.runBlocking | ||
import org.json.JSONObject | ||
import org.junit.After | ||
import org.junit.Before | ||
import org.junit.Test | ||
|
||
class BlueshiftEventRepositoryImplTest { | ||
private lateinit var repository: BlueshiftEventRepositoryImpl | ||
|
||
@Before | ||
fun setUp() { | ||
val context = InstrumentationRegistry.getInstrumentation().targetContext | ||
repository = BlueshiftEventRepositoryImpl(context) | ||
} | ||
|
||
@After | ||
fun tearDown() = runBlocking { | ||
repository.clear() | ||
} | ||
|
||
@Test | ||
fun insertEvent_insertsEventsToTheSQLiteDatabase() = runBlocking { | ||
val name = "test_event" | ||
val json = "{\"key\":\"val\"}" | ||
val timestamp = System.currentTimeMillis() | ||
val event = BlueshiftEvent( | ||
eventName = name, eventParams = JSONObject(json), timestamp = timestamp | ||
) | ||
|
||
repository.insertEvent(event) | ||
val events = repository.readOneBatch() | ||
|
||
assert(events.size == 1) | ||
assert(events[0].eventName == name) | ||
assert(events[0].eventParams.toString() == json) | ||
assert(events[0].timestamp == timestamp) | ||
} | ||
|
||
@Test | ||
fun deleteEvents_deletesEventsFromTheSQLiteDatabase() = runBlocking { | ||
val name = "test_event" | ||
val json = "{\"key\":\"val\"}" | ||
val timestamp = 0L | ||
val event = BlueshiftEvent( | ||
eventName = name, eventParams = JSONObject(json), timestamp = timestamp | ||
) | ||
|
||
repository.insertEvent(event) | ||
var events = repository.readOneBatch() | ||
|
||
assert(events.size == 1) | ||
|
||
repository.deleteEvents(events) | ||
events = repository.readOneBatch() | ||
|
||
assert(events.isEmpty()) | ||
} | ||
|
||
@Test | ||
fun readOneBatch_retrievesAListOfHundredEventsWhenCountIsNotSpecified() = runBlocking { | ||
for (i in 1..200) { | ||
val name = "test_event_$i" | ||
val json = "{\"key\":\"val\"}" | ||
val timestamp = 0L | ||
val event = BlueshiftEvent( | ||
eventName = name, eventParams = JSONObject(json), timestamp = timestamp | ||
) | ||
repository.insertEvent(event) | ||
} | ||
|
||
val events = repository.readOneBatch() | ||
assert(events.size == 100) | ||
} | ||
|
||
@Test | ||
fun readOneBatch_retrievesAListOfTenEventsWhenCountIsSetToTen() = runBlocking { | ||
for (i in 1..200) { | ||
val name = "test_event_$i" | ||
val json = "{\"key\":\"val\"}" | ||
val timestamp = 0L | ||
val event = BlueshiftEvent( | ||
eventName = name, eventParams = JSONObject(json), timestamp = timestamp | ||
) | ||
repository.insertEvent(event) | ||
} | ||
|
||
val events = repository.readOneBatch(batchCount = 10) | ||
assert(events.size == 10) | ||
} | ||
|
||
@Test | ||
fun readOneBatch_retrievesAListOfEventsInTheSameOrderTheyAreStoredInTheDatabase() = | ||
runBlocking { | ||
for (i in 1..10) { | ||
val name = "test_event_$i" | ||
val json = "{\"key\":\"val\"}" | ||
val timestamp = 0L | ||
val event = BlueshiftEvent( | ||
eventName = name, eventParams = JSONObject(json), timestamp = timestamp | ||
) | ||
repository.insertEvent(event) | ||
} | ||
|
||
val events = repository.readOneBatch(batchCount = 10) | ||
for (i in 1..9) { | ||
assert((events[i].id - events[i - 1].id) == 1L) | ||
} | ||
} | ||
} |
234 changes: 234 additions & 0 deletions
234
.../androidTest/java/com/blueshift/core/network/BlueshiftNetworkRequestRepositoryImplTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
package com.blueshift.core.network | ||
|
||
import androidx.test.platform.app.InstrumentationRegistry | ||
import kotlinx.coroutines.runBlocking | ||
import org.json.JSONObject | ||
import org.junit.After | ||
import org.junit.Before | ||
import org.junit.Test | ||
|
||
class BlueshiftNetworkRequestRepositoryImplTest { | ||
private lateinit var repository: BlueshiftNetworkRequestRepositoryImpl | ||
|
||
@Before | ||
fun setUp() { | ||
val context = InstrumentationRegistry.getInstrumentation().targetContext | ||
repository = BlueshiftNetworkRequestRepositoryImpl(context) | ||
} | ||
|
||
@After | ||
fun tearDown() = runBlocking { | ||
repository.clear() | ||
} | ||
|
||
@Test | ||
fun insertRequest_insertsRequestsToTheSQLiteDatabase(): Unit = runBlocking { | ||
val url = "https://example.com" | ||
val method = BlueshiftNetworkRequest.Method.GET | ||
val header = JSONObject(mapOf("Content-Type" to "application/json")) | ||
val body = JSONObject() | ||
val authRequired = true | ||
val retryBalance = 1 | ||
val retryTimestamp = 1234567890L | ||
val timestamp = 1234567890L | ||
|
||
val request = BlueshiftNetworkRequest( | ||
url = url, | ||
method = method, | ||
header = header, | ||
body = body, | ||
authorizationRequired = authRequired, | ||
retryAttemptBalance = retryBalance, | ||
retryAttemptTimestamp = retryTimestamp, | ||
timestamp = timestamp | ||
) | ||
|
||
repository.insertRequest(request) | ||
val request2 = repository.readNextRequest() | ||
|
||
assert(request2 != null) | ||
request2?.let { | ||
assert(it.url == url) | ||
assert(it.method == method) | ||
assert(it.header.toString() == header.toString()) | ||
assert(it.body.toString() == body.toString()) | ||
assert(it.authorizationRequired == authRequired) | ||
assert(it.retryAttemptBalance == retryBalance) | ||
assert(it.retryAttemptTimestamp == retryTimestamp) | ||
assert(it.timestamp == timestamp) | ||
} | ||
} | ||
|
||
@Test | ||
fun updateRequest_updatesRequestsInTheSQLiteDatabase(): Unit = runBlocking { | ||
val url = "https://example.com" | ||
val method = BlueshiftNetworkRequest.Method.GET | ||
val header = JSONObject(mapOf("Content-Type" to "application/json")) | ||
val body = JSONObject() | ||
val authRequired = true | ||
val retryBalance = 1 | ||
val retryTimestamp = 1234567890L | ||
val timestamp = 1234567890L | ||
|
||
val request = BlueshiftNetworkRequest( | ||
url = url, | ||
method = method, | ||
header = header, | ||
body = body, | ||
authorizationRequired = authRequired, | ||
retryAttemptBalance = retryBalance, | ||
retryAttemptTimestamp = retryTimestamp, | ||
timestamp = timestamp | ||
) | ||
|
||
repository.insertRequest(request) | ||
|
||
// the code only allows updating the following two fields. | ||
val retryBalance2 = 2 | ||
val retryTimestamp2 = 9876543210L | ||
|
||
val request2 = repository.readNextRequest() | ||
request2?.let { | ||
it.retryAttemptBalance = retryBalance2 | ||
it.retryAttemptTimestamp = retryTimestamp2 | ||
|
||
repository.updateRequest(it) | ||
} | ||
|
||
val request3 = repository.readNextRequest() | ||
assert(request3 != null) | ||
request3?.let { | ||
assert(it.retryAttemptBalance == retryBalance2) | ||
assert(it.retryAttemptTimestamp == retryTimestamp2) | ||
} | ||
} | ||
|
||
@Test | ||
fun deleteRequest_deletesRequestsInTheSQLiteDatabase(): Unit = runBlocking { | ||
val url = "https://example.com" | ||
val method = BlueshiftNetworkRequest.Method.GET | ||
val header = JSONObject(mapOf("Content-Type" to "application/json")) | ||
val body = JSONObject() | ||
val authRequired = true | ||
val retryBalance = 1 | ||
val retryTimestamp = 1234567890L | ||
val timestamp = 1234567890L | ||
|
||
val request = BlueshiftNetworkRequest( | ||
url = url, | ||
method = method, | ||
header = header, | ||
body = body, | ||
authorizationRequired = authRequired, | ||
retryAttemptBalance = retryBalance, | ||
retryAttemptTimestamp = retryTimestamp, | ||
timestamp = timestamp | ||
) | ||
|
||
repository.insertRequest(request) | ||
|
||
val request2 = repository.readNextRequest() | ||
request2?.let { | ||
repository.deleteRequest(it) | ||
} | ||
|
||
val request3 = repository.readNextRequest() | ||
assert(request3 == null) | ||
} | ||
|
||
@Test | ||
fun readNextRequest_shouldReturnTheFirstRequestWhenAllRequestsInTheQueueRetryAttemptBalanceGreaterThanZero(): Unit = | ||
runBlocking { | ||
for (i in 1..3) { | ||
val url = "https://api.com/$i" | ||
val method = BlueshiftNetworkRequest.Method.GET | ||
val header = JSONObject(mapOf("Content-Type" to "application/json")) | ||
val body = JSONObject() | ||
val authRequired = true | ||
val retryBalance = 3 | ||
val retryTimestamp = 0L | ||
val timestamp = System.currentTimeMillis() | ||
val request = BlueshiftNetworkRequest( | ||
url = url, | ||
method = method, | ||
header = header, | ||
body = body, | ||
authorizationRequired = authRequired, | ||
retryAttemptBalance = retryBalance, | ||
retryAttemptTimestamp = retryTimestamp, | ||
timestamp = timestamp | ||
) | ||
repository.insertRequest(request) | ||
} | ||
|
||
val request = repository.readNextRequest() | ||
assert(request != null) | ||
request?.let { | ||
assert(it.url == "https://api.com/1") | ||
} | ||
} | ||
|
||
@Test | ||
fun readNextRequest_shouldReturnNullWhenAllRequestsInTheQueueHasRetryAttemptBalanceEqualToZero(): Unit = | ||
runBlocking { | ||
for (i in 1..3) { | ||
val url = "https://api.com/$i" | ||
val method = BlueshiftNetworkRequest.Method.GET | ||
val header = JSONObject(mapOf("Content-Type" to "application/json")) | ||
val body = JSONObject() | ||
val authRequired = true | ||
val retryBalance = 0 | ||
val retryTimestamp = 0L | ||
val timestamp = System.currentTimeMillis() | ||
val request = BlueshiftNetworkRequest( | ||
url = url, | ||
method = method, | ||
header = header, | ||
body = body, | ||
authorizationRequired = authRequired, | ||
retryAttemptBalance = retryBalance, | ||
retryAttemptTimestamp = retryTimestamp, | ||
timestamp = timestamp | ||
) | ||
repository.insertRequest(request) | ||
} | ||
|
||
val request = repository.readNextRequest() | ||
assert(request == null) | ||
} | ||
|
||
@Test | ||
fun readNextRequest_shouldReturnTheRequestWithRetryAttemptTimestampLessThanCurrentTime(): Unit = | ||
runBlocking { | ||
for (i in 1..2) { | ||
val fiveMinutes = 5 * 60 * 1000 | ||
val url = "https://api.com/$i" | ||
val method = BlueshiftNetworkRequest.Method.GET | ||
val header = JSONObject(mapOf("Content-Type" to "application/json")) | ||
val body = JSONObject() | ||
val authRequired = true | ||
val retryBalance = 1 | ||
val retryTimestamp = if (i % 2 == 0) System.currentTimeMillis() + fiveMinutes else System.currentTimeMillis() - fiveMinutes | ||
val timestamp = System.currentTimeMillis() | ||
val request = BlueshiftNetworkRequest( | ||
url = url, | ||
method = method, | ||
header = header, | ||
body = body, | ||
authorizationRequired = authRequired, | ||
retryAttemptBalance = retryBalance, | ||
retryAttemptTimestamp = retryTimestamp, | ||
timestamp = timestamp | ||
) | ||
repository.insertRequest(request) | ||
} | ||
|
||
// i = 1 -> current time - 5min | ||
// i = 2 -> current time + 5min | ||
val request = repository.readNextRequest() | ||
assert(request != null) | ||
request?.let { | ||
assert(it.url == "https://api.com/1") | ||
} | ||
} | ||
} |
Oops, something went wrong.