Skip to content

Commit a5964bf

Browse files
committed
Extend search functionality to include body and headers
- Add search support for requestBody and responseBody fields - Add search support for requestHeaders and responseHeaders (both header names and values) - Maintain existing GraphQL operation name search functionality - Update SQL query in HttpTransactionDao to search across all relevant fields - Update MainViewModel to pass searchQuery for both code and text searches - Add comprehensive tests for body and headers search functionality This enhancement allows users to search transactions not only by URL path and GraphQL operation name, but also by content in request/response bodies and headers, making it easier to find specific transactions.
1 parent b2eb1ec commit a5964bf

File tree

5 files changed

+153
-18
lines changed

5 files changed

+153
-18
lines changed

library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,11 @@ internal class HttpTransactionDatabaseRepository(
1515
code: String,
1616
path: String,
1717
): LiveData<List<HttpTransactionTuple>> {
18-
val pathQuery = if (path.isNotEmpty()) "%$path%" else "%"
18+
val codeQuery = if (code.isNotEmpty()) "$code%" else "%"
19+
val searchQuery = if (path.isNotEmpty()) "%$path%" else "%"
1920
return transactionDao.getFilteredTuples(
20-
"$code%",
21-
pathQuery = pathQuery,
22-
/*
23-
* Refer <a href='https://github.com/ChuckerTeam/chucker/issues/847">Issue #847</a> for
24-
* more context
25-
*/
26-
graphQlQuery = pathQuery,
21+
codeQuery = codeQuery,
22+
searchQuery = searchQuery,
2723
)
2824
}
2925

