Skip to content

Commit eae52cb

Browse files
committed
add unit test for storage and event stream
1 parent 4ec1ef5 commit eae52cb

File tree

3 files changed

+255
-39
lines changed

3 files changed

+255
-39
lines changed

core/src/main/java/com/segment/analytics/kotlin/core/utilities/StorageImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ open class StorageImpl(
2525
internal val eventStream: EventStream,
2626
private val store: Store,
2727
private val writeKey: String,
28-
private val fileIndexKey: String,
28+
internal val fileIndexKey: String,
2929
private val ioDispatcher: CoroutineDispatcher
3030
) : Subscriber, Storage {
3131

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package com.segment.analytics.kotlin.core
2+
3+
import com.segment.analytics.kotlin.core.utilities.ConcreteStorageProvider
4+
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
5+
import com.segment.analytics.kotlin.core.utilities.EventStream
6+
import com.segment.analytics.kotlin.core.utilities.FileEventStream
7+
import com.segment.analytics.kotlin.core.utilities.InMemoryEventStream
8+
import com.segment.analytics.kotlin.core.utilities.InMemoryPrefs
9+
import com.segment.analytics.kotlin.core.utilities.InMemoryStorageProvider
10+
import com.segment.analytics.kotlin.core.utilities.KVS
11+
import com.segment.analytics.kotlin.core.utilities.PropertiesFile
12+
import com.segment.analytics.kotlin.core.utilities.StorageImpl
13+
import com.segment.analytics.kotlin.core.utils.clearPersistentStorage
14+
import com.segment.analytics.kotlin.core.utils.testAnalytics
15+
import io.mockk.every
16+
import io.mockk.mockk
17+
import io.mockk.verify
18+
import kotlinx.coroutines.test.TestScope
19+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
20+
import kotlinx.coroutines.test.runTest
21+
import kotlinx.serialization.encodeToString
22+
import kotlinx.serialization.json.buildJsonObject
23+
import kotlinx.serialization.json.put
24+
import org.junit.jupiter.api.Assertions.*
25+
import org.junit.jupiter.api.BeforeEach
26+
import org.junit.jupiter.api.Nested
27+
import org.junit.jupiter.api.Test
28+
import org.junit.jupiter.api.assertThrows
29+
import sovran.kotlin.Store
30+
import java.lang.StringBuilder
31+
import java.util.Date
32+
33+
class StorageTest {
34+
@Nested
35+
inner class StorageProviderTest {
36+
private lateinit var analytics: Analytics
37+
private val testDispatcher = UnconfinedTestDispatcher()
38+
private val testScope = TestScope(testDispatcher)
39+
40+
@BeforeEach
41+
fun setup() {
42+
clearPersistentStorage()
43+
val config = Configuration(
44+
writeKey = "123",
45+
application = "Test"
46+
)
47+
48+
analytics = testAnalytics(config, testScope, testDispatcher)
49+
}
50+
51+
@Test
52+
fun concreteStorageProviderTest() {
53+
val storage = ConcreteStorageProvider.createStorage(analytics) as StorageImpl
54+
assertTrue(storage.eventStream is FileEventStream)
55+
assertTrue(storage.propertiesFile is PropertiesFile)
56+
57+
val eventStream = storage.eventStream as FileEventStream
58+
val propertiesFile = (storage.propertiesFile as PropertiesFile).file
59+
60+
val dir = "/tmp/analytics-kotlin/${analytics.configuration.writeKey}"
61+
// we don't cache storage directory, but we can use the parent of the event storage to verify
62+
assertEquals(dir, eventStream.directory.parent)
63+
assertTrue(eventStream.directory.path.contains(dir))
64+
assertTrue(propertiesFile.path.contains(dir))
65+
assertTrue(eventStream.directory.exists())
66+
assertTrue(propertiesFile.exists())
67+
}
68+
69+
@Test
70+
fun inMemoryStorageProviderTest() {
71+
val storage = InMemoryStorageProvider.createStorage(analytics) as StorageImpl
72+
assertTrue(storage.eventStream is InMemoryEventStream)
73+
assertTrue(storage.propertiesFile is InMemoryPrefs)
74+
}
75+
}
76+
77+
@Nested
78+
inner class StorageTest {
79+
private lateinit var storage: StorageImpl
80+
81+
private lateinit var prefs: KVS
82+
83+
private lateinit var stream: EventStream
84+
85+
private lateinit var payload: String
86+
87+
@BeforeEach
88+
fun setup() {
89+
val trackEvent = TrackEvent(
90+
event = "clicked",
91+
properties = buildJsonObject { put("foo", "bar") })
92+
.apply {
93+
messageId = "qwerty-1234"
94+
anonymousId = "anonId"
95+
integrations = emptyJsonObject
96+
context = emptyJsonObject
97+
timestamp = Date(0).toInstant().toString()
98+
}
99+
payload = EncodeDefaultsJson.encodeToString(trackEvent)
100+
prefs = InMemoryPrefs()
101+
stream = mockk<EventStream>(relaxed = true)
102+
storage = StorageImpl(prefs, stream, mockk<Store>(), "test", "key", UnconfinedTestDispatcher())
103+
}
104+
105+
@Test
106+
fun writeNewFileTest() = runTest {
107+
every { stream.openOrCreate(any()) } returns true
108+
storage.write(Storage.Constants.Events, payload)
109+
verify(exactly = 1) {
110+
stream.write(storage.begin)
111+
stream.write(payload)
112+
}
113+
}
114+
115+
@Test
116+
fun rolloverToNewFileTest() = runTest {
117+
every { stream.openOrCreate(any()) } returns false andThen true
118+
every { stream.length } returns Storage.MAX_FILE_SIZE + 1L
119+
every { stream.isOpened } returns true
120+
121+
storage.write(Storage.Constants.Events, payload)
122+
assertEquals(1, prefs.get(storage.fileIndexKey, 0))
123+
verify (exactly = 1) {
124+
stream.finishAndClose(any())
125+
stream.write(storage.begin)
126+
stream.write(payload)
127+
}
128+
129+
verify (exactly = 3){
130+
stream.write(any())
131+
}
132+
}
133+
134+
@Test
135+
fun largePayloadCauseExceptionTest() = runTest {
136+
val letters = "abcdefghijklmnopqrstuvwxyz1234567890"
137+
val largePayload = StringBuilder()
138+
for (i in 0..1000) {
139+
largePayload.append(letters)
140+
}
141+
142+
assertThrows<Exception> {
143+
storage.write(Storage.Constants.Events, largePayload.toString())
144+
}
145+
}
146+
147+
@Test
148+
fun writePrefsAsyncTest() = runTest {
149+
val expected = "userid"
150+
assertNull(storage.read(Storage.Constants.UserId))
151+
storage.write(Storage.Constants.UserId, expected)
152+
assertEquals(expected, storage.read(Storage.Constants.UserId))
153+
}
154+
155+
@Test
156+
fun writePrefsTest() {
157+
val expected = "userId"
158+
assertNull(storage.read(Storage.Constants.UserId))
159+
storage.writePrefs(Storage.Constants.UserId, expected)
160+
assertEquals(expected, storage.read(Storage.Constants.UserId))
161+
}
162+
163+
@Test
164+
fun rolloverTest() = runTest {
165+
every { stream.isOpened } returns true
166+
167+
storage.rollover()
168+
169+
verify (exactly = 1) {
170+
stream.write(any())
171+
stream.finishAndClose(any())
172+
}
173+
174+
assertEquals(1, prefs.get(storage.fileIndexKey, 0))
175+
}
176+
177+
@Test
178+
fun readTest() {
179+
val files = listOf("test1.tmp", "test2", "test3.tmp", "test4")
180+
every { stream.read() } returns files
181+
prefs.put(Storage.Constants.UserId.rawVal, "userId")
182+
183+
val actual = storage.read(Storage.Constants.Events)
184+
assertEquals(listOf(files[1], files[3]).joinToString(), actual)
185+
assertEquals("userId", storage.read(Storage.Constants.UserId))
186+
}
187+
188+
@Test
189+
fun removeTest() {
190+
prefs.put(Storage.Constants.UserId.rawVal, "userId")
191+
storage.remove(Storage.Constants.UserId)
192+
193+
assertTrue(storage.remove(Storage.Constants.Events))
194+
assertNull(storage.read(Storage.Constants.UserId))
195+
}
196+
197+
@Test
198+
fun removeFileTest() {
199+
storage.removeFile("file")
200+
verify (exactly = 1) {
201+
stream.remove("file")
202+
}
203+
204+
every { stream.remove(any()) } throws java.lang.Exception()
205+
assertFalse(storage.removeFile("file"))
206+
}
207+
208+
@Test
209+
fun readAsStream() {
210+
storage.readAsStream("file")
211+
verify (exactly = 1) {
212+
stream.readAsStream(any())
213+
}
214+
}
215+
}
216+
}

0 commit comments

Comments
 (0)