Skip to content

Commit 4db357f

Browse files
ANDROID-17023 Move Loggerazzi fixes to Snaptesting library (#14)
1 parent 3aea8a6 commit 4db357f

File tree

6 files changed

+86
-21
lines changed

6 files changed

+86
-21
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Regular `connectedXXXXAndroidTest` target invocation is enough for verifications
9494
```bash
9595
./gradlew :app:connectedDebugAndroidTest
9696
```
97+
At the end of each test, Loggerazzi compares the recorded logs with the corresponding baseline logs (previously generated in recording mode) allowing up to 5 seconds for the logs to match the expected output.
9798

9899
In case of any failures due to screenshots or log verifications, regular JUnit reports include failed tests and the comparison failure reason.
99100

android-snaptesting/src/main/java/com/telefonica/androidsnaptesting/logs/LogComparator.kt

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public interface LogComparator<LogType> {
99
public class DefaultLogComparator<LogType> : LogComparator<LogType> {
1010
override fun compare(recorded: List<LogType>, golden: List<LogType>): String? {
1111
if (recorded.size != golden.size) {
12-
return "Different number of lines: recorded=${recorded.size}, golden=${golden.size}"
12+
return "Different number of lines: golden=${golden.size}, recorded=${recorded.size}"
1313
}
1414

1515
val compareResult = StringBuilder()
@@ -21,4 +21,29 @@ public class DefaultLogComparator<LogType> : LogComparator<LogType> {
2121

2222
return compareResult.toString().takeIf { it.isNotEmpty() }
2323
}
24-
}
24+
}
25+
26+
@Suppress("unused")
27+
public class AnyOrderLogComparator<LogType> : LogComparator<LogType> {
28+
override fun compare(recorded: List<LogType>, golden: List<LogType>): String? {
29+
val goldenSet = golden.toSet()
30+
val recordedSet = recorded.toSet()
31+
32+
val missing = goldenSet - recordedSet
33+
val extra = recordedSet - goldenSet
34+
35+
if (missing.isEmpty() && extra.isEmpty()) {
36+
return null
37+
}
38+
39+
val result = StringBuilder()
40+
if (missing.isNotEmpty()) {
41+
result.appendLine("Missing entries (in golden but not in recorded): ${missing.toList()}")
42+
}
43+
if (extra.isNotEmpty()) {
44+
result.appendLine("Extra entries (in recorded but not in golden): ${extra.toList()}")
45+
}
46+
47+
return result.toString().trimEnd()
48+
}
49+
}

android-snaptesting/src/main/java/com/telefonica/androidsnaptesting/logs/LogsRule.kt

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,54 @@ public open class GenericLogsRule<LogType>(
4747
val testName = "${description?.className}_${description?.methodName}"
4848
val fileName = "${testName}.txt.${System.nanoTime()}"
4949

50-
val recordedLogs = recorder.getRecordedLogs()
51-
val log = recordedLogs.joinToString("\n") { stringMapper.fromLog(it) }
52-
val testFile = File(directories.recordedDir, fileName)
53-
testFile.createNewFile()
54-
testFile.writeText(log)
50+
val recordedLogs: List<LogType>
5551

5652
if (InstrumentationRegistry.getArguments().getString("record") != "true" && !isTestIgnored) {
5753
val goldenFile = directories.context.assets.open("${directories.goldenFilesDir}/${testName}.txt")
5854
val goldenStringLogs = String(goldenFile.readBytes()).takeIf { it.isNotEmpty() }?.split("\n") ?: emptyList()
59-
val result = comparator.compare(recordedLogs, goldenStringLogs.map { stringMapper.toLog(it) })
60-
if (result != null) {
55+
val comparison = compare(goldenStringLogs)
56+
if (!comparison.success) {
6157
val compareFile = File(directories.failuresDir, fileName)
6258
compareFile.createNewFile()
63-
compareFile.writeText(result)
64-
throw AssertionError("Logs do not match:\n$result")
59+
compareFile.writeText(comparison.failure!!)
60+
throw AssertionError("Logs do not match:\n${comparison.failure}")
6561
}
62+
recordedLogs = comparison.recordedLogs
63+
} else {
64+
recordedLogs = recorder.getRecordedLogs()
6665
}
66+
67+
val log = recordedLogs.joinToString("\n") { stringMapper.fromLog(it) }
68+
val testFile = File(directories.recordedDir, fileName)
69+
testFile.createNewFile()
70+
testFile.writeText(log)
71+
}
72+
73+
private fun compare(goldenStringLogs: List<String>): Comparison<LogType> {
74+
val goldenLogs = goldenStringLogs.map { stringMapper.toLog(it) }
75+
val startTime = System.currentTimeMillis()
76+
var comparison: Comparison<LogType>
77+
do {
78+
val recordedLogs = recorder.getRecordedLogs()
79+
val comparisonFailure = comparator.compare(recordedLogs, goldenLogs)
80+
comparison = Comparison(comparisonFailure, recordedLogs)
81+
if (!comparison.success) {
82+
Thread.sleep(RESULT_POLLING_INTERVAL_MS)
83+
}
84+
} while (!comparison.success && System.currentTimeMillis() - startTime < RESULT_TIMEOUT_MS)
85+
return comparison
86+
}
87+
88+
private data class Comparison<LogType>(
89+
val failure: String?,
90+
val recordedLogs: List<LogType>,
91+
) {
92+
val success: Boolean
93+
get() = failure == null
94+
}
95+
96+
private companion object {
97+
const val RESULT_POLLING_INTERVAL_MS = 500L
98+
const val RESULT_TIMEOUT_MS = 5000L
6799
}
68100
}

app/src/main/java/com/telefonica/androidsnaptesting/MainActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package com.telefonica.androidsnaptesting
22

33
import androidx.appcompat.app.AppCompatActivity
44
import android.os.Bundle
5+
import androidx.activity.enableEdgeToEdge
56

67
class MainActivity : AppCompatActivity() {
78
override fun onCreate(savedInstanceState: Bundle?) {
89
super.onCreate(savedInstanceState)
10+
enableEdgeToEdge()
911
setContentView(R.layout.activity_main)
1012
}
1113
}

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
agp = "8.10.0"
33
constraintlayout = "2.2.1"
44
min-sdk = "23"
5-
target-sdk = "35"
6-
compile-sdk = "35"
5+
target-sdk = "36"
6+
compile-sdk = "36"
77
material = "1.12.0"
88
kotlin = "2.1.21"
99
appcompat = "1.7.0"

include-build/gradle-plugin/src/main/java/com/telefonica/androidsnaptesting/AndroidSnaptestingPlugin.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,12 @@ class AndroidSnaptestingPlugin @Inject constructor(
5555
val recordedFolderFile = reportsFolder.dir("recorded").asFile.apply {
5656
mkdirs()
5757
deviceFileManager.pullRecordedSnapshots(absolutePath)
58-
processAndFilterResults()
5958
}
6059
val failuresFolderFile = reportsFolder.dir("failures").asFile.apply {
6160
mkdirs()
6261
deviceFileManager.pullFailuresSnapshots(absolutePath)
63-
processAndFilterResults()
6462
}
63+
filterRecordedAndFailureResults(recordedFolderFile, failuresFolderFile)
6564
val goldenForFailuresReportFolderFile = reportsFolder.dir("golden").asFile.apply {
6665
mkdirs()
6766
}
@@ -133,22 +132,28 @@ class AndroidSnaptestingPlugin @Inject constructor(
133132
return replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
134133
}
135134

136-
private fun File.processAndFilterResults() {
137-
listFiles()
135+
private fun filterRecordedAndFailureResults(recordedDir: File, failuresDir: File) {
136+
recordedDir.listFiles()
138137
?.groupBy {
139138
it.name.substringBeforeLast(".")
140139
}
141140
?.forEach { (key, filesGroup) ->
142-
val lastFile = filesGroup.maxByOrNull {
141+
val lastRecordedFile = filesGroup.maxByOrNull {
143142
it.name.substringAfterLast(".").toLong()
144143
}
145144
filesGroup.forEach { file ->
146-
if (file != lastFile) {
145+
if (file != lastRecordedFile) {
147146
file.delete()
147+
File(failuresDir, file.name).takeIf { it.exists() }?.delete()
148148
}
149149
}
150-
151-
lastFile?.renameTo(File(this, key))
150+
if (lastRecordedFile != null) {
151+
lastRecordedFile
152+
.renameTo(File(recordedDir, "$key.txt"))
153+
File(failuresDir, lastRecordedFile.name)
154+
.takeIf { it.exists() }
155+
?.renameTo(File(failuresDir, "$key.txt"))
156+
}
152157
}
153158
}
154159
}

0 commit comments

Comments
 (0)