Skip to content

Commit 6d9cf53

Browse files
zhu-xiaoweixiaoweii
andauthored
fix: timestamp order in event and user attributes. (#15)
Co-authored-by: xiaoweii <xiaoweii@amazom.com>
1 parent b5bb3d8 commit 6d9cf53

File tree

5 files changed

+96
-48
lines changed

5 files changed

+96
-48
lines changed

Sources/Clickstream/AWSClickstreamPlugin+ClientBehavior.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,23 @@ import Foundation
1010

1111
extension AWSClickstreamPlugin {
1212
func identifyUser(userId: String, userProfile: AnalyticsUserProfile?) {
13-
if userId == Event.User.USER_ID_EMPTY {
14-
userProfile?.properties?.forEach { key, value in
15-
Task {
16-
await analyticsClient.addUserAttribute(value, forKey: key)
13+
Task {
14+
if userId == Event.User.USER_ID_EMPTY {
15+
if let attributes = userProfile?.properties {
16+
for attribute in attributes {
17+
await analyticsClient.addUserAttribute(attribute.value, forKey: attribute.key)
18+
}
1719
}
18-
}
19-
} else {
20-
Task {
20+
} else {
2121
if userId == Event.User.USER_ID_NIL {
2222
await analyticsClient.updateUserId(nil)
2323
} else {
2424
await analyticsClient.updateUserId(userId)
2525
}
2626
}
27-
}
28-
Task {
2927
await analyticsClient.updateUserAttributes()
28+
record(eventWithName: Event.PresetEvent.PROFILE_SET)
3029
}
31-
record(eventWithName: Event.PresetEvent.PROFILE_SET)
3230
}
3331

3432
func record(event: AnalyticsEvent) {

Sources/Clickstream/ClickstreamAnalytics.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ public enum ClickstreamAnalytics {
1717

1818
/// Use this method to record event
1919
/// - Parameter eventName: the event name
20-
public static func recordEvent(eventName: String) {
20+
public static func recordEvent(_ eventName: String) {
2121
Amplify.Analytics.record(eventWithName: eventName)
2222
}
2323

2424
/// The method to record event with ClickstreamAttribute
2525
/// - Parameters:
2626
/// - eventName: the event name
2727
/// - attributes: the event attributes
28-
public static func recordEvent(eventName: String, attributes: ClickstreamAttribute) {
28+
public static func recordEvent(_ eventName: String, _ attributes: ClickstreamAttribute) {
2929
let event = BaseClickstreamEvent(name: eventName, attribute: attributes)
3030
Amplify.Analytics.record(event: event)
3131
}
@@ -37,27 +37,27 @@ public enum ClickstreamAnalytics {
3737

3838
/// Add global attributes
3939
/// - Parameter attributes: the global attributes to add
40-
public static func addGlobalAttributes(attributes: ClickstreamAttribute) {
40+
public static func addGlobalAttributes(_ attributes: ClickstreamAttribute) {
4141
Amplify.Analytics.registerGlobalProperties(attributes)
4242
}
4343

4444
/// Delete global attributes
4545
/// - Parameter attributes: the global attributes names to delete
46-
public static func deleteGlobalAttributes(attributes: String...) {
46+
public static func deleteGlobalAttributes(_ attributes: String...) {
4747
Amplify.Analytics.unregisterGlobalProperties(attributes)
4848
}
4949

5050
/// Add user attributes
5151
/// - Parameter attributes: the user attributes to add
52-
public static func addUserAttributes(attributes: ClickstreamAttribute) {
52+
public static func addUserAttributes(_ attributes: ClickstreamAttribute) {
5353
let userProfile = AnalyticsUserProfile(location: nil, properties: attributes)
5454
Amplify.Analytics.identifyUser(userId: Event.User.USER_ID_EMPTY,
5555
userProfile: userProfile)
5656
}
5757

5858
/// Set user id for login and logout
5959
/// - Parameter userId: current userId, nil for logout
60-
public static func setUserId(userId: String?) {
60+
public static func setUserId(_ userId: String?) {
6161
if userId == nil {
6262
Amplify.Analytics.identifyUser(userId: Event.User.USER_ID_NIL)
6363
} else {

Sources/Clickstream/ClickstreamObjc.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import Foundation
99

1010
/// ClickstreamAnalytics api for objective-c
1111
@objcMembers public class ClickstreamObjc: NSObject {
12+
13+
/// Hide the constructor
14+
@nonobjc
15+
override private init() {
16+
super.init()
17+
}
18+
1219
/// Init the Clickstream sdk
1320
public static func initSDK() throws {
1421
try ClickstreamAnalytics.initSDK()
@@ -17,15 +24,15 @@ import Foundation
1724
/// Use this method to record event
1825
/// - Parameter eventName: the event name
1926
public static func recordEvent(_ eventName: String) {
20-
ClickstreamAnalytics.recordEvent(eventName: eventName)
27+
ClickstreamAnalytics.recordEvent(eventName)
2128
}
2229

2330
/// The method to record event with attributes
2431
/// - Parameters:
2532
/// - eventName: the event name
2633
/// - attributes: the event attributes which type is NSDictionary
2734
public static func recordEvent(_ eventName: String, _ attributes: NSDictionary) {
28-
ClickstreamAnalytics.recordEvent(eventName: eventName, attributes: getAttributes(attributes))
35+
ClickstreamAnalytics.recordEvent(eventName, getAttributes(attributes))
2936
}
3037

3138
/// Use this method to send events immediately
@@ -36,27 +43,27 @@ import Foundation
3643
/// Add global attributes
3744
/// - Parameter attributes: the global attributes to add
3845
public static func addGlobalAttributes(_ attributes: NSDictionary) {
39-
ClickstreamAnalytics.addGlobalAttributes(attributes: getAttributes(attributes))
46+
ClickstreamAnalytics.addGlobalAttributes(getAttributes(attributes))
4047
}
4148

4249
/// Delete global attributes
4350
/// - Parameter attributes: the global attributes names to delete
4451
public static func deleteGlobalAttributes(_ attributes: [String]) {
4552
for attribute in attributes {
46-
ClickstreamAnalytics.deleteGlobalAttributes(attributes: attribute)
53+
ClickstreamAnalytics.deleteGlobalAttributes(attribute)
4754
}
4855
}
4956

5057
/// Add user attributes
5158
/// - Parameter attributes: the user attributes to add
5259
public static func addUserAttributes(_ attributes: NSDictionary) {
53-
ClickstreamAnalytics.addUserAttributes(attributes: getAttributes(attributes))
60+
ClickstreamAnalytics.addUserAttributes(getAttributes(attributes))
5461
}
5562

5663
/// Set user id for login and logout
5764
/// - Parameter userId: current userId, nil for logout
5865
public static func setUserId(_ userId: String?) {
59-
ClickstreamAnalytics.setUserId(userId: userId)
66+
ClickstreamAnalytics.setUserId(userId)
6067
}
6168

6269
/// Get Clickstream configuration, please config it after initialize sdk

Sources/Clickstream/PackageInfo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
enum PackageInfo {
99
/// the clickstream analytics iOS sdk version
1010
/// note: update and align the version with new tag version before committing new tag
11-
static let version = "0.4.2"
11+
static let version = "0.5.0"
1212
}

Tests/ClickstreamTests/IntegrationTest.swift

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class IntegrationTest: XCTestCase {
3737
"appId": appId,
3838
"endpoint": "http://localhost:8080/collect",
3939
"isCompressEvents": false,
40-
"autoFlushEventsInterval": 80,
40+
"autoFlushEventsInterval": 10000,
4141
"isTrackAppExceptionEvents": false
4242
]
4343
]
@@ -61,42 +61,41 @@ class IntegrationTest: XCTestCase {
6161
}
6262

6363
func testRecordOneEventSuccess() throws {
64-
let attribute: ClickstreamAttribute = [
64+
ClickstreamAnalytics.recordEvent("userId", [
6565
"Channel": "SMS",
6666
"Successful": true,
6767
"Score": 90
68-
]
69-
ClickstreamAnalytics.recordEvent(eventName: "userId", attributes: attribute)
68+
])
7069
ClickstreamAnalytics.flushEvents()
7170
Thread.sleep(forTimeInterval: 0.2)
7271
let eventCount = try eventRecorder.dbUtil.getEventCount()
7372
XCTAssertEqual(0, eventCount)
7473
}
7574

7675
func testRecordOneEventWithNameSuccess() throws {
77-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
76+
ClickstreamAnalytics.recordEvent("testEvent")
7877
ClickstreamAnalytics.flushEvents()
7978
Thread.sleep(forTimeInterval: 0.2)
8079
let eventCount = try eventRecorder.dbUtil.getEventCount()
8180
XCTAssertEqual(0, eventCount)
8281
}
8382

8483
func testFlushEvents() throws {
85-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
84+
ClickstreamAnalytics.recordEvent("testEvent")
8685
ClickstreamAnalytics.flushEvents()
8786
Thread.sleep(forTimeInterval: 0.2)
8887
let eventCount = try eventRecorder.dbUtil.getEventCount()
8988
XCTAssertEqual(0, eventCount)
9089
}
9190

9291
func testAddGlobalAttribute() throws {
93-
ClickstreamAnalytics.addGlobalAttributes(attributes: [
92+
ClickstreamAnalytics.addGlobalAttributes([
9493
"channel": "AppStore",
9594
"level": 5.1,
9695
"class": 5,
9796
"isOpenNotification": true
9897
])
99-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
98+
ClickstreamAnalytics.recordEvent("testEvent")
10099
Thread.sleep(forTimeInterval: 0.1)
101100

102101
let testEvent = try getTestEvent()
@@ -108,14 +107,14 @@ class IntegrationTest: XCTestCase {
108107
}
109108

110109
func testDeleteGlobalAttribute() throws {
111-
ClickstreamAnalytics.addGlobalAttributes(attributes: [
110+
ClickstreamAnalytics.addGlobalAttributes([
112111
"channel": "AppStore",
113112
"level": 5.1,
114113
"class": 5,
115114
"isOpenNotification": true
116115
])
117-
ClickstreamAnalytics.deleteGlobalAttributes(attributes: "channel")
118-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
116+
ClickstreamAnalytics.deleteGlobalAttributes("channel")
117+
ClickstreamAnalytics.recordEvent("testEvent")
119118
Thread.sleep(forTimeInterval: 0.1)
120119

121120
let testEvent = try getTestEvent()
@@ -127,15 +126,15 @@ class IntegrationTest: XCTestCase {
127126
}
128127

129128
func testAddUserAttribute() throws {
130-
ClickstreamAnalytics.setUserId(userId: "13232")
131-
let userAttribute: ClickstreamAttribute = [
129+
ClickstreamAnalytics.setUserId("13232")
130+
ClickstreamAnalytics.addUserAttributes([
132131
"_user_age": 21,
133132
"isFirstOpen": true,
134133
"score": 85.2,
135134
"_user_name": "carl"
136-
]
137-
ClickstreamAnalytics.addUserAttributes(attributes: userAttribute)
138-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
135+
])
136+
Thread.sleep(forTimeInterval: 0.1)
137+
ClickstreamAnalytics.recordEvent("testEvent")
139138
Thread.sleep(forTimeInterval: 0.1)
140139
let testEvent = try getTestEvent()
141140
let userInfo = testEvent["user"] as! [String: Any]
@@ -147,26 +146,26 @@ class IntegrationTest: XCTestCase {
147146
}
148147

149148
func testSetUserIdString() throws {
150-
ClickstreamAnalytics.setUserId(userId: "12345")
151-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
149+
ClickstreamAnalytics.setUserId("12345")
150+
ClickstreamAnalytics.recordEvent("testEvent")
152151
Thread.sleep(forTimeInterval: 0.1)
153152
let testEvent = try getTestEvent()
154153
let userInfo = testEvent["user"] as! [String: Any]
155154
XCTAssertEqual("12345", (userInfo[Event.ReservedAttribute.USER_ID] as! JsonObject)["value"] as! String)
156155
}
157156

158157
func testSetUserIdNil() throws {
159-
ClickstreamAnalytics.setUserId(userId: "12345")
160-
ClickstreamAnalytics.setUserId(userId: nil)
161-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
158+
ClickstreamAnalytics.setUserId("12345")
159+
ClickstreamAnalytics.setUserId(nil)
160+
ClickstreamAnalytics.recordEvent("testEvent")
162161
Thread.sleep(forTimeInterval: 0.1)
163162
let testEvent = try getTestEvent()
164163
let userInfo = testEvent["user"] as! [String: Any]
165164
XCTAssertNil(userInfo[Event.ReservedAttribute.USER_ID])
166165
}
167166

168167
func testProfileSetEvent() throws {
169-
ClickstreamAnalytics.setUserId(userId: "12345")
168+
ClickstreamAnalytics.setUserId("12345")
170169
Thread.sleep(forTimeInterval: 0.1)
171170
let eventArray = try eventRecorder.getBatchEvent().eventsJson.jsonArray()
172171
let profileSetEvent = eventArray[eventArray.count - 1]
@@ -175,10 +174,52 @@ class IntegrationTest: XCTestCase {
175174
as! JsonObject)["value"] as! String, "12345")
176175
}
177176

177+
func testProfileSetEventWithAllAttributes() throws {
178+
ClickstreamAnalytics.addUserAttributes([
179+
"_user_age": 21,
180+
"isFirstOpen": true,
181+
"score": 85.2,
182+
"_user_name": "carl"
183+
])
184+
Thread.sleep(forTimeInterval: 0.1)
185+
let eventArray = try eventRecorder.getBatchEvent().eventsJson.jsonArray()
186+
let profileSetEvent = eventArray[eventArray.count - 1]
187+
XCTAssertEqual(profileSetEvent["event_type"] as! String, Event.PresetEvent.PROFILE_SET)
188+
let user = (profileSetEvent["user"] as! JsonObject)
189+
XCTAssertEqual((user["_user_age"] as! JsonObject)["value"] as! Int, 21)
190+
XCTAssertEqual((user["isFirstOpen"] as! JsonObject)["value"] as! Bool, true)
191+
XCTAssertEqual((user["score"] as! JsonObject)["value"] as! Double, 85.2)
192+
XCTAssertEqual((user["_user_name"] as! JsonObject)["value"] as! String, "carl")
193+
XCTAssertNotNil(user[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP])
194+
}
195+
196+
func testProfileSetTimestamp() throws {
197+
ClickstreamAnalytics.addUserAttributes([
198+
"_user_age": 21,
199+
"isFirstOpen": true,
200+
"score": 85.2,
201+
"_user_name": "carl"
202+
])
203+
Thread.sleep(forTimeInterval: 0.1)
204+
let eventArray = try eventRecorder.getBatchEvent().eventsJson.jsonArray()
205+
let profileSetEvent = eventArray[eventArray.count - 1]
206+
XCTAssertEqual(profileSetEvent["event_type"] as! String, Event.PresetEvent.PROFILE_SET)
207+
let eventTime = profileSetEvent["timestamp"] as! Int64
208+
let user = (profileSetEvent["user"] as! JsonObject)
209+
let userAgeSetTime = (user["_user_age"] as! JsonObject)["set_timestamp"] as! Int64
210+
let isFirstOpenSetTime = (user["isFirstOpen"] as! JsonObject)["set_timestamp"] as! Int64
211+
let scoreSetTime = (user["score"] as! JsonObject)["set_timestamp"] as! Int64
212+
let userNameSetTime = (user["_user_name"] as! JsonObject)["set_timestamp"] as! Int64
213+
XCTAssertTrue(eventTime >= userAgeSetTime)
214+
XCTAssertTrue(eventTime >= isFirstOpenSetTime)
215+
XCTAssertTrue(eventTime >= scoreSetTime)
216+
XCTAssertTrue(eventTime >= userNameSetTime)
217+
}
218+
178219
func testModifyEndpoint() throws {
179220
let configuration = try ClickstreamAnalytics.getClickstreamConfiguration()
180221
configuration.endpoint = testFailEndpoint
181-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
222+
ClickstreamAnalytics.recordEvent("testEvent")
182223
ClickstreamAnalytics.flushEvents()
183224
Thread.sleep(forTimeInterval: 0.2)
184225
let eventCount = try eventRecorder.dbUtil.getEventCount()
@@ -190,7 +231,7 @@ class IntegrationTest: XCTestCase {
190231
configuration.isCompressEvents = true
191232
configuration.isLogEvents = true
192233
configuration.authCookie = "authCookie"
193-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
234+
ClickstreamAnalytics.recordEvent("testEvent")
194235
ClickstreamAnalytics.flushEvents()
195236
Thread.sleep(forTimeInterval: 0.2)
196237
let eventCount = try eventRecorder.dbUtil.getEventCount()
@@ -223,6 +264,7 @@ class IntegrationTest: XCTestCase {
223264
]
224265
ClickstreamObjc.addGlobalAttributes(attribute)
225266
ClickstreamObjc.deleteGlobalAttributes(["Channel"])
267+
Thread.sleep(forTimeInterval: 0.1)
226268
ClickstreamObjc.recordEvent("testEvent")
227269
Thread.sleep(forTimeInterval: 0.1)
228270
let testEvent = try getTestEvent()
@@ -242,6 +284,7 @@ class IntegrationTest: XCTestCase {
242284
"_user_name": "carl"
243285
]
244286
ClickstreamObjc.addUserAttributes(userAttribute)
287+
Thread.sleep(forTimeInterval: 0.1)
245288
ClickstreamObjc.recordEvent("testEvent")
246289
Thread.sleep(forTimeInterval: 0.1)
247290
let testEvent = try getTestEvent()
@@ -257,7 +300,7 @@ class IntegrationTest: XCTestCase {
257300
let configuration = try ClickstreamObjc.getClickstreamConfiguration()
258301
configuration.isCompressEvents = true
259302
configuration.authCookie = "authCookie"
260-
ClickstreamAnalytics.recordEvent(eventName: "testEvent")
303+
ClickstreamAnalytics.recordEvent("testEvent")
261304
ClickstreamAnalytics.flushEvents()
262305
Thread.sleep(forTimeInterval: 0.2)
263306
let eventCount = try eventRecorder.dbUtil.getEventCount()

0 commit comments

Comments
 (0)