library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,18 @@ internal interface HttpTransactionDao {
2222
@Query(
2323
"SELECT id, requestDate, tookMs, protocol, method, host, path, scheme, responseCode, " +
2424
"requestPayloadSize, responsePayloadSize, error, graphQLDetected, graphQlOperationName FROM " +
25-
"transactions WHERE responseCode LIKE :codeQuery AND (path LIKE :pathQuery OR " +
26-
"graphQlOperationName LIKE :graphQlQuery) ORDER BY requestDate DESC",
25+
"transactions WHERE responseCode LIKE :codeQuery AND (" +
26+
"path LIKE :searchQuery OR " +
27+
"graphQlOperationName LIKE :searchQuery OR " +
28+
"requestBody LIKE :searchQuery OR " +
29+
"responseBody LIKE :searchQuery OR " +
30+
"requestHeaders LIKE :searchQuery OR " +
31+
"responseHeaders LIKE :searchQuery" +
32+
") ORDER BY requestDate DESC",
2733
)
2834
fun getFilteredTuples(
2935
codeQuery: String,
30-
pathQuery: String,
31-
graphQlQuery: String = "",
36+
searchQuery: String,
3237
): LiveData<List<HttpTransactionTuple>>
3338

3439
@Insert

library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ internal class MainViewModel : ViewModel() {
3434
with(RepositoryProvider.transaction()) {
3535
when {
3636
searchQuery.isNullOrBlank() -> getSortedTransactionTuples()
37-
searchQuery.isDigitsOnly() -> getFilteredTransactionTuples(searchQuery, "")
37+
searchQuery.isDigitsOnly() -> getFilteredTransactionTuples(searchQuery, searchQuery)
3838
else -> getFilteredTransactionTuples("", searchQuery)
3939
}
4040
}

library/src/test/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDaoTest.kt

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ internal class HttpTransactionDaoTest {
200200
insertTransaction(transactionTwo)
201201
insertTransaction(transactionThree)
202202

203-
testObject.getFilteredTuples(codeQuery = "418", pathQuery = "%abc%").observeForever { result ->
203+
testObject.getFilteredTuples(codeQuery = "%", searchQuery = "%abc%").observeForever { result ->
204204
assertTuples(listOf(transactionOne, transactionTwo), result)
205205
}
206206
}
@@ -234,7 +234,7 @@ internal class HttpTransactionDaoTest {
234234
insertTransaction(transactionFour)
235235

236236
testObject
237-
.getFilteredTuples(codeQuery = "%", pathQuery = "%get%", graphQlQuery = "%get%")
237+
.getFilteredTuples(codeQuery = "%", searchQuery = "%get%")
238238
.observeForever { result ->
239239
assertTuples(listOf(transactionFour), result)
240240
}
@@ -263,11 +263,145 @@ internal class HttpTransactionDaoTest {
263263
insertTransaction(transactionTwo)
264264
insertTransaction(transactionThree)
265265

266-
testObject.getFilteredTuples(codeQuery = "4%", pathQuery = "%").observeForever { result ->
266+
testObject.getFilteredTuples(codeQuery = "4%", searchQuery = "%").observeForever { result ->
267267
assertTuples(listOf(transactionThree, transactionOne), result)
268268
}
269269
}
270270

271+
@Test
272+
fun `transaction tuples are filtered by request body`() =
273+
runBlocking {
274+
val transactionOne =
275+
createRequest("test").withResponseData().apply {
276+
requestDate = 200L
277+
requestBody = "searchTermInBody"
278+
}
279+
val transactionTwo =
280+
createRequest("other").withResponseData().apply {
281+
requestDate = 100L
282+
requestBody = "differentContent"
283+
}
284+
285+
insertTransaction(transactionOne)
286+
insertTransaction(transactionTwo)
287+
288+
testObject.getFilteredTuples(codeQuery = "%", searchQuery = "%searchTermInBody%").observeForever { result ->
289+
assertTuples(listOf(transactionOne), result)
290+
}
291+
}
292+
293+
@Test
294+
fun `transaction tuples are filtered by response body`() =
295+
runBlocking {
296+
val transactionOne =
297+
createRequest("test").withResponseData().apply {
298+
requestDate = 200L
299+
responseBody = "searchTermInResponse"
300+
}
301+
val transactionTwo =
302+
createRequest("other").withResponseData().apply {
303+
requestDate = 100L
304+
responseBody = "differentContent"
305+
}
306+
307+
insertTransaction(transactionOne)
308+
insertTransaction(transactionTwo)
309+
310+
testObject.getFilteredTuples(codeQuery = "%", searchQuery = "%searchTermInResponse%").observeForever { result ->
311+
assertTuples(listOf(transactionOne), result)
312+
}
313+
}
314+
315+
@Test
316+
fun `transaction tuples are filtered by request headers`() =
317+
runBlocking {
318+
val transactionOne =
319+
createRequest("test").withResponseData().apply {
320+
requestDate = 200L
321+
setRequestHeaders(
322+
okhttp3.Headers.Builder()
323+
.add("Authorization", "Bearer searchTermInHeader")
324+
.build(),
325+
)
326+
}
327+
val transactionTwo =
328+
createRequest("other").withResponseData().apply {
329+
requestDate = 100L
330+
setRequestHeaders(
331+
okhttp3.Headers.Builder()
332+
.add("Authorization", "Bearer differentToken")
333+
.build(),
334+
)
335+
}
336+
337+
insertTransaction(transactionOne)
338+
insertTransaction(transactionTwo)
339+
340+
testObject.getFilteredTuples(codeQuery = "%", searchQuery = "%searchTermInHeader%").observeForever { result ->
341+
assertTuples(listOf(transactionOne), result)
342+
}
343+
}
344+
345+
@Test
346+
fun `transaction tuples are filtered by response headers`() =
347+
runBlocking {
348+
val transactionOne =
349+
createRequest("test").withResponseData().apply {
350+
requestDate = 200L
351+
setResponseHeaders(
352+
okhttp3.Headers.Builder()
353+
.add("X-Custom-Header", "searchTermInResponseHeader")
354+
.build(),
355+
)
356+
}
357+
val transactionTwo =
358+
createRequest("other").withResponseData().apply {
359+
requestDate = 100L
360+
setResponseHeaders(
361+
okhttp3.Headers.Builder()
362+
.add("X-Custom-Header", "differentValue")
363+
.build(),
364+
)
365+
}
366+
367+
insertTransaction(transactionOne)
368+
insertTransaction(transactionTwo)
369+
370+
testObject.getFilteredTuples(codeQuery = "%", searchQuery = "%searchTermInResponseHeader%").observeForever { result ->
371+
assertTuples(listOf(transactionOne), result)
372+
}
373+
}
374+
375+
@Test
376+
fun `transaction tuples are filtered by header name`() =
377+
runBlocking {
378+
val transactionOne =
379+
createRequest("test").withResponseData().apply {
380+
requestDate = 200L
381+
setRequestHeaders(
382+
okhttp3.Headers.Builder()
383+
.add("X-Special-Header", "value")
384+
.build(),
385+
)
386+
}
387+
val transactionTwo =
388+
createRequest("other").withResponseData().apply {
389+
requestDate = 100L
390+
setRequestHeaders(
391+
okhttp3.Headers.Builder()
392+
.add("X-Different-Header", "value")
393+
.build(),
394+
)
395+
}
396+
397+
insertTransaction(transactionOne)
398+
insertTransaction(transactionTwo)
399+
400+
testObject.getFilteredTuples(codeQuery = "%", searchQuery = "%X-Special-Header%").observeForever { result ->
401+
assertTuples(listOf(transactionOne), result)
402+
}
403+
}
404+
271405
private suspend fun insertTransaction(transaction: HttpTransaction) {
272406
transaction.id = testObject.insert(transaction)!!
273407
}

library/src/test/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModelTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ internal class MainViewModelTest {
108108
every {
109109
transactionRepository.getFilteredTransactionTuples(
110110
searchQuery,
111-
"",
111+
searchQuery,
112112
)
113113
} returns transactionLiveData
114114
every { TextUtils.isDigitsOnly(searchQuery) } returns true
@@ -117,7 +117,7 @@ internal class MainViewModelTest {
117117
viewModel.updateItemsFilter(searchQuery)
118118
transactionLiveData.value = expectedTuples
119119

120-
verify { transactionRepository.getFilteredTransactionTuples(searchQuery, "") }
120+
verify { transactionRepository.getFilteredTransactionTuples(searchQuery, searchQuery) }
121121
verify { transactionObserver.onChanged(expectedTuples) }
122122
}
123123

0 commit comments

Comments
 (0)