Skip to content

Commit f3bce6c

Browse files
authored
Merge pull request #145 from Countly/auto_events_on_user_props
Auto events on user props
2 parents cf85277 + b16151b commit f3bce6c

File tree

6 files changed

+130
-10
lines changed

6 files changed

+130
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 23.2.4
2+
- Mitigated an issue where cached events were not queued when a user property was recorded.
3+
14
## 23.2.3
25
- Mitigated an issue where the new device ID was used when ending a session if device ID was changed without merging.
36

include/countly.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class Countly : public cly::CountlyDelegates {
5858

5959
void enableManualSessionControl();
6060

61+
void disableAutoEventsOnUserProperties();
62+
6163
void setHTTPClient(HTTPClientFunction fun);
6264

6365
void setMetrics(const std::string &os, const std::string &os_version, const std::string &device, const std::string &resolution, const std::string &carrier, const std::string &app_version);

include/countly/constants.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <string>
1414

1515
#define COUNTLY_SDK_NAME "cpp-native-unknown"
16-
#define COUNTLY_SDK_VERSION "23.2.3"
16+
#define COUNTLY_SDK_VERSION "23.2.4"
1717
#define COUNTLY_POST_THRESHOLD 2000
1818
#define COUNTLY_KEEPALIVE_INTERVAL 3000
1919
#define COUNTLY_MAX_EVENTS_DEFAULT 200

include/countly/countly_configuration.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ struct CountlyConfiguration {
7070

7171
bool manualSessionControl = false;
7272

73+
bool autoEventsOnUserProperties = true;
74+
7375
HTTPClientFunction http_client_function = nullptr;
7476

7577
nlohmann::json metrics;

src/countly.cpp

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,20 @@ void Countly::enableManualSessionControl() {
142142
mutex->unlock();
143143
}
144144

145+
/**
146+
* Disable automatic events on user properties changes.
147+
*/
148+
void Countly::disableAutoEventsOnUserProperties() {
149+
if (is_sdk_initialized) {
150+
log(LogLevel::WARNING, "[Countly][disableAutoEventsOnUserProperties] You can not disable automatic events on user properties after SDK initialization.");
151+
return;
152+
}
153+
154+
mutex->lock();
155+
configuration->autoEventsOnUserProperties = false;
156+
mutex->unlock();
157+
}
158+
145159
void Countly::setMetrics(const std::string &os, const std::string &os_version, const std::string &device, const std::string &resolution, const std::string &carrier, const std::string &app_version) {
146160
if (is_sdk_initialized) {
147161
log(LogLevel::WARNING, "[Countly][setMetrics] You can not set metrics after SDK initialization.");
@@ -182,6 +196,12 @@ void Countly::setUserDetails(const std::map<std::string, std::string> &value) {
182196
return;
183197
}
184198

199+
if (configuration->autoEventsOnUserProperties == true) {
200+
mutex->unlock();
201+
flushEvents();
202+
mutex->lock();
203+
}
204+
185205
std::map<std::string, std::string> data = {{"app_key", session_params["app_key"].get<std::string>()}, {"device_id", session_params["device_id"].get<std::string>()}, {"user_details", session_params["user_details"].dump()}};
186206

187207
requestModule->addRequestToQueue(data);
@@ -198,6 +218,12 @@ void Countly::setCustomUserDetails(const std::map<std::string, std::string> &val
198218
return;
199219
}
200220

221+
if (configuration->autoEventsOnUserProperties == true) {
222+
mutex->unlock();
223+
flushEvents();
224+
mutex->lock();
225+
}
226+
201227
std::map<std::string, std::string> data = {{"app_key", session_params["app_key"].get<std::string>()}, {"device_id", session_params["device_id"].get<std::string>()}, {"user_details", session_params["user_details"].dump()}};
202228
requestModule->addRequestToQueue(data);
203229

@@ -345,7 +371,7 @@ void Countly::_changeDeviceIdWithoutMerge(const std::string &value) {
345371

346372
// send all event to server and end current session of old user
347373
flushEvents();
348-
if(configuration->manualSessionControl == false){
374+
if (configuration->manualSessionControl == false) {
349375
endSession();
350376
}
351377

@@ -355,10 +381,9 @@ void Countly::_changeDeviceIdWithoutMerge(const std::string &value) {
355381
mutex->unlock();
356382

357383
// start a new session for new user
358-
if(configuration->manualSessionControl == false){
384+
if (configuration->manualSessionControl == false) {
359385
beginSession();
360386
}
361-
362387
}
363388
#pragma endregion Device Id
364389

@@ -439,7 +464,7 @@ void Countly::start(const std::string &app_key, const std::string &host, int por
439464

440465
if (!running) {
441466

442-
if(configuration->manualSessionControl == false){
467+
if (configuration->manualSessionControl == false) {
443468
mutex->unlock();
444469
beginSession();
445470
mutex->lock();
@@ -612,7 +637,7 @@ bool Countly::attemptSessionUpdateEQ() {
612637
return false;
613638
}
614639
#endif
615-
if(configuration->manualSessionControl == false){
640+
if (configuration->manualSessionControl == false) {
616641
return !updateSession();
617642
} else {
618643
packEvents();
@@ -735,7 +760,7 @@ bool Countly::updateSession() {
735760
mutex->lock();
736761
if (began_session == false) {
737762
mutex->unlock();
738-
if(configuration->manualSessionControl == true){
763+
if (configuration->manualSessionControl == true) {
739764
log(LogLevel::WARNING, "[Countly][updateSession] SDK is in manual session control mode and there is no active session. Please start a session first.");
740765
return false;
741766
}
@@ -829,7 +854,7 @@ void Countly::packEvents() {
829854
} else {
830855
log(LogLevel::DEBUG, "[Countly][packEvents] EQ empty.");
831856
}
832-
// report events if there are any to request queue
857+
// report events if there are any to request queue
833858
if (!no_events) {
834859
sendEventsToRQ(events);
835860
}
@@ -852,7 +877,6 @@ void Countly::packEvents() {
852877
mutex->unlock();
853878
}
854879

855-
856880
void Countly::sendEventsToRQ(const nlohmann::json &events) {
857881
log(LogLevel::DEBUG, "[Countly][sendEventsToRQ] Sending events to RQ.");
858882
std::map<std::string, std::string> data = {{"app_key", session_params["app_key"].get<std::string>()}, {"device_id", session_params["device_id"].get<std::string>()}, {"events", events.dump()}};
@@ -861,7 +885,7 @@ void Countly::sendEventsToRQ(const nlohmann::json &events) {
861885

862886
bool Countly::endSession() {
863887
log(LogLevel::INFO, "[Countly][endSession]");
864-
if(began_session == false) {
888+
if (began_session == false) {
865889
log(LogLevel::DEBUG, "[Countly][endSession] There is no active session to end.");
866890
return true;
867891
}

tests/event_queue.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,93 @@ TEST_CASE("Tests that sets 'setEventsToRQThreshold' before and after SDK starts"
234234
nlohmann::json events = nlohmann::json::parse(oldest_call.data["events"]);
235235
CHECK(events.size() == 3);
236236
}
237+
}
238+
239+
TEST_CASE("Tests that saving user details trigger flushing EQ"){
240+
clearSDK();
241+
Countly &countly = Countly::getInstance();
242+
243+
// Automatic saving of events before user props calls
244+
SUBCASE("Saving user properties should flush EQ") {
245+
countly.enableManualSessionControl();
246+
test_utils::initCountlyWithFakeNetworking(true, countly);
247+
248+
test_utils::generateEvents(4, countly);
249+
CHECK(countly.checkEQSize() == 4);
250+
251+
// set user properties, this should flush the EQ
252+
countly.setUserDetails({{"name", "Full name"}});
253+
CHECK(countly.checkEQSize() == 0);
254+
255+
test_utils::generateEvents(4, countly);
256+
CHECK(countly.checkEQSize() == 4);
257+
258+
// set custom user properties, this should flush the EQ
259+
countly.setCustomUserDetails({{"custom_key", "custom_value"}});
260+
CHECK(countly.checkEQSize() == 0);
261+
262+
// RQ should have 4 events and user details
263+
// trigger RQ to send requests to http_call_queue
264+
countly.processRQDebug();
265+
// queue should have 4 requests
266+
CHECK(!http_call_queue.empty());
267+
CHECK(http_call_queue.size() == 4);
268+
HTTPCall eventsReq1 = http_call_queue.front();
269+
http_call_queue.pop_front();
270+
HTTPCall userDetails = http_call_queue.front();
271+
http_call_queue.pop_front();
272+
HTTPCall eventsReq2 = http_call_queue.front();
273+
http_call_queue.pop_front();
274+
HTTPCall customUserDetails = http_call_queue.front();
275+
http_call_queue.pop_front();
276+
CHECK(http_call_queue.size() == 0);
277+
278+
// last call should have 4 events
279+
nlohmann::json events1 = nlohmann::json::parse(eventsReq1.data["events"]);
280+
CHECK(events1.size() == 4);
281+
nlohmann::json userDetailsJson = nlohmann::json::parse(userDetails.data["user_details"]);
282+
CHECK(userDetailsJson["name"] == "Full name");
283+
284+
nlohmann::json events2 = nlohmann::json::parse(eventsReq2.data["events"]);
285+
CHECK(events2.size() == 4);
286+
nlohmann::json customUserDetailsJson = nlohmann::json::parse(customUserDetails.data["user_details"]);
287+
CHECK(customUserDetailsJson["custom"]["custom_key"] == "custom_value");
288+
}
289+
290+
// Automatic saving of events before user props calls
291+
SUBCASE("Saving user properties should not flush EQ when behavior is disabled") {
292+
countly.enableManualSessionControl();
293+
countly.disableAutoEventsOnUserProperties();
294+
test_utils::initCountlyWithFakeNetworking(true, countly);
295+
296+
test_utils::generateEvents(4, countly);
297+
CHECK(countly.checkEQSize() == 4);
298+
299+
// set user properties, this should flush the EQ
300+
countly.setUserDetails({{"name", "Full name"}});
301+
CHECK(countly.checkEQSize() == 4);
302+
303+
test_utils::generateEvents(4, countly);
304+
CHECK(countly.checkEQSize() == 8);
305+
306+
// set custom user properties, this should flush the EQ
307+
countly.setCustomUserDetails({{"custom_key", "custom_value"}});
308+
CHECK(countly.checkEQSize() == 8);
309+
// RQ should have 4 events and user details
310+
// trigger RQ to send requests to http_call_queue
311+
countly.processRQDebug();
312+
// queue should have 2 requests
313+
CHECK(!http_call_queue.empty());
314+
CHECK(http_call_queue.size() == 2);
315+
HTTPCall userDetails = http_call_queue.front();
316+
http_call_queue.pop_front();
317+
HTTPCall customUserDetails = http_call_queue.front();
318+
http_call_queue.pop_front();
319+
CHECK(http_call_queue.size() == 0);
320+
321+
nlohmann::json userDetailsJson = nlohmann::json::parse(userDetails.data["user_details"]);
322+
CHECK(userDetailsJson["name"] == "Full name");
323+
nlohmann::json customUserDetailsJson = nlohmann::json::parse(customUserDetails.data["user_details"]);
324+
CHECK(customUserDetailsJson["custom"]["custom_key"] == "custom_value");
325+
}
237326
}

0 commit comments

Comments
 (0)