From 40e4e663f89f5fdae65d8e1bf2b5f25141745441 Mon Sep 17 00:00:00 2001 From: David Pastor Herranz Date: Mon, 15 Sep 2025 18:28:04 +0200 Subject: [PATCH 1/4] ANDROID-16807 Add waitForCondition at loggerazzi logs comparation --- .../telefonica/loggerazzi/LoggerazziRule.kt | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt index 9a988d8..2ebf760 100644 --- a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt +++ b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt @@ -53,25 +53,55 @@ 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 comparationResult = compare(goldenStringLogs) + if (!comparationResult.success) { val compareFile = File(failuresDir, fileName) compareFile.createNewFile() - compareFile.writeText(result) - throw AssertionError("Logs do not match:\n$result") + compareFile.writeText(comparationResult.result!!) + throw AssertionError("Logs do not match:\n${comparationResult.result}") } + recordedLogs = comparationResult.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): ComparationResult { + val startTime = System.currentTimeMillis() + var comparationResult: ComparationResult + do { + val recordedLogs = recorder.getRecordedLogs() + val result = comparator.compare(recordedLogs, goldenStringLogs.map { stringMapper.toLog(it) }) + comparationResult = ComparationResult(result, recordedLogs) + if (!comparationResult.success) { + Thread.sleep(RESULT_POLLING_INTERVAL_MS) + } + } while (!comparationResult.success && System.currentTimeMillis() - startTime < RESULT_TIMEOUT_MS) + return comparationResult + } + + private data class ComparationResult( + val result: String?, + val recordedLogs: List, + ) { + val success: Boolean + get() = result == null + } + + private companion object { + const val RESULT_POLLING_INTERVAL_MS = 500L + const val RESULT_TIMEOUT_MS = 5000L } } \ No newline at end of file From c53551c9201e9e24f9a3dab16210f92639e4882f Mon Sep 17 00:00:00 2001 From: David Pastor Herranz Date: Mon, 15 Sep 2025 18:40:06 +0200 Subject: [PATCH 2/4] ANDROID-16807 Renaming --- .../telefonica/loggerazzi/LoggerazziRule.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt index 2ebf760..04f147f 100644 --- a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt +++ b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt @@ -60,14 +60,14 @@ open class GenericLoggerazziRule( "loggerazzi-golden-files/${testName}.txt" ) val goldenStringLogs = String(goldenFile.readBytes()).takeIf { it.isNotEmpty() }?.split("\n") ?: emptyList() - val comparationResult = compare(goldenStringLogs) - if (!comparationResult.success) { + val comparison = compare(goldenStringLogs) + if (!comparison.success) { val compareFile = File(failuresDir, fileName) compareFile.createNewFile() - compareFile.writeText(comparationResult.result!!) - throw AssertionError("Logs do not match:\n${comparationResult.result}") + compareFile.writeText(comparison.result!!) + throw AssertionError("Logs do not match:\n${comparison.result}") } - recordedLogs = comparationResult.recordedLogs + recordedLogs = comparison.recordedLogs } else { recordedLogs = recorder.getRecordedLogs() } @@ -78,21 +78,21 @@ open class GenericLoggerazziRule( testFile.writeText(log) } - private fun compare(goldenStringLogs: List): ComparationResult { + private fun compare(goldenStringLogs: List): Comparison { val startTime = System.currentTimeMillis() - var comparationResult: ComparationResult + var comparison: Comparison do { val recordedLogs = recorder.getRecordedLogs() val result = comparator.compare(recordedLogs, goldenStringLogs.map { stringMapper.toLog(it) }) - comparationResult = ComparationResult(result, recordedLogs) - if (!comparationResult.success) { + comparison = Comparison(result, recordedLogs) + if (!comparison.success) { Thread.sleep(RESULT_POLLING_INTERVAL_MS) } - } while (!comparationResult.success && System.currentTimeMillis() - startTime < RESULT_TIMEOUT_MS) - return comparationResult + } while (!comparison.success && System.currentTimeMillis() - startTime < RESULT_TIMEOUT_MS) + return comparison } - private data class ComparationResult( + private data class Comparison( val result: String?, val recordedLogs: List, ) { From d9e584e80c9a5bb92f56fd5653849745e8cf8a62 Mon Sep 17 00:00:00 2001 From: David Pastor Herranz Date: Wed, 17 Sep 2025 09:01:22 +0200 Subject: [PATCH 3/4] ANDROID-16807 Add explanation on readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) 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` From 9ca8ff342959aecd5e0a1a9316e818275b2ef62f Mon Sep 17 00:00:00 2001 From: David Pastor Herranz Date: Wed, 17 Sep 2025 10:58:54 +0200 Subject: [PATCH 4/4] ANDROID-16807 Improve semantics --- .../com/telefonica/loggerazzi/LoggerazziRule.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt index 04f147f..bf2619b 100644 --- a/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt +++ b/loggerazzi/src/main/java/com/telefonica/loggerazzi/LoggerazziRule.kt @@ -64,8 +64,8 @@ open class GenericLoggerazziRule( if (!comparison.success) { val compareFile = File(failuresDir, fileName) compareFile.createNewFile() - compareFile.writeText(comparison.result!!) - throw AssertionError("Logs do not match:\n${comparison.result}") + compareFile.writeText(comparison.failure!!) + throw AssertionError("Logs do not match:\n${comparison.failure}") } recordedLogs = comparison.recordedLogs } else { @@ -79,12 +79,13 @@ open class GenericLoggerazziRule( } 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 result = comparator.compare(recordedLogs, goldenStringLogs.map { stringMapper.toLog(it) }) - comparison = Comparison(result, recordedLogs) + val comparisonFailure = comparator.compare(recordedLogs, goldenLogs) + comparison = Comparison(comparisonFailure, recordedLogs) if (!comparison.success) { Thread.sleep(RESULT_POLLING_INTERVAL_MS) } @@ -93,11 +94,11 @@ open class GenericLoggerazziRule( } private data class Comparison( - val result: String?, + val failure: String?, val recordedLogs: List, ) { val success: Boolean - get() = result == null + get() = failure == null } private companion object {