Skip to content

Commit fe5c5ba

Browse files
authored
feat: [ANDROAPP-7605] Add granular sync use-case for teis (#4955)
1 parent 62b899b commit fe5c5ba

5 files changed

Lines changed: 187 additions & 0 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.dhis2.mobile.sync.data
2+
3+
import org.dhis2.mobile.sync.model.EnrollmentInfo
4+
import org.hisp.dhis.android.core.D2
5+
6+
internal class SyncTeiRepositoryImpl(
7+
private val d2: D2,
8+
) : SyncTeiRepository {
9+
override suspend fun getEnrollmentInfo(enrollmentUid: String): EnrollmentInfo {
10+
val enrollment =
11+
d2
12+
.enrollmentModule()
13+
.enrollments()
14+
.uid(enrollmentUid)
15+
.blockingGet() ?: throw IllegalStateException("Enrollment does not exist")
16+
17+
return EnrollmentInfo(
18+
uid = enrollmentUid,
19+
teiUid =
20+
enrollment.trackedEntityInstance() ?: throw IllegalStateException(
21+
"Missing tei uid for enrollment %s".format(
22+
enrollmentUid,
23+
),
24+
),
25+
programUid =
26+
enrollment.program() ?: throw IllegalStateException(
27+
"Missing program uid for enrollment %s".format(
28+
enrollmentUid,
29+
),
30+
),
31+
)
32+
}
33+
34+
override suspend fun uploadTei(enrollmentInfo: EnrollmentInfo) {
35+
d2
36+
.trackedEntityModule()
37+
.trackedEntityInstances()
38+
.byUid()
39+
.eq(enrollmentInfo.teiUid)
40+
.byProgramUids(listOf(enrollmentInfo.programUid))
41+
.blockingUpload()
42+
}
43+
44+
override suspend fun downloadTei(enrollmentInfo: EnrollmentInfo) {
45+
d2
46+
.trackedEntityModule()
47+
.trackedEntityInstanceDownloader()
48+
.byUid()
49+
.eq(enrollmentInfo.teiUid)
50+
.byProgramUid(enrollmentInfo.programUid)
51+
.blockingDownload()
52+
}
53+
54+
override suspend fun downloadFileResources(enrollmentInfo: EnrollmentInfo) {
55+
d2
56+
.fileResourceModule()
57+
.fileResourceDownloader()
58+
.byTrackedEntityUid()
59+
.eq(enrollmentInfo.teiUid)
60+
.byProgramUid()
61+
.eq(enrollmentInfo.programUid)
62+
.blockingDownload()
63+
}
64+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.dhis2.mobile.sync.data
2+
3+
import org.dhis2.mobile.sync.model.EnrollmentInfo
4+
5+
internal interface SyncTeiRepository {
6+
suspend fun getEnrollmentInfo(enrollmentUid: String): EnrollmentInfo
7+
8+
suspend fun uploadTei(enrollmentInfo: EnrollmentInfo)
9+
10+
suspend fun downloadTei(enrollmentInfo: EnrollmentInfo)
11+
12+
suspend fun downloadFileResources(enrollmentInfo: EnrollmentInfo)
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.dhis2.mobile.sync.domain
2+
3+
import org.dhis2.mobile.commons.domain.UseCase
4+
import org.dhis2.mobile.sync.data.SyncTeiRepository
5+
6+
internal typealias EnrollmentUid = String
7+
8+
internal class SyncTei(
9+
private val syncTeiRepository: SyncTeiRepository,
10+
) : UseCase<String, Unit> {
11+
override suspend fun invoke(input: EnrollmentUid): Result<Unit> =
12+
try {
13+
val enrollmentInfo = syncTeiRepository.getEnrollmentInfo(input)
14+
syncTeiRepository.uploadTei(enrollmentInfo)
15+
syncTeiRepository.downloadTei(enrollmentInfo)
16+
syncTeiRepository.downloadFileResources(enrollmentInfo)
17+
Result.success(Unit)
18+
} catch (e: Exception) {
19+
Result.failure(e)
20+
}
21+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.dhis2.mobile.sync.model
2+
3+
internal data class EnrollmentInfo(
4+
val uid: String,
5+
val teiUid: String,
6+
val programUid: String,
7+
)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.dhis2.mobile.sync.domain
2+
3+
import kotlinx.coroutines.runBlocking
4+
import org.dhis2.mobile.sync.data.SyncTeiRepository
5+
import org.dhis2.mobile.sync.model.EnrollmentInfo
6+
import org.junit.Test
7+
import org.mockito.kotlin.mock
8+
import org.mockito.kotlin.verify
9+
import org.mockito.kotlin.whenever
10+
import kotlin.test.assertTrue
11+
12+
class SyncTeiTest {
13+
private val repository: SyncTeiRepository = mock()
14+
private val useCase = SyncTei(repository)
15+
16+
private val enrollmentUid = "enrollmentUid"
17+
private val enrollmentInfo =
18+
EnrollmentInfo(
19+
uid = enrollmentUid,
20+
teiUid = "teiUid",
21+
programUid = "programUid",
22+
)
23+
24+
@Test
25+
fun `should return success and call all repository methods in order`() =
26+
runBlocking {
27+
whenever(repository.getEnrollmentInfo(enrollmentUid)).thenReturn(enrollmentInfo)
28+
29+
val result = useCase(enrollmentUid)
30+
31+
assertTrue(result.isSuccess)
32+
verify(repository).getEnrollmentInfo(enrollmentUid)
33+
verify(repository).uploadTei(enrollmentInfo)
34+
verify(repository).downloadTei(enrollmentInfo)
35+
verify(repository).downloadFileResources(enrollmentInfo)
36+
}
37+
38+
@Test
39+
fun `should return failure when getEnrollmentInfo throws`() =
40+
runBlocking {
41+
whenever(repository.getEnrollmentInfo(enrollmentUid))
42+
.thenThrow(RuntimeException("enrollment error"))
43+
44+
val result = useCase(enrollmentUid)
45+
46+
assertTrue(result.isFailure)
47+
}
48+
49+
@Test
50+
fun `should return failure when uploadTei throws`() =
51+
runBlocking {
52+
whenever(repository.getEnrollmentInfo(enrollmentUid)).thenReturn(enrollmentInfo)
53+
whenever(repository.uploadTei(enrollmentInfo)).thenThrow(RuntimeException("upload error"))
54+
55+
val result = useCase(enrollmentUid)
56+
57+
assertTrue(result.isFailure)
58+
}
59+
60+
@Test
61+
fun `should return failure when downloadTei throws`() =
62+
runBlocking {
63+
whenever(repository.getEnrollmentInfo(enrollmentUid)).thenReturn(enrollmentInfo)
64+
whenever(repository.downloadTei(enrollmentInfo)).thenThrow(RuntimeException("download error"))
65+
66+
val result = useCase(enrollmentUid)
67+
68+
assertTrue(result.isFailure)
69+
}
70+
71+
@Test
72+
fun `should return failure when downloadFileResources throws`() =
73+
runBlocking {
74+
whenever(repository.getEnrollmentInfo(enrollmentUid)).thenReturn(enrollmentInfo)
75+
whenever(repository.downloadFileResources(enrollmentInfo))
76+
.thenThrow(RuntimeException("file resources error"))
77+
78+
val result = useCase(enrollmentUid)
79+
80+
assertTrue(result.isFailure)
81+
}
82+
}

0 commit comments

Comments
 (0)