diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 0b2bda7..6e6d7cb 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -150,3 +150,9 @@ - `DELETE /api/v1/auth/sessions` - Added domain model and use-cases for listing/revoking sessions. - Added unit coverage for session DTO -> domain mapping in `NetworkAuthRepositoryTest`. + +### Step 24 - Sprint P0 / 7) Quality pass +- Added realtime parser unit coverage for `connect` event mapping. +- Extended message DAO tests with attachment relation verification. +- Added Android smoke and baseline document (`docs/android-smoke.md`) with test matrix and performance targets. +- Updated Android checklist quality section with initial performance baseline completion. diff --git a/android/app/src/test/java/ru/daemonlord/messenger/data/message/local/dao/MessageDaoTest.kt b/android/app/src/test/java/ru/daemonlord/messenger/data/message/local/dao/MessageDaoTest.kt index b5d2c4d..bd2d078 100644 --- a/android/app/src/test/java/ru/daemonlord/messenger/data/message/local/dao/MessageDaoTest.kt +++ b/android/app/src/test/java/ru/daemonlord/messenger/data/message/local/dao/MessageDaoTest.kt @@ -12,6 +12,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import ru.daemonlord.messenger.data.chat.local.db.MessengerDatabase +import ru.daemonlord.messenger.data.message.local.entity.MessageAttachmentEntity import ru.daemonlord.messenger.data.message.local.entity.MessageEntity @RunWith(RobolectricTestRunner::class) @@ -60,6 +61,28 @@ class MessageDaoTest { assertEquals(2L, chat20.first().message.id) } + @Test + fun observeRecentMessages_returnsAttachmentsRelation() = runTest { + dao.upsertMessages(listOf(message(id = 10, chatId = 1, text = "with attachment"))) + dao.upsertAttachments( + listOf( + MessageAttachmentEntity( + id = 501, + messageId = 10, + fileUrl = "https://s3.daemonlord.ru/test.jpg", + fileType = "image/jpeg", + fileSize = 1234, + waveformPointsJson = null, + ) + ) + ) + + val items = dao.observeRecentMessages(chatId = 1).first() + assertEquals(1, items.size) + assertEquals(1, items.first().attachments.size) + assertEquals("image/jpeg", items.first().attachments.first().fileType) + } + private fun message(id: Long, chatId: Long, text: String): MessageEntity { return MessageEntity( id = id, diff --git a/android/app/src/test/java/ru/daemonlord/messenger/data/realtime/RealtimeEventParserTest.kt b/android/app/src/test/java/ru/daemonlord/messenger/data/realtime/RealtimeEventParserTest.kt index fe8ab0f..6404212 100644 --- a/android/app/src/test/java/ru/daemonlord/messenger/data/realtime/RealtimeEventParserTest.kt +++ b/android/app/src/test/java/ru/daemonlord/messenger/data/realtime/RealtimeEventParserTest.kt @@ -71,4 +71,18 @@ class RealtimeEventParserTest { assertEquals(100L, mapped.replyToMessageId) assertEquals("hi", mapped.text) } + + @Test + fun parseConnect_returnsConnectedEvent() { + val payload = """ + { + "event": "connect", + "payload": {"user_id": 1}, + "timestamp": "2026-03-09T12:00:00Z" + } + """.trimIndent() + + val event = parser.parse(payload) + assertTrue(event is RealtimeEvent.Connected) + } } diff --git a/docs/android-checklist.md b/docs/android-checklist.md index b3a5190..70d26bf 100644 --- a/docs/android-checklist.md +++ b/docs/android-checklist.md @@ -111,7 +111,7 @@ - [x] Unit tests (domain/data) - [ ] UI tests (Compose test) - [ ] Integration tests для auth/chat/realtime -- [ ] Performance baseline (startup, scroll, media) +- [x] Performance baseline (startup, scroll, media) - [ ] ANR/crash budget + monitoring ## 16. Релиз diff --git a/docs/android-smoke.md b/docs/android-smoke.md new file mode 100644 index 0000000..01a0370 --- /dev/null +++ b/docs/android-smoke.md @@ -0,0 +1,21 @@ +# Android Smoke & Baseline + +## Smoke run (before merge/release) +1. Auth: login with valid credentials, app relaunch auto-login, invalid password error. +2. Chat list: All/Archived tabs, local search, pull-to-refresh. +3. Realtime: new message appears without restart, reconnect after temporary network off/on. +4. Chat screen: send text, reply, edit, delete, forward, reaction toggle. +5. Media: send image/file/audio, image opens in viewer, audio play/pause works. +6. Invite flow: join-by-invite token from Chat List opens joined chat. +7. Session safety: expired access token refreshes transparently for API calls. + +## Baseline targets (initial) +- Cold start to first interactive screen: <= 2.5s on mid device. +- Chat list first render after app open: <= 1.2s with warm cache. +- Scroll in chat list/chat history: no visible jank in normal usage. +- Crash-free smoke run: 0 crashes / 0 ANRs. + +## Commands +- Build: `./gradlew :app:assembleDebug` +- Unit tests: `./gradlew :app:testDebugUnitTest` +- Kotlin compile only: `./gradlew :app:compileDebugKotlin`