Skip to content

Commit a149ea4

Browse files
authored
Merge d2b1452 into 0358ae9
2 parents 0358ae9 + d2b1452 commit a149ea4

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/FirebaseSessions.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import com.google.firebase.ktx.Firebase
2424
import com.google.firebase.ktx.app
2525

2626
class FirebaseSessions internal constructor(firebaseApp: FirebaseApp) {
27+
28+
private val sessionGenerator = SessionGenerator(collectEvents = true)
29+
2730
init {
2831
val sessionInitiator = SessionInitiator(WallClock::elapsedRealtime, this::initiateSessionStart)
2932
val context = firebaseApp.applicationContext.applicationContext
@@ -40,6 +43,8 @@ class FirebaseSessions internal constructor(firebaseApp: FirebaseApp) {
4043
private fun initiateSessionStart() {
4144
// TODO(mrober): Generate a session
4245
Log.i(TAG, "Initiate session start")
46+
47+
sessionGenerator.generateNewSession()
4348
}
4449

4550
companion object {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.sessions
18+
19+
import java.util.UUID
20+
21+
/**
22+
* [SessionInfo] is a data class responsible for storing information about the current Session.
23+
*
24+
* @hide
25+
*/
26+
internal data class SessionInfo(
27+
val sessionId: String,
28+
val firstSessionId: String,
29+
val collectEvents: Boolean,
30+
val sessionIndex: Int,
31+
)
32+
33+
/**
34+
* The [SessionGenerator] is responsible for generating the Session ID, and keeping the
35+
* [SessionInfo] up to date with the latest values.
36+
*
37+
* @hide
38+
*/
39+
internal class SessionGenerator(collectEvents: Boolean) {
40+
private var firstSessionId = ""
41+
private var sessionIndex: Int = -1
42+
private var collectEvents = collectEvents
43+
44+
private var thisSession: SessionInfo =
45+
SessionInfo(
46+
sessionId = "",
47+
firstSessionId = "",
48+
collectEvents = collectEvents,
49+
sessionIndex = sessionIndex
50+
)
51+
52+
// Generates a new Session ID. If there was already a generated Session ID
53+
// from the last session during the app's lifecycle, it will also set the last Session ID
54+
fun generateNewSession() {
55+
val newSessionId = UUID.randomUUID().toString().replace("-", "").lowercase()
56+
57+
// If firstSessionId is set, use it. Otherwise set it to the
58+
// first generated Session ID
59+
firstSessionId = if (firstSessionId.isEmpty()) newSessionId else firstSessionId
60+
61+
sessionIndex += 1
62+
63+
thisSession =
64+
SessionInfo(
65+
sessionId = newSessionId,
66+
firstSessionId = firstSessionId,
67+
collectEvents = collectEvents,
68+
sessionIndex = sessionIndex
69+
)
70+
}
71+
72+
val currentSession: SessionInfo
73+
get() = thisSession
74+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.sessions
18+
19+
import com.google.common.truth.Truth.assertThat
20+
import org.junit.Test
21+
22+
class SessionGeneratorTest {
23+
fun isValidSessionId(sessionId: String): Boolean {
24+
if (sessionId.length != 32) {
25+
return false
26+
}
27+
if (sessionId.contains("-")) {
28+
return false
29+
}
30+
if (sessionId.lowercase() != sessionId) {
31+
return false
32+
}
33+
return true
34+
}
35+
36+
// This test case isn't important behavior. Nothing should access
37+
// currentSession before generateNewSession has been called. This test just
38+
// ensures it has consistent behavior.
39+
@Test
40+
fun currentSession_beforeGenerateReturnsDefault() {
41+
val sessionGenerator = SessionGenerator(collectEvents = false)
42+
43+
assertThat(sessionGenerator.currentSession.sessionId).isEqualTo("")
44+
assertThat(sessionGenerator.currentSession.firstSessionId).isEqualTo("")
45+
assertThat(sessionGenerator.currentSession.collectEvents).isEqualTo(false)
46+
assertThat(sessionGenerator.currentSession.sessionIndex).isEqualTo(-1)
47+
}
48+
49+
@Test
50+
fun generateNewSessionID_generatesValidSessionInfo() {
51+
val sessionGenerator = SessionGenerator(collectEvents = true)
52+
53+
sessionGenerator.generateNewSession()
54+
55+
assertThat(isValidSessionId(sessionGenerator.currentSession.sessionId)).isEqualTo(true)
56+
assertThat(isValidSessionId(sessionGenerator.currentSession.firstSessionId)).isEqualTo(true)
57+
assertThat(sessionGenerator.currentSession.firstSessionId)
58+
.isEqualTo(sessionGenerator.currentSession.sessionId)
59+
assertThat(sessionGenerator.currentSession.collectEvents).isEqualTo(true)
60+
assertThat(sessionGenerator.currentSession.sessionIndex).isEqualTo(0)
61+
}
62+
63+
// Ensures that generating a Session ID multiple times results in the fist
64+
// Session ID being set in the firstSessionId field
65+
@Test
66+
fun generateNewSessionID_incrementsSessionIndex_keepsFirstSessionId() {
67+
val sessionGenerator = SessionGenerator(collectEvents = true)
68+
69+
sessionGenerator.generateNewSession()
70+
71+
val firstSessionInfo = sessionGenerator.currentSession
72+
73+
assertThat(isValidSessionId(firstSessionInfo.sessionId)).isEqualTo(true)
74+
assertThat(isValidSessionId(firstSessionInfo.firstSessionId)).isEqualTo(true)
75+
assertThat(firstSessionInfo.firstSessionId).isEqualTo(firstSessionInfo.sessionId)
76+
assertThat(firstSessionInfo.sessionIndex).isEqualTo(0)
77+
78+
sessionGenerator.generateNewSession()
79+
val secondSessionInfo = sessionGenerator.currentSession
80+
81+
assertThat(isValidSessionId(secondSessionInfo.sessionId)).isEqualTo(true)
82+
assertThat(isValidSessionId(secondSessionInfo.firstSessionId)).isEqualTo(true)
83+
// Ensure the new firstSessionId is equal to the first Session ID from earlier
84+
assertThat(secondSessionInfo.firstSessionId).isEqualTo(firstSessionInfo.sessionId)
85+
// Session Index should increase
86+
assertThat(secondSessionInfo.sessionIndex).isEqualTo(1)
87+
88+
// Do a third round just in case
89+
sessionGenerator.generateNewSession()
90+
val thirdSessionInfo = sessionGenerator.currentSession
91+
92+
assertThat(isValidSessionId(thirdSessionInfo.sessionId)).isEqualTo(true)
93+
assertThat(isValidSessionId(thirdSessionInfo.firstSessionId)).isEqualTo(true)
94+
// Ensure the new firstSessionId is equal to the first Session ID from earlier
95+
assertThat(thirdSessionInfo.firstSessionId).isEqualTo(firstSessionInfo.sessionId)
96+
// Session Index should increase
97+
assertThat(thirdSessionInfo.sessionIndex).isEqualTo(2)
98+
}
99+
}

0 commit comments

Comments
 (0)