Skip to content

Commit

Permalink
Prepare for release 1.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanlogan committed Jul 14, 2023
1 parent 847ef8d commit 6598608
Show file tree
Hide file tree
Showing 8 changed files with 375 additions and 134 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
.cxx
local.properties
/support/repo/

# Sonatype signing
secure_do_not_distribute_sonatype.properties
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.4.0

##### Added
* Added support to parse `braze_subscription_groups` in the Identity traits to subscribe and unsubscribe from Braze subscription groups.
* Updated to use Braze Android SDK 26.1.0 and analytics-kotlin 1.13.0.

## 1.3.0

#### Breaking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ class BrazeAndroidTest {
content = mapOf(
"apiKey" to JsonPrimitive(apiKey),
"customEndpoint" to JsonPrimitive(customEndpoint),
"automatic_in_app_message_registration_enabled" to JsonPrimitive(autoInAppRegistration)
"automatic_in_app_message_registration_enabled" to JsonPrimitive(autoInAppRegistration),
"logPurchaseWhenRevenuePresent" to JsonPrimitive(false)
)
)
val integrations = JsonObject(mapOf("Appboy" to brazeJsonSettings))
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package com.segment.analytics.kotlin.destinations.braze
import android.app.Activity
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.braze.Braze
import com.braze.BrazeUser
import com.braze.enums.Gender
import com.braze.enums.Month
import com.braze.events.IValueCallback
import com.braze.models.outgoing.AttributionData
import com.braze.Braze
import com.braze.BrazeUser
import com.braze.models.outgoing.BrazeProperties
import com.braze.support.getOptionalString
import com.segment.analytics.kotlin.core.*
Expand Down Expand Up @@ -130,6 +131,9 @@ class BrazeSegmentTest {
}
val brazeMock = mock<Braze>() {
on { currentUser } doReturn brazeUserMock
on { getCurrentUser(any()) }.doAnswer { invocation ->
(invocation.arguments[0] as IValueCallback<BrazeUser>).onSuccess(brazeUserMock)
}
}
brazeDestination.brazeTestingMock = brazeMock

