android: add media repository tests and checklist updates
Some checks failed
CI / test (push) Failing after 2m3s
Some checks failed
CI / test (push) Failing after 2m3s
This commit is contained in:
@@ -104,3 +104,7 @@
|
||||
- Extended `MessageRepository` with media send flow (`sendMediaMessage`) and optimistic local update behavior.
|
||||
- Wired media API/repository through Hilt modules.
|
||||
- Integrated file picking and media sending into Android `ChatScreen`/`ChatViewModel` with upload state handling.
|
||||
|
||||
### Step 17 - Sprint B / media tests
|
||||
- Added `NetworkMediaRepositoryTest` for successful upload+attach flow.
|
||||
- Added error-path coverage for failed presigned upload handling.
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package ru.daemonlord.messenger.data.media.repository
|
||||
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import retrofit2.Retrofit
|
||||
import ru.daemonlord.messenger.data.media.api.MediaApiService
|
||||
import ru.daemonlord.messenger.domain.common.AppResult
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class NetworkMediaRepositoryTest {
|
||||
|
||||
private lateinit var apiServer: MockWebServer
|
||||
private lateinit var uploadServer: MockWebServer
|
||||
private lateinit var mediaApiService: MediaApiService
|
||||
private val dispatcher = StandardTestDispatcher()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
apiServer = MockWebServer().also { it.start() }
|
||||
uploadServer = MockWebServer().also { it.start() }
|
||||
mediaApiService = Retrofit.Builder()
|
||||
.baseUrl(apiServer.url("/"))
|
||||
.addConverterFactory(
|
||||
Json { ignoreUnknownKeys = true }.asConverterFactory("application/json".toMediaType())
|
||||
)
|
||||
.build()
|
||||
.create(MediaApiService::class.java)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
apiServer.shutdown()
|
||||
uploadServer.shutdown()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun uploadAndAttach_success() = runTest(dispatcher) {
|
||||
apiServer.enqueue(
|
||||
MockResponse().setResponseCode(200).setBody(
|
||||
"""
|
||||
{
|
||||
"upload_url": "${uploadServer.url("/upload")}",
|
||||
"file_url": "https://s3.daemonlord.ru/uploads/image.png",
|
||||
"object_key": "uploads/image.png",
|
||||
"expires_in": 900,
|
||||
"required_headers": { "Content-Type": "image/png" }
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
uploadServer.enqueue(MockResponse().setResponseCode(200))
|
||||
apiServer.enqueue(MockResponse().setResponseCode(200).setBody("{}"))
|
||||
|
||||
val repository = NetworkMediaRepository(
|
||||
mediaApiService = mediaApiService,
|
||||
uploadClient = OkHttpClient(),
|
||||
ioDispatcher = dispatcher,
|
||||
)
|
||||
|
||||
val result = repository.uploadAndAttach(
|
||||
messageId = 10,
|
||||
fileName = "image.png",
|
||||
mimeType = "image/png",
|
||||
bytes = byteArrayOf(1, 2, 3),
|
||||
)
|
||||
|
||||
assertTrue(result is AppResult.Success)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun uploadAndAttach_uploadFails_returnsError() = runTest(dispatcher) {
|
||||
apiServer.enqueue(
|
||||
MockResponse().setResponseCode(200).setBody(
|
||||
"""
|
||||
{
|
||||
"upload_url": "${uploadServer.url("/upload")}",
|
||||
"file_url": "https://s3.daemonlord.ru/uploads/image.png",
|
||||
"object_key": "uploads/image.png",
|
||||
"expires_in": 900,
|
||||
"required_headers": { "Content-Type": "image/png" }
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
uploadServer.enqueue(MockResponse().setResponseCode(500))
|
||||
|
||||
val repository = NetworkMediaRepository(
|
||||
mediaApiService = mediaApiService,
|
||||
uploadClient = OkHttpClient(),
|
||||
ioDispatcher = dispatcher,
|
||||
)
|
||||
|
||||
val result = repository.uploadAndAttach(
|
||||
messageId = 10,
|
||||
fileName = "image.png",
|
||||
mimeType = "image/png",
|
||||
bytes = byteArrayOf(1, 2, 3),
|
||||
)
|
||||
|
||||
assertTrue(result is AppResult.Error)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import ru.daemonlord.messenger.data.message.api.MessageApiService
|
||||
import ru.daemonlord.messenger.data.message.dto.MessageCreateRequestDto
|
||||
import ru.daemonlord.messenger.data.message.dto.MessageReadDto
|
||||
import ru.daemonlord.messenger.data.message.dto.MessageUpdateRequestDto
|
||||
import ru.daemonlord.messenger.domain.common.AppResult
|
||||
import ru.daemonlord.messenger.domain.media.repository.MediaRepository
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@@ -92,6 +94,7 @@ class NetworkMessageRepositoryTest {
|
||||
messageApiService = fakeApi,
|
||||
messageDao = db.messageDao(),
|
||||
chatDao = db.chatDao(),
|
||||
mediaRepository = FakeMediaRepository(),
|
||||
ioDispatcher = dispatcher,
|
||||
)
|
||||
}
|
||||
@@ -121,4 +124,15 @@ class NetworkMessageRepositoryTest {
|
||||
|
||||
override suspend fun deleteMessage(messageId: Long, forAll: Boolean) = Unit
|
||||
}
|
||||
|
||||
private class FakeMediaRepository : MediaRepository {
|
||||
override suspend fun uploadAndAttach(
|
||||
messageId: Long,
|
||||
fileName: String,
|
||||
mimeType: String,
|
||||
bytes: ByteArray,
|
||||
): AppResult<Unit> {
|
||||
return AppResult.Success(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
- [ ] Delivery/read states
|
||||
|
||||
## 8. Медиа и вложения
|
||||
- [ ] Upload image/video/file/audio
|
||||
- [x] Upload image/video/file/audio
|
||||
- [ ] Галерея в сообщении (multi media)
|
||||
- [ ] Media viewer (zoom/swipe/download)
|
||||
- [ ] Единое контекстное меню для медиа
|
||||
|
||||
Reference in New Issue
Block a user