Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ class RealPirDashboardMaintenanceScanDataProvider @Inject constructor(
}

val mirrorValidScanJobs = validScansJobs.getMirrorSites()
return (validScansJobs + mirrorValidScanJobs).sortedBy { it.dateInMillis }
return (validScansJobs + mirrorValidScanJobs)
.sortedBy { it.dateInMillis }
.distinctBy { it.broker.name }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deduplication keeps oldest scan instead of most recent

The getBrokerMatches function is shared between getLastScanDetails() and getNextScanDetails(). By applying .sortedBy { it.dateInMillis } followed by .distinctBy { it.broker.name }, the code keeps the earliest (oldest) entry for each broker. This is correct for getNextScanDetails() (shows when broker will next be scanned), but for getLastScanDetails(), it keeps the oldest scan instead of the most recent one. When multiple profile queries exist for the same broker with different scan dates, users would see an older scan date rather than when the broker was actually last scanned.

Fix in Cursor Fix in Web

}

private suspend fun List<DashboardBrokerMatch>.getMirrorSites(): List<DashboardBrokerMatch> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,39 @@ class RealPirDashboardMaintenanceScanDataProviderTest {
assertEquals(currentTime - TimeUnit.DAYS.toMillis(5), broker2Match.dateInMillis)
}

@Test
fun whenScanJobsExistForSameBrokerButDifferentProfileQueriesThenGetLastScanDetailsReturnsOneBrokerMatch() =
runTest {
// Given - same broker with two different profile queries (userProfileId)
val activeBrokers = listOf(createBroker("broker1"))
val scanJobs = listOf(
createScanJobRecord(
"broker1",
userProfileId = 1L,
ScanJobStatus.MATCHES_FOUND,
currentTime - TimeUnit.DAYS.toMillis(2),
),
createScanJobRecord(
"broker1",
userProfileId = 2L,
ScanJobStatus.MATCHES_FOUND,
currentTime - TimeUnit.DAYS.toMillis(3),
),
)

whenever(mockPirRepository.getAllActiveBrokerObjects()).thenReturn(activeBrokers)
whenever(mockPirRepository.getAllBrokerOptOutUrls()).thenReturn(emptyMap())
whenever(mockPirSchedulingRepository.getAllValidScanJobRecords()).thenReturn(scanJobs)
whenever(mockPirRepository.getAllMirrorSites()).thenReturn(emptyList())

// When
val result = testee.getLastScanDetails()

// Then - Returns only ONE broker match per broker, regardless of how many profile queries exist
assertEquals(1, result.brokerMatches.size)
assertEquals("broker1", result.brokerMatches[0].broker.name)
}

@Test
fun whenNoScheduledScanJobsExistThenGetNextScanDetailsReturnsEmptyDetails() = runTest {
// Given
Expand Down Expand Up @@ -660,6 +693,65 @@ class RealPirDashboardMaintenanceScanDataProviderTest {
assertEquals(expectedNextScan, result.dateInMillis)
}

@Test
fun whenOptOutsExistForSameBrokerButDifferentProfileQueriesThenGetNextScanDetailsReturnsOneBrokerMatch() =
runTest {
// Given - same broker with two different profile queries (userProfileId)
val activeBrokers = listOf(createBroker("broker1"))
val schedulingConfigs = listOf(
createBrokerSchedulingConfig(
"broker1",
maintenanceScanInMillis = TimeUnit.DAYS.toMillis(10),
confirmOptOutScanInMillis = TimeUnit.DAYS.toMillis(5),
),
)
val scanJobs = listOf(
createScanJobRecord(
"broker1",
userProfileId = 1L,
ScanJobStatus.MATCHES_FOUND,
currentTime - TimeUnit.DAYS.toMillis(3),
),
createScanJobRecord(
"broker1",
userProfileId = 2L,
ScanJobStatus.MATCHES_FOUND,
currentTime - TimeUnit.DAYS.toMillis(4),
),
)
val optOutJobs = listOf(
createOptOutJobRecord(
brokerName = "broker1",
extractedProfileId = 1L,
userProfileId = 1L,
status = OptOutJobStatus.REQUESTED,
optOutRequestedDateInMillis = currentTime - TimeUnit.DAYS.toMillis(2),
),
createOptOutJobRecord(
brokerName = "broker1",
extractedProfileId = 2L,
userProfileId = 2L,
status = OptOutJobStatus.REQUESTED,
optOutRequestedDateInMillis = currentTime - TimeUnit.DAYS.toMillis(1),
),
)

whenever(mockPirSchedulingRepository.getAllValidOptOutJobRecords()).thenReturn(optOutJobs)
whenever(mockPirRepository.getAllActiveBrokerObjects()).thenReturn(activeBrokers)
whenever(mockPirRepository.getAllBrokerOptOutUrls()).thenReturn(emptyMap())
whenever(mockPirRepository.getAllBrokerSchedulingConfigs()).thenReturn(schedulingConfigs)
whenever(mockPirSchedulingRepository.getAllValidScanJobRecords()).thenReturn(scanJobs)
whenever(mockPirRepository.getAllMirrorSites()).thenReturn(emptyList())

// When
val result = testee.getNextScanDetails()

// Then - Returns only ONE broker match per broker, regardless of how many profile queries exist
// This is because DashboardBrokerMatch only contains broker info, not profile query info
assertEquals(1, result.brokerMatches.size)
assertEquals("broker1", result.brokerMatches[0].broker.name)
}

@Test
fun whenNoneInRangeThenGetNextScanDetailsReturnsEmpty() = runTest {
// Given
Expand Down
Loading