Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 24.1.4

* Updated user properties caching mechanism according to sessions.
* Cleaned up unused gradle dependencies from root build.gradle.

## 24.1.3
Expand Down
11 changes: 11 additions & 0 deletions sdk-java/src/main/java/ly/count/sdk/java/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ public class Config {
protected String city = null;
protected String country = null;
protected boolean locationEnabled = true;
protected boolean autoSendUserPropertiesOnSessions = true;

// TODO: storage limits & configuration
// protected int maxRequestsStored = 0;
Expand Down Expand Up @@ -1480,4 +1481,14 @@ public String toString() {
return "DID " + id + " ( " + strategy + ")";
}
}

/**
* Disable automatic sending of user properties on session begin, update and end
*
* @return {@code this} instance for method chaining
*/
public Config disableAutoSendUserPropertiesOnSessions() {
this.autoSendUserPropertiesOnSessions = false;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class InternalConfig extends Config {
protected IdGenerator viewIdGenerator;
protected IdGenerator eventIdGenerator;
protected ViewIdProvider viewIdProvider;

/**
* Shouldn't be used!
*/
Expand Down Expand Up @@ -211,4 +212,8 @@ String[] getLocationParams() {
boolean isLocationDisabled() {
return !locationEnabled;
}

boolean isAutoSendUserPropertiesOnSessions() {
return autoSendUserPropertiesOnSessions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ Future<Boolean> begin(Long now) {
}

this.consents = SDKCore.instance.consents;
if (config.isAutoSendUserPropertiesOnSessions() && config.sdk.userProfile() != null) {
config.sdk.module(ModuleUserProfile.class).saveInternal();
}

if (pushOnChange) {
Storage.pushAsync(config, this);
Expand Down Expand Up @@ -157,6 +160,9 @@ Future<Boolean> update(Long now) {
}

this.consents = SDKCore.instance.consents;
if (config.isAutoSendUserPropertiesOnSessions() && config.sdk.userProfile() != null) {
config.sdk.module(ModuleUserProfile.class).saveInternal();
}

Long duration = updateDuration(now);

Expand Down Expand Up @@ -192,6 +198,9 @@ Future<Boolean> end(Long now, final Tasks.Callback<Boolean> callback, String did
ended = now == null ? System.nanoTime() : now;

this.consents = SDKCore.instance.consents;
if (config.isAutoSendUserPropertiesOnSessions() && config.sdk.userProfile() != null) {
config.sdk.module(ModuleUserProfile.class).saveInternal();
}

if (currentView != null) {
currentView.stop(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,81 @@ public void view_stopStartedAndNext() {
ModuleViewsTests.validateView("next", 0.0, 2, 3, false, true, null, TestUtils.keysValues[1], TestUtils.keysValues[0]);
}

/**
* Validates that when session calls are made, if any user properties are set,
* they are sent before sending that session call
* Validated with all session calls: begin, update, end
*
* @throws InterruptedException if thread is interrupted
*/
@Test
public void userPropsOnSessions() throws InterruptedException {
Countly.instance().init(TestUtils.getConfigSessions(Config.Feature.UserProfiles));
Countly.instance().userProfile().setProperty("name", "John Doe");
Countly.instance().userProfile().setProperty("custom_key", "custom_value");

Countly.session().begin();
Map<String, String>[] RQ = TestUtils.getCurrentRQ();
UserEditorTests.validateUserDetailsRequestInRQ(TestUtils.map("user_details", TestUtils.json("name", "John Doe", "custom", TestUtils.map("custom_key", "custom_value"))), 0, 2);
Assert.assertEquals("1", RQ[1].get("begin_session"));

Thread.sleep(2000); // wait for session to update
Countly.instance().userProfile().save();
RQ = TestUtils.getCurrentRQ();
Assert.assertEquals(2, RQ.length); // Validate that user properties are flushed

Countly.instance().userProfile().setProperty("email", "john@doe.com");
Countly.session().update();

RQ = TestUtils.getCurrentRQ();
Assert.assertEquals(TestUtils.json("email", "john@doe.com"), RQ[2].get("user_details"));
Assert.assertEquals("2", RQ[3].get("session_duration"));

Thread.sleep(2000); // wait for session to update
Countly.instance().userProfile().save();
RQ = TestUtils.getCurrentRQ();
Assert.assertEquals(4, RQ.length); // Validate that user properties are flushed with update call

Countly.instance().userProfile().setProperty("done", "yes");
Countly.session().end();

RQ = TestUtils.getCurrentRQ();
Assert.assertEquals(TestUtils.json("custom", TestUtils.map("done", "yes")), RQ[4].get("user_details"));
Assert.assertEquals("1", RQ[5].get("end_session"));
}

/**
* Validates that when session calls are made, if any user properties are set,
* they are not packed because auto-send is disabled
*
* @throws InterruptedException if thread is interrupted
*/
@Test
public void userPropsOnSessions_reversed() throws InterruptedException {
Countly.instance().init(TestUtils.getConfigSessions(Config.Feature.UserProfiles).disableAutoSendUserPropertiesOnSessions());
Countly.instance().userProfile().setProperty("name", "John Doe");
Countly.instance().userProfile().setProperty("custom_key", "custom_value");

Countly.session().begin();
Map<String, String>[] RQ = TestUtils.getCurrentRQ();
Assert.assertEquals(1, RQ.length);
Assert.assertEquals("1", RQ[0].get("begin_session"));

Thread.sleep(2000); // wait for session to update
Countly.session().update();
RQ = TestUtils.getCurrentRQ();

Assert.assertEquals(2, RQ.length);
Assert.assertEquals("2", RQ[1].get("session_duration"));

Thread.sleep(2000);
Countly.session().end();
RQ = TestUtils.getCurrentRQ();

Assert.assertEquals(3, RQ.length);
Assert.assertEquals("1", RQ[2].get("end_session"));
}

private void validateNotEquals(int idOffset, BiFunction<SessionImpl, SessionImpl, Consumer<Long>> setter) {
Countly.instance().init(TestUtils.getConfigSessions());
long ts = TimeUtils.timestampMs();
Expand Down
Loading