1package com.parseable.android
3import com.parseable.android.data.api.ParseableApiClient
4import com.parseable.android.data.model.*
5import com.parseable.android.data.repository.ParseableRepository
7import kotlinx.coroutines.test.runTest
8import org.junit.Assert.*
12class ParseableRepositoryTest {
14 private lateinit var apiClient: ParseableApiClient
15 private lateinit var repository: ParseableRepository
19 apiClient = mockk(relaxed = true)
20 repository = ParseableRepository(apiClient)
24 fun `getAbout caches result on success`() = runTest {
25 val aboutInfo = AboutInfo(version = "1.0.0", mode = "standalone")
26 coEvery { apiClient.getAbout() } returns ApiResult.Success(aboutInfo)
28 val first = repository.getAbout()
29 val second = repository.getAbout()
31 assertTrue(first is ApiResult.Success)
32 assertEquals("1.0.0", (first as ApiResult.Success).data.version)
33 // Should only call API once due to caching
34 coVerify(exactly = 1) { apiClient.getAbout() }
38 fun `getAbout does not cache errors`() = runTest {
39 coEvery { apiClient.getAbout() } returns ApiResult.Error("fail", 500)
41 val first = repository.getAbout()
44 assertTrue(first is ApiResult.Error)
45 coVerify(exactly = 2) { apiClient.getAbout() }
49 fun `listStreams forceRefresh bypasses cache`() = runTest {
50 val streams = listOf(LogStream(name = "test"))
51 coEvery { apiClient.listStreams() } returns ApiResult.Success(streams)
53 repository.listStreams()
54 repository.listStreams(forceRefresh = true)
56 coVerify(exactly = 2) { apiClient.listStreams() }
60 fun `listStreams returns cached data within TTL`() = runTest {
61 val streams = listOf(LogStream(name = "test"))
62 coEvery { apiClient.listStreams() } returns ApiResult.Success(streams)
64 repository.listStreams()
65 val cached = repository.listStreams(forceRefresh = false)
67 assertTrue(cached is ApiResult.Success)
68 assertEquals(1, (cached as ApiResult.Success).data.size)
69 coVerify(exactly = 1) { apiClient.listStreams() }
73 fun `invalidateAll clears all caches`() = runTest {
74 val about = AboutInfo(version = "1.0.0")
75 val streams = listOf(LogStream(name = "s1"))
76 coEvery { apiClient.getAbout() } returns ApiResult.Success(about)
77 coEvery { apiClient.listStreams() } returns ApiResult.Success(streams)
80 repository.listStreams()
81 repository.invalidateAll()
83 repository.listStreams()
85 coVerify(exactly = 2) { apiClient.getAbout() }
86 coVerify(exactly = 2) { apiClient.listStreams() }
90 fun `configure invalidates cache and configures client`() = runTest {
91 val config = ServerConfig("https://test.com", "user", "pass", true)
92 repository.configure(config)
93 verify { apiClient.configure(config) }
97 fun `auth error triggers channel`() = runTest {
98 coEvery { apiClient.listStreams() } returns ApiResult.Error("Unauthorized", 401)
100 val result = repository.listStreams()
102 assertTrue(result is ApiResult.Error)
103 assertTrue((result as ApiResult.Error).isUnauthorized)
107 fun `queryLogs builds correct SQL with filter`() = runTest {
108 coEvery { apiClient.queryLogs(any(), any(), any()) } returns ApiResult.Success(emptyList())
110 repository.queryLogs(
111 stream = "my_stream",
112 startTime = "2024-01-01T00:00:00Z",
113 endTime = "2024-01-02T00:00:00Z",
114 filterSql = "\"level\" = 'ERROR'",
120 match { it.contains("WHERE \"level\" = 'ERROR'") && it.contains("LIMIT 100") },
121 "2024-01-01T00:00:00Z",
122 "2024-01-02T00:00:00Z",
128 fun `queryLogs without filter builds SQL without WHERE`() = runTest {
129 coEvery { apiClient.queryLogs(any(), any(), any()) } returns ApiResult.Success(emptyList())
131 repository.queryLogs(
139 match { !it.contains("WHERE") && it.contains("\"test\"") },
147 fun `deleteStream invalidates cache`() = runTest {
148 val streams = listOf(LogStream(name = "s1"))
149 coEvery { apiClient.listStreams() } returns ApiResult.Success(streams)
150 coEvery { apiClient.deleteStream(any()) } returns ApiResult.Success("ok")
152 repository.listStreams()
153 repository.deleteStream("s1")
154 repository.listStreams()
156 // After delete, cache was invalidated, so listStreams called twice
157 coVerify(exactly = 2) { apiClient.listStreams() }
161 fun `getStreamSchema caches per stream`() = runTest {
162 val schema = StreamSchema(fields = listOf(SchemaField(name = "col1")))
163 coEvery { apiClient.getStreamSchema("s1") } returns ApiResult.Success(schema)
164 coEvery { apiClient.getStreamSchema("s2") } returns ApiResult.Success(schema)
166 repository.getStreamSchema("s1")
167 repository.getStreamSchema("s1") // cached
168 repository.getStreamSchema("s2") // different stream, not cached
170 coVerify(exactly = 1) { apiClient.getStreamSchema("s1") }
171 coVerify(exactly = 1) { apiClient.getStreamSchema("s2") }
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list