Expand Down Expand Up @@ -177,6 +181,9 @@ class BrazeSegmentTest {
val brazeUserMock: BrazeUser = mock()
val brazeMock = mock<Braze>() {
on { currentUser } doReturn brazeUserMock
on { getCurrentUser(any()) }.doAnswer { invocation ->
(invocation.arguments[0] as IValueCallback<BrazeUser>).onSuccess(brazeUserMock)
}
}
brazeDestination.brazeTestingMock = brazeMock

Expand Down Expand Up @@ -309,11 +316,47 @@ class BrazeSegmentTest {
}

@Test
fun whenCalledWithExtraProperties_track_callsLogPurchaseWithProperies() {
fun whenCalledWithRevenueButSettingIsFalse_track_DoesNotCallLogPurchaseWithProperties() {
val brazePropertiesCaptor = argumentCaptor<BrazeProperties>()
val brazeMock = mock<Braze> {
on { logPurchase(any(), any(), any(), brazePropertiesCaptor.capture()) }.then { }
on { logCustomEvent(any(), brazePropertiesCaptor.capture()) }.then { }
}
val settings = getMockSettings(logPurchaseWhenRevenuePresent = false)
brazeDestination.update(settings, Plugin.UpdateType.Initial)
brazeDestination.brazeTestingMock = brazeMock

val trackEvent = TrackEvent(
JsonObject(
mapOf(
"revenue" to JsonPrimitive(5.99),
"currency" to JsonPrimitive("CAD"),
"color" to JsonPrimitive("red")

)
),
"Random Event Name"
)
val payload = brazeDestination.track(trackEvent)
assertEquals(payload, trackEvent)
verify(brazeMock, times(0)).logPurchase(any(), any(), any(), any() as BrazeProperties?)

verify(brazeMock, times(1)).logCustomEvent(eq("Random Event Name"), any() as BrazeProperties?)

assertEquals(1, brazePropertiesCaptor.allValues.size)
val brazeProperties = brazePropertiesCaptor.firstValue
assertEquals(1, brazeProperties.size)
assertEquals("red", brazeProperties["color"])
}

@Test
fun whenCalledWithRevenueButSettingIsFalseButNameIsOrderCompleted_track_DoesCallLogPurchaseWithProperties() {
val brazePropertiesCaptor = argumentCaptor<BrazeProperties>()
val brazeMock = mock<Braze> {
on { logPurchase(any(), any(), any(), brazePropertiesCaptor.capture()) }.then { }
}
val settings = getMockSettings(logPurchaseWhenRevenuePresent = false)
brazeDestination.update(settings, Plugin.UpdateType.Initial)
brazeDestination.brazeTestingMock = brazeMock

val trackEvent = TrackEvent(
Expand All @@ -337,6 +380,37 @@ class BrazeSegmentTest {
assertEquals("red", brazeProperties["color"])
}

@Test
fun whenCalledWithRevenueAndSettingIsTrueButNameIsNotOrderCompleted_track_DoesCallLogPurchaseWithProperties() {
val brazePropertiesCaptor = argumentCaptor<BrazeProperties>()
val brazeMock = mock<Braze> {
on { logPurchase(any(), any(), any(), brazePropertiesCaptor.capture()) }.then { }
}
val settings = getMockSettings(logPurchaseWhenRevenuePresent = true)
brazeDestination.update(settings, Plugin.UpdateType.Initial)
brazeDestination.brazeTestingMock = brazeMock

val trackEvent = TrackEvent(
JsonObject(
mapOf(
"revenue" to JsonPrimitive(5.99),
"currency" to JsonPrimitive("CAD"),
"color" to JsonPrimitive("red")

)
),
"Random Event Name"
)
val payload = brazeDestination.track(trackEvent)
assertEquals(payload, trackEvent)
verify(brazeMock, times(1)).logPurchase(eq("Random Event Name"), any(), any(), any() as BrazeProperties?)

assertEquals(1, brazePropertiesCaptor.allValues.size)
val brazeProperties = brazePropertiesCaptor.firstValue
assertEquals(1, brazeProperties.size)
assertEquals("red", brazeProperties["color"])
}

@Test
fun whenEventNameIsInstallAttributed_track_callsSetAttributionData() {
val attributionDataCaptor = argumentCaptor<AttributionData>()
Expand All @@ -346,6 +420,9 @@ class BrazeSegmentTest {
}
val brazeMock = mock<Braze>() {
on { currentUser } doReturn brazeUserMock
on { getCurrentUser(any()) }.doAnswer { invocation ->
(invocation.arguments[0] as IValueCallback<BrazeUser>).onSuccess(brazeUserMock)
}
}
brazeDestination.brazeTestingMock = brazeMock

Expand Down Expand Up @@ -376,16 +453,82 @@ class BrazeSegmentTest {
verifyNoMoreInteractions(brazeUserMock)
}

@Test
fun whenCalledWithSubscriptionData_track_callsAddToSubscriptionGroup() {
val groupIdCaptor = argumentCaptor<String>()
val brazeUserMock: BrazeUser = mock() {
on { addToSubscriptionGroup(groupIdCaptor.capture()) }.thenReturn(true)
}

val brazeMock = mock<Braze>() {
on { currentUser } doReturn brazeUserMock
on { getCurrentUser(any()) }.doAnswer { invocation ->
(invocation.arguments[0] as IValueCallback<BrazeUser>).onSuccess(brazeUserMock)
}
}
brazeDestination.brazeTestingMock = brazeMock

val identifyEvent = IdentifyEvent(
"myUser",
getMockSubscriptionTraits(true)
)
val payload = brazeDestination.identify(identifyEvent)
assertEquals(payload, identifyEvent)
verify(brazeUserMock, times(1)).addToSubscriptionGroup(any())
assertEquals("123-456-789", groupIdCaptor.firstValue)

// Verify the other data is handled
verify(brazeUserMock, times(1)).setFirstName(FIRST_NAME)
verify(brazeUserMock, times(1)).setLastName(LAST_NAME)

// Verify that nothing else was called (subscription data didn't turn into the custom attributes)
verifyNoMoreInteractions(brazeUserMock)
}

@Test
fun whenCalledWithUnSubscriptionData_identify_callsRemoveFromSubscriptionGroup() {
val groupIdCaptor = argumentCaptor<String>()
val brazeUserMock: BrazeUser = mock() {
on { removeFromSubscriptionGroup(groupIdCaptor.capture()) }.thenReturn(true)
}

val brazeMock = mock<Braze>() {
on { currentUser } doReturn brazeUserMock
on { getCurrentUser(any()) }.doAnswer { invocation ->
(invocation.arguments[0] as IValueCallback<BrazeUser>).onSuccess(brazeUserMock)
}
}
brazeDestination.brazeTestingMock = brazeMock

val identifyEvent = IdentifyEvent(
"myUser",
getMockSubscriptionTraits(false)
)
val payload = brazeDestination.identify(identifyEvent)
assertEquals(payload, identifyEvent)
verify(brazeUserMock, times(1)).removeFromSubscriptionGroup(any())
assertEquals("123-456-789", groupIdCaptor.firstValue)

// Verify the other data is handled
verify(brazeUserMock, times(1)).setFirstName(FIRST_NAME)
verify(brazeUserMock, times(1)).setLastName(LAST_NAME)

// Verify that nothing else was called (subscription data didn't turn into the custom attributes)
verifyNoMoreInteractions(brazeUserMock)
}

private fun getMockSettings(
apiKey: String = API_KEY,
customEndpoint: String = CUSTOM_ENDPOINT,
autoInAppRegistration: Boolean = true
autoInAppRegistration: Boolean = true,
logPurchaseWhenRevenuePresent: Boolean = true
): Settings {
val brazeJsonSettings = JsonObject(
content = mapOf(
"apiKey" to JsonPrimitive(apiKey),
"customEndpoint" to JsonPrimitive(customEndpoint),
"automatic_in_app_message_registration_enabled" to JsonPrimitive(autoInAppRegistration)
"automatic_in_app_message_registration_enabled" to JsonPrimitive(autoInAppRegistration),
"logPurchaseWhenRevenuePresent" to JsonPrimitive(logPurchaseWhenRevenuePresent)
)
)
val integrations = JsonObject(mapOf("Appboy" to brazeJsonSettings))
Expand Down Expand Up @@ -439,6 +582,36 @@ class BrazeSegmentTest {
)
}

private fun getMockSubscriptionTraits(subscription: Boolean = true): Traits {
val groupId = "123-456-789"
val groupStatus = if (subscription) {
"subscribed"
} else {
"unsubscribed"
}

val subscriptionData = JsonArray(
listOf(
JsonObject(
mapOf(
"subscription_group_id" to JsonPrimitive(groupId),
"subscription_state_id" to JsonPrimitive(groupStatus)
)
)
)
)

val contentMap = mutableMapOf(
"firstName" to JsonPrimitive(FIRST_NAME),
"lastName" to JsonPrimitive(LAST_NAME),
"braze_subscription_groups" to subscriptionData
)

return JsonObject(
content = contentMap
)
}

@OptIn(ExperimentalContracts::class)
fun ktAssertNotNull(thing: Any?, failureMessage: String? = null) {
contract {
Expand Down
22 changes: 22 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,26 @@ plugins {
id 'com.android.application' version "$ANDROID_APPLICATION_PLUGIN" apply false
id 'com.android.library' version "$ANDROID_LIBRARY_PLUGIN" apply false
id 'org.jetbrains.kotlin.android' version "$KOTLIN_ANDROID_PLUGIN" apply false
id 'signing'
id "io.github.gradle-nexus.publish-plugin" version "${GRADLE_NEXUS_PUBLISH_PLUGIN_VERSION}"
}

apply plugin: 'io.github.gradle-nexus.publish-plugin'
apply plugin: 'maven-publish'
apply plugin: 'signing'

nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
packageGroup = "com.braze"
if (isReleaseBuild.toBoolean()) {
def secureProps = new Properties()
rootProject.file(findProperty("MAVEN_CENTRAL_SONATYPE_SECRETS_FILEPATH")).withInputStream { secureProps.load(it) }
username = secureProps["sonatype.username"]
password = secureProps["sonatype.password"]
}
}
}
}
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ android.nonTransitiveRClass=true

isReleaseBuild=false

LIBRARY_VERSION=1.3.0
LIBRARY_VERSION=1.4.0

BRAZE_SDK_VERSION=25.0.0
SEGMENT_SDK_VERSION=1.10.5
BRAZE_SDK_VERSION=26.1.0
SEGMENT_SDK_VERSION=1.13.0

ANDROIDX_CORE_KTX_VERSION=1.9.0
APPCOMPAT_VERSION=1.5.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.braze.enums.BrazeDateFormat
import com.braze.support.BrazeLogger
import com.braze.support.formatDate
import com.segment.analytics.kotlin.brazesample.testapp.databinding.ActivityMainBinding
import kotlinx.serialization.json.*
import java.util.*

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
Expand All @@ -21,7 +24,8 @@ class MainActivity : AppCompatActivity() {
}

findViewById<Button>(R.id.identifyButton).setOnClickListener {
MainApplication.analytics.identify("bob", buildJsonObject {
val userId = "segmentKotlin-${Date().formatDate(BrazeDateFormat.SHORT)}"
MainApplication.analytics.identify(userId, buildJsonObject {
put("username", "BobBraze")
put("email", "[email protected]")
put("plan", "premium")
Expand Down

0 comments on commit 6598608

Please sign in to comment.