Mitigate notifications from old grades (#258)

Fixes #257
This commit is contained in:
Mikołaj Pich 2019-03-02 19:15:37 +01:00 committed by Rafał Borcz
parent f8ee5cb062
commit e910c7a48e
13 changed files with 227 additions and 15 deletions

View File

@ -119,6 +119,7 @@ dependencies {
testImplementation "org.mockito:mockito-inline:2.23.4" testImplementation "org.mockito:mockito-inline:2.23.4"
testImplementation 'org.threeten:threetenbp:1.3.8' testImplementation 'org.threeten:threetenbp:1.3.8'
androidTestImplementation "io.mockk:mockk-android:1.9"
androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.ext:junit:1.1.0'

View File

@ -0,0 +1,19 @@
package io.github.wulkanowy.data.repositories
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler
import io.reactivex.Observable
import io.reactivex.Single
class TestInternetObservingStrategy : InternetObservingStrategy {
override fun checkInternetConnectivity(host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Single<Boolean> {
return Single.just(true)
}
override fun observeInternetConnectivity(initialIntervalInMs: Int, intervalInMs: Int, host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Observable<Boolean> {
return Observable.just(true)
}
override fun getDefaultPingHost() = "localhost"
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.attendance
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -6,7 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.attendance.AttendanceLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.completedlessons
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -6,7 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.exam
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -6,7 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.exam.ExamLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -0,0 +1,34 @@
package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.api.toDate
import org.threeten.bp.LocalDate
import io.github.wulkanowy.api.grades.Grade as GradeRemote
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal
fun createGradeLocal(value: Int, weight: Int, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
return GradeLocal(
semesterId = semesterId,
studentId = 1,
modifier = .0,
teacher = "",
subject = "",
date = date,
color = "",
comment = "",
description = desc,
entry = "",
gradeSymbol = "",
value = value,
weight = "",
weightValue = weight
)
}
fun createGradeApi(value: Int, weight: Int, date: LocalDate, desc: String): GradeRemote {
return GradeRemote().apply {
this.value = value
this.weightValue = weight
this.date = date.toDate()
this.description = desc
}
}

View File

@ -0,0 +1,49 @@
package io.github.wulkanowy.data.repositories.grade
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class GradeLocalTest {
private lateinit var gradeLocal: GradeLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
gradeLocal.saveGrades(listOf(
createGradeLocal(5, 3, LocalDate.of(2018, 9, 10), "", 1),
createGradeLocal(4, 4, LocalDate.of(2019, 2, 27), "", 2),
createGradeLocal(3, 5, LocalDate.of(2019, 2, 28), "", 2)
))
val grades = gradeLocal
.getGrades(Semester(1, 2, "", 2, 3, true, 1, 1))
.blockingGet()
assertEquals(2, grades.size)
assertEquals(grades[0].date, LocalDate.of(2019, 2, 27))
assertEquals(grades[1].date, LocalDate.of(2019, 2, 28))
}
}

View File

@ -0,0 +1,115 @@
package io.github.wulkanowy.data.repositories.grade
import android.os.Build.VERSION_CODES.P
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.toDate
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.reactivex.Single
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.of
import org.threeten.bp.LocalDateTime
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import io.github.wulkanowy.api.grades.Grade as GradeApi
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class GradeRepositoryTest {
@SpyK
private var mockApi = Api()
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK
private lateinit var semesterMock: Semester
@MockK
private lateinit var studentMock: Student
private lateinit var gradeRemote: GradeRemote
private lateinit var gradeLocal: GradeLocal
private lateinit var testDb: AppDatabase
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao)
gradeRemote = GradeRemote(mockApi)
every { mockApi.diaryId } returns 1
every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0)
every { semesterMock.studentId } returns 1
every { semesterMock.semesterId } returns 1
every { semesterMock.diaryId } returns 1
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun markOlderThanRegisterDateAsRead() {
every { mockApi.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 4, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeApi(5, 4, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeApi(5, 4, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeApi(5, 4, of(2019, 2, 28), "Ocena jeszcze nowsza")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
assertTrue { grades[2].isRead }
assertTrue { grades[3].isRead }
}
@Test
fun mitigateOldGradesNotifications() {
gradeLocal.saveGrades(listOf(
createGradeLocal(5, 3, of(2019, 2, 25), "Jedna ocena"),
createGradeLocal(4, 4, of(2019, 2, 26), "Druga"),
createGradeLocal(3, 5, of(2019, 2, 27), "Trzecia")
))
every { mockApi.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 2, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeApi(4, 3, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeApi(3, 4, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeApi(2, 5, of(2019, 2, 28), "Ta jest już w ogóle nowa")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
assertTrue { grades[2].isRead }
assertTrue { grades[3].isRead }
}
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.luckynumber
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -6,7 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.recipient
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -7,7 +7,6 @@ import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.recipient.RecipientLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.student
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
@ -7,7 +7,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefHelper import io.github.wulkanowy.data.db.SharedPrefHelper
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.student.StudentLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.timetable
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -6,7 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.repositories.timetable.TimetableLocal
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -27,10 +27,11 @@ class GradeRepository @Inject constructor(
}.flatMap { newGrades -> }.flatMap { newGrades ->
local.getGrades(semester).toSingle(emptyList()) local.getGrades(semester).toSingle(emptyList())
.doOnSuccess { oldGrades -> .doOnSuccess { oldGrades ->
val notifyBreakDate = oldGrades.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate()
local.deleteGrades(oldGrades - newGrades) local.deleteGrades(oldGrades - newGrades)
local.saveGrades((newGrades - oldGrades) local.saveGrades((newGrades - oldGrades)
.onEach { .onEach {
if (student.registrationDate <= it.date.atStartOfDay()) { if (it.date >= notifyBreakDate) {
if (notify) it.isNotified = false if (notify) it.isNotified = false
it.isRead = false it.isRead = false
} }