diff --git a/README.md b/README.md index a2a72dc..221836e 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,8 @@ Regular `connectedXXXXAndroidTest` target invocation is enough for verifications ./gradlew :app:connectedDebugAndroidTest ``` +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. + In case of any failures due logs verifications, regular junit reports include failed tests and comparation failure reason. Additionally, an specific Loggerazzi report is generated at --> `build/reports/androidTests/connected/debug/loggerazzi/failures.html` diff --git a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt index 9a988d8..bf2619b 100644 --- a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt +++ b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt @@ -53,25 +53,56 @@ open class GenericLoggerazziRule( val testName = "${description?.className}_${description?.methodName}" val fileName = "${testName}.${System.nanoTime()}" - val recordedLogs = recorder.getRecordedLogs() - val log = recordedLogs.joinToString("\n") { stringMapper.fromLog(it) } - val testFile = File(recordedDir, fileName) - testFile.createNewFile() - testFile.writeText(log) - + val recordedLogs: List if (InstrumentationRegistry.getArguments().getString("record") != "true" && !isTestIgnored) { val goldenFile = InstrumentationRegistry.getInstrumentation().context.assets.open( "loggerazzi-golden-files/${testName}.txt" ) val goldenStringLogs = String(goldenFile.readBytes()).takeIf { it.isNotEmpty() }?.split("\n") ?: emptyList() - val result = comparator.compare(recordedLogs, goldenStringLogs.map { stringMapper.toLog(it) }) - if (result != null) { + val comparison = compare(goldenStringLogs) + if (!comparison.success) { val compareFile = File(failuresDir, fileName) compareFile.createNewFile() - compareFile.writeText(result) - throw AssertionError("Logs do not match:\n$result") + compareFile.writeText(comparison.failure!!) + throw AssertionError("Logs do not match:\n${comparison.failure}") } + recordedLogs = comparison.recordedLogs + } else { + recordedLogs = recorder.getRecordedLogs() } + + val log = recordedLogs.joinToString("\n") { stringMapper.fromLog(it) } + val testFile = File(recordedDir, fileName) + testFile.createNewFile() + testFile.writeText(log) + } + + private fun compare(goldenStringLogs: List): Comparison { + val goldenLogs = goldenStringLogs.map { stringMapper.toLog(it) } + val startTime = System.currentTimeMillis() + var comparison: Comparison + do { + val recordedLogs = recorder.getRecordedLogs() + val comparisonFailure = comparator.compare(recordedLogs, goldenLogs) + comparison = Comparison(comparisonFailure, recordedLogs) + if (!comparison.success) { + Thread.sleep(RESULT_POLLING_INTERVAL_MS) + } + } while (!comparison.success && System.currentTimeMillis() - startTime < RESULT_TIMEOUT_MS) + return comparison + } + + private data class Comparison( + val failure: String?, + val recordedLogs: List, + ) { + val success: Boolean + get() = failure == null + } + + private companion object { + const val RESULT_POLLING_INTERVAL_MS = 500L + const val RESULT_TIMEOUT_MS = 5000L } } \ No newline at end of file