Skip to content

Commit 4294267

Browse files
authored
Update SessionGenerator for first_session_id, session_index (#10764)
* Update SessionGenerator for first_session_id, session_index * Improve * Fix * Ternary
1 parent 1612473 commit 4294267

File tree

5 files changed

+106
-89
lines changed

5 files changed

+106
-89
lines changed

FirebaseSessions/Sources/SessionGenerator.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ import Foundation
1919

2020
struct SessionInfo {
2121
let sessionId: String
22-
let previousSessionId: String?
22+
let firstSessionId: String
2323
let shouldDispatchEvents: Bool
24+
let sessionIndex: Int32
2425

25-
init(sessionId: String, previousSessionId: String?, dispatchEvents: Bool) {
26+
init(sessionId: String, firstSessionId: String, dispatchEvents: Bool, sessionIndex: Int32) {
2627
self.sessionId = sessionId
27-
self.previousSessionId = previousSessionId
28+
self.firstSessionId = firstSessionId
2829
shouldDispatchEvents = dispatchEvents
30+
self.sessionIndex = sessionIndex
2931
}
3032
}
3133

@@ -39,25 +41,36 @@ class SessionGenerator {
3941
private var thisSession: SessionInfo?
4042
private var settings: SettingsProtocol
4143

44+
private var firstSessionId = ""
45+
private var sessionIndex: Int32
46+
4247
init(settings: SettingsProtocol) {
4348
self.settings = settings
49+
// This will be incremented to 0 on the first generation
50+
sessionIndex = -1
4451
}
4552

4653
// Generates a new Session ID. If there was already a generated Session ID
4754
// from the last session during the app's lifecycle, it will also set the last Session ID
4855
func generateNewSession() -> SessionInfo {
4956
let newSessionId = UUID().uuidString.replacingOccurrences(of: "-", with: "").lowercased()
5057

58+
// If firstSessionId is set, use it. Otherwise set it to the
59+
// first generated Session ID
60+
firstSessionId = firstSessionId.isEmpty ? newSessionId : firstSessionId
61+
62+
sessionIndex += 1
63+
5164
var collectEvents = true
5265
let randomValue = Double.random(in: 0 ... 1)
53-
5466
if randomValue > settings.samplingRate {
5567
collectEvents = false
5668
}
5769

5870
let newSession = SessionInfo(sessionId: newSessionId,
59-
previousSessionId: thisSession?.sessionId,
60-
dispatchEvents: collectEvents)
71+
firstSessionId: firstSessionId,
72+
dispatchEvents: collectEvents,
73+
sessionIndex: sessionIndex)
6174
thisSession = newSession
6275
return newSession
6376
}

FirebaseSessions/Sources/SessionStartEvent.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class SessionStartEvent: NSObject, GDTCOREventDataObject {
4343

4444
proto.event_type = firebase_appquality_sessions_EventType_SESSION_START
4545
proto.session_data.session_id = makeProtoString(sessionInfo.sessionId)
46+
proto.session_data.first_session_id = makeProtoString(sessionInfo.firstSessionId)
47+
proto.session_data.session_index = sessionInfo.sessionIndex
4648
proto.session_data.event_timestamp_us = time.timestampUS
4749

4850
proto.application_info.app_id = makeProtoString(appInfo.appID)

FirebaseSessions/Tests/Unit/SessionCoordinatorTests.swift

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,17 @@ class SessionCoordinatorTests: XCTestCase {
3434
)
3535
}
3636

37-
func test_attemptLoggingSessionStart_logsToGDT() throws {
38-
let sessionInfo = SessionInfo(
39-
sessionId: "testSessionId",
40-
previousSessionId: "testPreviousSessionId",
41-
dispatchEvents: true
37+
var defaultSessionInfo: SessionInfo {
38+
return SessionInfo(
39+
sessionId: "test_session_id",
40+
firstSessionId: "test_first_session_id",
41+
dispatchEvents: true,
42+
sessionIndex: 0
4243
)
43-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
44+
}
45+
46+
func test_attemptLoggingSessionStart_logsToGDT() throws {
47+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
4448
var resultSuccess = false
4549
coordinator.attemptLoggingSessionStart(event: event) { result in
4650
switch result {
@@ -65,12 +69,7 @@ class SessionCoordinatorTests: XCTestCase {
6569
func test_attemptLoggingSessionStart_handlesGDTError() throws {
6670
fireLogger.result = .failure(NSError(domain: "TestError", code: -1))
6771

68-
let sessionInfo = SessionInfo(
69-
sessionId: "testSessionId",
70-
previousSessionId: "testPreviousSessionId",
71-
dispatchEvents: true
72-
)
73-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
72+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
7473

7574
// Start success so it must be set to false
7675
var resultSuccess = true
@@ -98,12 +97,7 @@ class SessionCoordinatorTests: XCTestCase {
9897
func test_attemptLoggingSessionStart_handlesInstallationsError() throws {
9998
installations.result = .failure(NSError(domain: "TestInstallationsError", code: -1))
10099

101-
let sessionInfo = SessionInfo(
102-
sessionId: "testSessionId",
103-
previousSessionId: "testPreviousSessionId",
104-
dispatchEvents: true
105-
)
106-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
100+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
107101

108102
// Start success so it must be set to false
109103
var resultSuccess = true

FirebaseSessions/Tests/Unit/SessionGeneratorTests.swift

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,38 @@ class SessionGeneratorTests: XCTestCase {
8282
func test_generateNewSessionID_generatesValidID() throws {
8383
let sessionInfo = generator.generateNewSession()
8484
XCTAssert(isValidSessionID(sessionInfo.sessionId))
85-
XCTAssertNil(sessionInfo.previousSessionId)
85+
XCTAssert(isValidSessionID(sessionInfo.firstSessionId))
86+
XCTAssertEqual(sessionInfo.firstSessionId, sessionInfo.sessionId)
8687
}
8788

88-
/// Ensures that generating a Session ID multiple times results in the last Session ID being set in the previousSessionID field
89+
/// Ensures that generating a Session ID multiple times results in the fist Session ID being set
90+
/// in the firstSessionId field
8991
func test_generateNewSessionID_rotatesPreviousID() throws {
9092
let firstSessionInfo = generator.generateNewSession()
9193

92-
let firstSessionID = firstSessionInfo.sessionId
9394
XCTAssert(isValidSessionID(firstSessionInfo.sessionId))
94-
XCTAssertNil(firstSessionInfo.previousSessionId)
95+
XCTAssert(isValidSessionID(firstSessionInfo.firstSessionId))
96+
XCTAssertEqual(firstSessionInfo.firstSessionId, firstSessionInfo.sessionId)
97+
XCTAssertEqual(firstSessionInfo.sessionIndex, 0)
9598

9699
let secondSessionInfo = generator.generateNewSession()
97100

98101
XCTAssert(isValidSessionID(secondSessionInfo.sessionId))
99-
XCTAssert(isValidSessionID(secondSessionInfo.previousSessionId!))
100-
101-
// Ensure the new lastSessionID is equal to the sessionID from earlier
102-
XCTAssertEqual(secondSessionInfo.previousSessionId, firstSessionID)
102+
XCTAssert(isValidSessionID(secondSessionInfo.firstSessionId))
103+
// Ensure the new firstSessionId is equal to the first Session ID from earlier
104+
XCTAssertEqual(secondSessionInfo.firstSessionId, firstSessionInfo.sessionId)
105+
// Session Index should increase
106+
XCTAssertEqual(secondSessionInfo.sessionIndex, 1)
107+
108+
// Do a third round just in case
109+
let thirdSessionInfo = generator.generateNewSession()
110+
111+
XCTAssert(isValidSessionID(thirdSessionInfo.sessionId))
112+
XCTAssert(isValidSessionID(thirdSessionInfo.firstSessionId))
113+
// Ensure the new firstSessionId is equal to the first Session ID from earlier
114+
XCTAssertEqual(thirdSessionInfo.firstSessionId, firstSessionInfo.sessionId)
115+
// Session Index should increase
116+
XCTAssertEqual(thirdSessionInfo.sessionIndex, 2)
103117
}
104118

105119
func test_sessionsNotSampled_AllEventsAllowed() throws {

FirebaseSessions/Tests/Unit/SessionStartEventTests.swift

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,24 @@ class SessionStartEventTests: XCTestCase {
3838
appInfo = MockApplicationInfo()
3939
}
4040

41+
var defaultSessionInfo: SessionInfo {
42+
return SessionInfo(
43+
sessionId: "test_session_id",
44+
firstSessionId: "test_first_session_id",
45+
dispatchEvents: true,
46+
sessionIndex: 0
47+
)
48+
}
49+
50+
var thirdSessionInfo: SessionInfo {
51+
return SessionInfo(
52+
sessionId: "test_third_session_id",
53+
firstSessionId: "test_first_session_id",
54+
dispatchEvents: true,
55+
sessionIndex: 2
56+
)
57+
}
58+
4159
/// This function runs the `testCase` twice, once for the proto object stored in
4260
/// the event, and once after encoding and decoding the proto. This is useful for
4361
/// testing cases where the proto hasn't been encoded correctly.
@@ -52,32 +70,28 @@ class SessionStartEventTests: XCTestCase {
5270
testCase(decodedProto)
5371
}
5472

55-
func test_init_setsSessionIDs() {
56-
let sessionInfo = SessionInfo(
57-
sessionId: "test_session_id",
58-
previousSessionId: "test_previous_session_id",
59-
dispatchEvents: true
60-
)
61-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
73+
func test_init_setsSessionData() {
74+
let event = SessionStartEvent(sessionInfo: thirdSessionInfo, appInfo: appInfo, time: time)
6275

6376
testProtoAndDecodedProto(sessionEvent: event) { proto in
6477
assertEqualProtoString(
6578
proto.session_data.session_id,
66-
expected: "test_session_id",
79+
expected: "test_third_session_id",
6780
fieldName: "session_id"
6881
)
82+
assertEqualProtoString(
83+
proto.session_data.first_session_id,
84+
expected: "test_first_session_id",
85+
fieldName: "first_session_id"
86+
)
87+
XCTAssertEqual(proto.session_data.session_index, 2)
6988

7089
XCTAssertEqual(proto.session_data.event_timestamp_us, 123)
7190
}
7291
}
7392

7493
func test_init_setsApplicationInfo() {
75-
let sessionInfo = SessionInfo(
76-
sessionId: "session_id",
77-
previousSessionId: "previous_session_id",
78-
dispatchEvents: true
79-
)
80-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
94+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
8195

8296
testProtoAndDecodedProto(sessionEvent: event) { proto in
8397
assertEqualProtoString(
@@ -110,12 +124,7 @@ class SessionStartEventTests: XCTestCase {
110124
}
111125

112126
func test_setInstallationID_setsInstallationID() {
113-
let sessionInfo = SessionInfo(
114-
sessionId: "session_id",
115-
previousSessionId: "previous_session_id",
116-
dispatchEvents: true
117-
)
118-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
127+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
119128

120129
event.setInstallationID(installationId: "testInstallationID")
121130

@@ -143,12 +152,11 @@ class SessionStartEventTests: XCTestCase {
143152
expectations.forEach { (given: String, expected: firebase_appquality_sessions_OsName) in
144153
appInfo.osName = given
145154

146-
let sessionInfo = SessionInfo(
147-
sessionId: "session_id",
148-
previousSessionId: "previous_session_id",
149-
dispatchEvents: true
155+
let event = SessionStartEvent(
156+
sessionInfo: self.defaultSessionInfo,
157+
appInfo: appInfo,
158+
time: time
150159
)
151-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
152160

153161
testProtoAndDecodedProto(sessionEvent: event) { proto in
154162
XCTAssertEqual(event.proto.application_info.apple_app_info.os_name, expected)
@@ -174,24 +182,18 @@ class SessionStartEventTests: XCTestCase {
174182
expected: firebase_appquality_sessions_LogEnvironment) in
175183
appInfo.environment = given
176184

177-
let sessionInfo = SessionInfo(
178-
sessionId: "session_id",
179-
previousSessionId: "previous_session_id",
180-
dispatchEvents: true
185+
let event = SessionStartEvent(
186+
sessionInfo: self.defaultSessionInfo,
187+
appInfo: appInfo,
188+
time: time
181189
)
182-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
183190

184191
XCTAssertEqual(event.proto.application_info.log_environment, expected)
185192
}
186193
}
187194

188195
func test_dataCollectionState_defaultIsUnknown() {
189-
let sessionInfo = SessionInfo(
190-
sessionId: "session_id",
191-
previousSessionId: "previous_session_id",
192-
dispatchEvents: true
193-
)
194-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
196+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
195197

196198
testProtoAndDecodedProto(sessionEvent: event) { proto in
197199
XCTAssertEqual(
@@ -217,12 +219,7 @@ class SessionStartEventTests: XCTestCase {
217219
#endif
218220
appInfo.networkInfo = mockNetworkInfo
219221

220-
let sessionInfo = SessionInfo(
221-
sessionId: "session_id",
222-
previousSessionId: "previous_session_id",
223-
dispatchEvents: true
224-
)
225-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
222+
let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
226223

227224
// These fields will not be filled in when Crashlytics is installed
228225
event.set(subscriber: .Crashlytics, isDataCollectionEnabled: true, appInfo: appInfo)
@@ -304,12 +301,11 @@ class SessionStartEventTests: XCTestCase {
304301
mockNetworkInfo.networkType = given
305302
appInfo.networkInfo = mockNetworkInfo
306303

307-
let sessionInfo = SessionInfo(
308-
sessionId: "session_id",
309-
previousSessionId: "previous_session_id",
310-
dispatchEvents: true
304+
let event = SessionStartEvent(
305+
sessionInfo: self.defaultSessionInfo,
306+
appInfo: appInfo,
307+
time: time
311308
)
312-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
313309

314310
// These fields will only be filled in when the Perf SDK is installed
315311
event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
@@ -389,12 +385,11 @@ class SessionStartEventTests: XCTestCase {
389385
mockNetworkInfo.mobileSubtype = given
390386
appInfo.networkInfo = mockNetworkInfo
391387

392-
let sessionInfo = SessionInfo(
393-
sessionId: "session_id",
394-
previousSessionId: "previous_session_id",
395-
dispatchEvents: true
388+
let event = SessionStartEvent(
389+
sessionInfo: self.defaultSessionInfo,
390+
appInfo: appInfo,
391+
time: time
396392
)
397-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
398393

399394
// These fields will only be filled in when the Perf SDK is installed
400395
event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
@@ -483,12 +478,11 @@ class SessionStartEventTests: XCTestCase {
483478
mockNetworkInfo.mobileSubtype = given
484479
appInfo.networkInfo = mockNetworkInfo
485480

486-
let sessionInfo = SessionInfo(
487-
sessionId: "session_id",
488-
previousSessionId: "previous_session_id",
489-
dispatchEvents: true
481+
let event = SessionStartEvent(
482+
sessionInfo: self.defaultSessionInfo,
483+
appInfo: appInfo,
484+
time: time
490485
)
491-
let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: appInfo, time: time)
492486

493487
// These fields will only be filled in when the Perf SDK is installed
494488
event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)

0 commit comments

Comments
 (0)