Skip to content

Commit bf7e5d0

Browse files
authored
Use counts in leaderboard (#509)
* Use nondistinct counts for leaderboard sites * Use nondistinct counts for leaderboard network entries
1 parent 8fd1c69 commit bf7e5d0

File tree

15 files changed

+720
-144
lines changed

15 files changed

+720
-144
lines changed

app/schemas/com.duckduckgo.app.global.db.AppDatabase/13.json

Lines changed: 546 additions & 0 deletions
Large diffs are not rendered by default.

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import com.duckduckgo.app.global.install.AppInstallStore
5252
import com.duckduckgo.app.global.model.SiteFactory
5353
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao
5454
import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry
55-
import com.duckduckgo.app.privacy.db.SiteVisitedEntity
5655
import com.duckduckgo.app.privacy.model.PrivacyPractices
5756
import com.duckduckgo.app.privacy.store.PrevalenceStore
5857
import com.duckduckgo.app.settings.db.SettingsDataStore
@@ -298,7 +297,7 @@ class BrowserTabViewModelTest {
298297
fun whenTrackerDetectedThenNetworkLeaderboardUpdated() {
299298
val event = TrackingEvent("http://www.example.com", "http://www.tracker.com/tracker.js", TrackerNetwork("Network1", "www.tracker.com"), false)
300299
testee.trackerDetected(event)
301-
verify(mockNetworkLeaderboardDao).insert(NetworkLeaderboardEntry("Network1", "www.example.com"))
300+
verify(mockNetworkLeaderboardDao).incrementNetworkCount("Network1")
302301
}
303302

304303
@Test
@@ -389,15 +388,15 @@ class BrowserTabViewModelTest {
389388
isBrowsing(true)
390389
testee.loadingStarted("http://example.com/abc")
391390
testee.loadingFinished("http://example.com/abc")
392-
verify(mockNetworkLeaderboardDao).insert(SiteVisitedEntity("example.com"))
391+
verify(mockNetworkLeaderboardDao).incrementSitesVisited()
393392
}
394393

395394
@Test
396395
fun whenNotBrowsingAndLoadingFinishedWithUrlThenSiteVisitedEntryNotAddedToLeaderboardDao() {
397396
isBrowsing(false)
398397
testee.loadingStarted("http://example.com/abc")
399398
testee.loadingFinished("http://example.com/abc")
400-
verify(mockNetworkLeaderboardDao, never()).insert(SiteVisitedEntity("example.com"))
399+
verify(mockNetworkLeaderboardDao, never()).incrementSitesVisited()
401400
}
402401

403402
@Test
@@ -443,13 +442,13 @@ class BrowserTabViewModelTest {
443442
@Test
444443
fun whenLoadingFinishedWithNoUrlThenSiteVisitedEntryNotAddedToLeaderboardDao() {
445444
testee.loadingFinished(null)
446-
verify(mockNetworkLeaderboardDao, never()).insert(SiteVisitedEntity("example.com"))
445+
verify(mockNetworkLeaderboardDao, never()).incrementSitesVisited()
447446
}
448447

449448
@Test
450449
fun whenTrackerDetectedThenSiteVisitedEntryAddedToLeaderboardDao() {
451450
testee.trackerDetected(TrackingEvent("http://example.com/abc", "http://tracker.com", TrackerNetwork("Network", "http:// netwotk.com"), true))
452-
verify(mockNetworkLeaderboardDao).insert(SiteVisitedEntity("example.com"))
451+
verify(mockNetworkLeaderboardDao).incrementSitesVisited()
453452
}
454453

455454
@Test

app/src/androidTest/java/com/duckduckgo/app/global/db/AppDatabaseTest.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class AppDatabaseTest {
5252
testHelper.createDatabase(TEST_DB_NAME, 2).use {
5353
it.execSQL("INSERT INTO `network_leaderboard` VALUES ('Network2', 'example.com')")
5454
}
55-
assertTrue(database().networkLeaderboardDao().trackerNetworkTally().blockingObserve()!!.isEmpty())
55+
assertTrue(database().networkLeaderboardDao().trackerNetworkLeaderboard().blockingObserve()!!.isEmpty())
5656
}
5757

5858
@Test
@@ -120,6 +120,11 @@ class AppDatabaseTest {
120120
createDatabaseAndMigrate(11, 12, AppDatabase.MIGRATION_11_TO_12)
121121
}
122122

123+
@Test
124+
fun whenMigratingFromVersion12To13ThenValidationSucceeds() {
125+
createDatabaseAndMigrate(12, 13, AppDatabase.MIGRATION_12_TO_13)
126+
}
127+
123128
@Test
124129
fun whenMigratingFromVersion11To12ThenTabsDoNotSkipHome() {
125130
testHelper.createDatabase(TEST_DB_NAME, 11).use {

app/src/androidTest/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDaoTest.kt

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import androidx.room.Room
2121
import androidx.test.platform.app.InstrumentationRegistry
2222
import com.duckduckgo.app.blockingObserve
2323
import com.duckduckgo.app.global.db.AppDatabase
24-
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally
2524
import org.junit.After
2625
import org.junit.Assert.assertEquals
2726
import org.junit.Assert.assertTrue
@@ -54,31 +53,34 @@ class NetworkLeaderboardDaoTest {
5453
}
5554

5655
@Test
57-
fun whenNetworksInsertedThenAddedToTallyWithCount() {
58-
dao.insert(NetworkLeaderboardEntry("Network1", domainVisited = "www.example1.com"))
59-
dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example2.com"))
60-
dao.insert(NetworkLeaderboardEntry("Network3", domainVisited = "www.example3.com"))
61-
62-
val data: List<NetworkTally>? = dao.trackerNetworkTally().blockingObserve()
63-
assertEquals(3, data!!.size)
64-
assertTrue(data.contains(NetworkTally("Network1", 1)))
65-
assertTrue(data.contains(NetworkTally("Network2", 1)))
66-
assertTrue(data.contains(NetworkTally("Network3", 1)))
56+
fun whenNetworkThatDoesNotExistIncrementedThenAddedToDatabase() {
57+
dao.incrementNetworkCount("Network1")
58+
val data: List<NetworkLeaderboardEntry>? = dao.trackerNetworkLeaderboard().blockingObserve()
59+
assertEquals(1, data!!.size)
60+
assertTrue(data.contains(NetworkLeaderboardEntry("Network1", 1)))
6761
}
6862

63+
6964
@Test
70-
fun whenNetworksHaveMultipleDomainsThenAddedToTallyWithCountInDescendingOrder() {
71-
dao.insert(NetworkLeaderboardEntry("Network1", domainVisited = "www.example1.com"))
72-
dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example1.com"))
73-
dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example2.com"))
74-
dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example3.com"))
75-
dao.insert(NetworkLeaderboardEntry("Network3", domainVisited = "www.example3.com"))
76-
dao.insert(NetworkLeaderboardEntry("Network3", domainVisited = "www.example4.com"))
65+
fun whenNetworksIncrementedMultipleTimesThenReturnedWithCountInDescendingOrder() {
66+
dao.incrementNetworkCount("Network1")
67+
dao.incrementNetworkCount("Network2")
68+
dao.incrementNetworkCount("Network2")
69+
dao.incrementNetworkCount("Network2")
70+
dao.incrementNetworkCount("Network3")
71+
dao.incrementNetworkCount("Network3")
7772

73+
val data: List<NetworkLeaderboardEntry> = dao.trackerNetworkLeaderboard().blockingObserve()!!
74+
assertEquals(NetworkLeaderboardEntry("Network2", 3), data[0])
75+
assertEquals(NetworkLeaderboardEntry("Network3", 2), data[1])
76+
assertEquals(NetworkLeaderboardEntry("Network1", 1), data[2])
77+
}
7878

79-
val data: List<NetworkTally> = dao.trackerNetworkTally().blockingObserve()!!
80-
assertEquals(NetworkTally("Network2", 3), data[0])
81-
assertEquals(NetworkTally("Network3", 2), data[1])
82-
assertEquals(NetworkTally("Network1", 1), data[2])
79+
@Test
80+
fun whenSiteVisitedIncremenetedThenSiteVisitedCountIncreaesByOne() {
81+
dao.incrementSitesVisited()
82+
assertEquals(1, dao.sitesVisited().blockingObserve())
83+
dao.incrementSitesVisited()
84+
assertEquals(2, dao.sitesVisited().blockingObserve())
8385
}
8486
}

app/src/androidTest/java/com/duckduckgo/app/privacy/renderer/TrackersRendererTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package com.duckduckgo.app.privacy.renderer
1818

1919
import androidx.test.platform.app.InstrumentationRegistry
2020
import com.duckduckgo.app.browser.R
21-
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally
21+
import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry
2222
import org.junit.Assert.assertEquals
2323
import org.junit.Assert.assertNull
2424
import org.junit.Test
@@ -65,26 +65,26 @@ class TrackersRendererTest {
6565
}
6666

6767
@Test
68-
fun whenTotalDomainsIsZeroThenPercentageIsBlank() {
69-
val text = testee.networkPercentage(NetworkTally("", 10), 0)
68+
fun whenSitestVisitedIsZeroThenPercentageIsBlank() {
69+
val text = testee.networkPercentage(NetworkLeaderboardEntry("", 10), 0)
7070
assertEquals("", text)
7171
}
7272

7373
@Test
74-
fun whenDomainCountIsZeroThenPercentageIsBlank() {
75-
val text = testee.networkPercentage(NetworkTally("", 0), 10)
74+
fun whenNetworkCountIsZeroThenPercentageIsBlank() {
75+
val text = testee.networkPercentage(NetworkLeaderboardEntry("", 0), 10)
7676
assertEquals("", text)
7777
}
7878

7979
@Test
8080
fun whenPortionIsRecurringFractionThenPercentageIsRoundNumber() {
81-
val text = testee.networkPercentage(NetworkTally("", 10), 30)
81+
val text = testee.networkPercentage(NetworkLeaderboardEntry("", 10), 30)
8282
assertEquals("33%", text)
8383
}
8484

8585
@Test
8686
fun whenPortionIsHalfThenPercentageIs50Percent() {
87-
val text = testee.networkPercentage(NetworkTally("", 10), 20)
87+
val text = testee.networkPercentage(NetworkLeaderboardEntry("", 10), 20)
8888
assertEquals("50%", text)
8989
}
9090

app/src/androidTest/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModelTest.kt

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import androidx.lifecycle.LiveData
2121
import androidx.lifecycle.Observer
2222
import com.duckduckgo.app.global.model.Site
2323
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao
24-
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally
24+
import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry
2525
import com.duckduckgo.app.privacy.model.HttpsStatus
2626
import com.duckduckgo.app.privacy.model.PrivacyGrade
2727
import com.duckduckgo.app.privacy.model.PrivacyPractices
@@ -47,23 +47,23 @@ class PrivacyDashboardViewModelTest {
4747

4848
private var viewStateObserver: Observer<PrivacyDashboardViewModel.ViewState> = mock()
4949
private var settingStore: PrivacySettingsStore = mock()
50-
private var networkLeaderboard: NetworkLeaderboardDao = mock()
51-
private var networkTallyLiveData: LiveData<List<NetworkTally>> = mock()
52-
private var domainsVisitedLiveData: LiveData<Int> = mock()
50+
private var networkLeaderboardDao: NetworkLeaderboardDao = mock()
51+
private var networkLeaserboardLiveData: LiveData<List<NetworkLeaderboardEntry>> = mock()
52+
private var sitesVisitedLiveData: LiveData<Int> = mock()
5353
private var mockPixel: Pixel = mock()
5454

5555
private val testee: PrivacyDashboardViewModel by lazy {
56-
val model = PrivacyDashboardViewModel(settingStore, networkLeaderboard, mockPixel)
56+
val model = PrivacyDashboardViewModel(settingStore, networkLeaderboardDao, mockPixel)
5757
model.viewState.observeForever(viewStateObserver)
5858
model
5959
}
6060

6161
@Before
6262
fun before() {
63-
whenever(domainsVisitedLiveData.value).thenReturn(0)
64-
whenever(networkTallyLiveData.value).thenReturn(emptyList())
65-
whenever(networkLeaderboard.domainsVisitedCount()).thenReturn(domainsVisitedLiveData)
66-
whenever(networkLeaderboard.trackerNetworkTally()).thenReturn(networkTallyLiveData)
63+
whenever(sitesVisitedLiveData.value).thenReturn(0)
64+
whenever(networkLeaserboardLiveData.value).thenReturn(emptyList())
65+
whenever(networkLeaderboardDao.sitesVisited()).thenReturn(sitesVisitedLiveData)
66+
whenever(networkLeaderboardDao.trackerNetworkLeaderboard()).thenReturn(networkLeaserboardLiveData)
6767
}
6868

6969
@After
@@ -151,50 +151,50 @@ class PrivacyDashboardViewModelTest {
151151
}
152152

153153
@Test
154-
fun whenNetworkCountIsAtLeastThreeAndTotalDomainsIsOverThirtyThenShowSummaryIsTrue() {
155-
val first = NetworkTally("Network1", 5)
156-
val second = NetworkTally("Network2", 3)
157-
val third = NetworkTally("Network3", 3)
158-
testee.onTrackerNetworkTallyChanged(listOf(first, second, third))
159-
testee.onDomainsVisitedChanged(31)
154+
fun whenNetworkCountIsAtLeastThreeAndTotalSitesIsOverThirtyThenShowSummaryIsTrue() {
155+
val first = NetworkLeaderboardEntry("Network1", 5)
156+
val second = NetworkLeaderboardEntry("Network2", 3)
157+
val third = NetworkLeaderboardEntry("Network3", 3)
158+
testee.onTrackerNetworkEntriesChanged(listOf(first, second, third))
159+
testee.onSitesVisitedChanged(31)
160160
assertTrue(testee.viewState.value!!.showTrackerNetworkLeaderboard)
161161
}
162162

163163
@Test
164164
fun whenNetworkCountIsLessThanThreeThenShowSummaryIsFalse() {
165-
val first = NetworkTally("Network1", 5)
166-
val second = NetworkTally("Network2", 3)
167-
testee.onTrackerNetworkTallyChanged(listOf(first, second))
168-
testee.onDomainsVisitedChanged(31)
165+
val first = NetworkLeaderboardEntry("Network1", 5)
166+
val second = NetworkLeaderboardEntry("Network2", 3)
167+
testee.onTrackerNetworkEntriesChanged(listOf(first, second))
168+
testee.onSitesVisitedChanged(31)
169169
assertFalse(testee.viewState.value!!.showTrackerNetworkLeaderboard)
170170
}
171171

172172
@Test
173-
fun whenDomainsIsNotOverThirtyThenShowSummaryIsFalse() {
174-
val first = NetworkTally("Network1", 5)
175-
val second = NetworkTally("Network2", 3)
176-
val third = NetworkTally("Network3", 3)
177-
testee.onTrackerNetworkTallyChanged(listOf(first, second, third))
178-
testee.onDomainsVisitedChanged(30)
173+
fun whenSitesIsNotOverThirtyThenShowSummaryIsFalse() {
174+
val first = NetworkLeaderboardEntry("Network1", 5)
175+
val second = NetworkLeaderboardEntry("Network2", 3)
176+
val third = NetworkLeaderboardEntry("Network3", 3)
177+
testee.onTrackerNetworkEntriesChanged(listOf(first, second, third))
178+
testee.onSitesVisitedChanged(30)
179179
assertFalse(testee.viewState.value!!.showTrackerNetworkLeaderboard)
180180
}
181181

182182
@Test
183183
fun whenNetworkLeaderboardDataAvailableThenViewStateUpdated() {
184-
val first = NetworkTally("Network1", 5)
185-
val second = NetworkTally("Network2", 3)
186-
testee.onTrackerNetworkTallyChanged(listOf(first, second))
184+
val first = NetworkLeaderboardEntry("Network1", 5)
185+
val second = NetworkLeaderboardEntry("Network2", 3)
186+
testee.onTrackerNetworkEntriesChanged(listOf(first, second))
187187

188188
val viewState = testee.viewState.value!!
189-
assertEquals(first, viewState.trackerNetworkTally[0])
190-
assertEquals(second, viewState.trackerNetworkTally[1])
189+
assertEquals(first, viewState.trackerNetworkEntries[0])
190+
assertEquals(second, viewState.trackerNetworkEntries[1])
191191
}
192192

193193
@Test
194194
fun whenNoNetworkLeaderboardDataThenDefaultValuesAreUsed() {
195-
testee.onTrackerNetworkTallyChanged(emptyList())
195+
testee.onTrackerNetworkEntriesChanged(emptyList())
196196
val viewState = testee.viewState.value!!
197-
assertEquals(emptyList<NetworkTally>(), viewState.trackerNetworkTally)
197+
assertEquals(emptyList<NetworkLeaderboardEntry>(), viewState.trackerNetworkEntries)
198198
assertFalse(viewState.showTrackerNetworkLeaderboard)
199199
}
200200

app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ import com.duckduckgo.app.global.db.AppConfigurationEntity
5555
import com.duckduckgo.app.global.model.Site
5656
import com.duckduckgo.app.global.model.SiteFactory
5757
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao
58-
import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry
59-
import com.duckduckgo.app.privacy.db.SiteVisitedEntity
6058
import com.duckduckgo.app.privacy.model.PrivacyGrade
6159
import com.duckduckgo.app.settings.db.SettingsDataStore
6260
import com.duckduckgo.app.statistics.api.StatisticsUpdater
@@ -431,9 +429,8 @@ class BrowserTabViewModel(
431429
}
432430

433431
private fun registerSiteVisit() {
434-
val domainVisited = url?.toUri()?.host ?: return
435432
Schedulers.io().scheduleDirect {
436-
networkLeaderboardDao.insert(SiteVisitedEntity(domainVisited))
433+
networkLeaderboardDao.incrementSitesVisited()
437434
}
438435
}
439436

@@ -515,9 +512,8 @@ class BrowserTabViewModel(
515512

516513
private fun updateNetworkLeaderboard(event: TrackingEvent) {
517514
val networkName = event.trackerNetwork?.name ?: return
518-
val domainVisited = Uri.parse(event.documentUrl).host ?: return
519-
networkLeaderboardDao.insert(NetworkLeaderboardEntry(networkName, domainVisited))
520-
networkLeaderboardDao.insert(SiteVisitedEntity(domainVisited))
515+
networkLeaderboardDao.incrementNetworkCount(networkName)
516+
networkLeaderboardDao.incrementSitesVisited()
521517
}
522518

523519
override fun pageHasHttpResources(page: String?) {

app/src/main/java/com/duckduckgo/app/global/db/AppDatabase.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import com.duckduckgo.app.notification.model.Notification
4040
import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao
4141
import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry
4242
import com.duckduckgo.app.privacy.db.PrivacyProtectionCountDao
43-
import com.duckduckgo.app.privacy.db.SiteVisitedEntity
43+
import com.duckduckgo.app.privacy.db.SitesVisitedEntity
4444
import com.duckduckgo.app.privacy.model.PrivacyProtectionCountsEntity
4545
import com.duckduckgo.app.survey.db.SurveyDao
4646
import com.duckduckgo.app.survey.model.Survey
@@ -55,12 +55,12 @@ import com.duckduckgo.app.usage.search.SearchCountDao
5555
import com.duckduckgo.app.usage.search.SearchCountEntity
5656

5757
@Database(
58-
exportSchema = true, version = 12, entities = [
58+
exportSchema = true, version = 13, entities = [
5959
DisconnectTracker::class,
6060
HttpsBloomFilterSpec::class,
6161
HttpsWhitelistedDomain::class,
6262
NetworkLeaderboardEntry::class,
63-
SiteVisitedEntity::class,
63+
SitesVisitedEntity::class,
6464
AppConfigurationEntity::class,
6565
TabEntity::class,
6666
TabSelectionEntity::class,
@@ -188,6 +188,15 @@ abstract class AppDatabase : RoomDatabase() {
188188
}
189189
}
190190

191+
val MIGRATION_12_TO_13: Migration = object : Migration(12, 13) {
192+
override fun migrate(database: SupportSQLiteDatabase) {
193+
database.execSQL("DROP TABLE `site_visited`")
194+
database.execSQL("DROP TABLE `network_leaderboard`")
195+
database.execSQL("CREATE TABLE IF NOT EXISTS `sites_visited` (`key` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`key`))")
196+
database.execSQL("CREATE TABLE IF NOT EXISTS `network_leaderboard` (`networkName` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`networkName`))")
197+
}
198+
}
199+
191200
val ALL_MIGRATIONS: List<Migration>
192201
get() = listOf(
193202
MIGRATION_1_TO_2,
@@ -200,7 +209,8 @@ abstract class AppDatabase : RoomDatabase() {
200209
MIGRATION_8_TO_9,
201210
MIGRATION_9_TO_10,
202211
MIGRATION_10_TO_11,
203-
MIGRATION_11_TO_12
212+
MIGRATION_11_TO_12,
213+
MIGRATION_12_TO_13
204214
)
205215
}
206216
}

0 commit comments

Comments
 (0)