Skip to content

Commit 3868d25

Browse files
authored
Add support for enqueueing daily and unique pixels (#7639)
Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1213068706396582?focus=true ### Description This PR adds PixelType param to enqueueFire() method in the Pixel interface, aligning functionality between fire() and enqueueFire() methods. ### Steps to test this PR The new API is not in use yet, so this PR is QA-optional. ### No UI changes <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes the core analytics enqueueing contract and adds new suppression logic for daily/unique pixels, which could alter what gets persisted and sent if misapplied. > > **Overview** > Aligns `Pixel.enqueueFire` with `fire` by adding a `PixelType` parameter (defaulting to `Count`) so enqueued pixels can be treated as *count*, *daily*, or *unique* events. > > Updates `PixelSender.enqueuePixel` to accept `PixelType` and return `Single<EnqueuePixelResult>` (`PIXEL_ENQUEUED`/`PIXEL_IGNORED`), and changes `RxPixelSender` to apply the same daily/unique suppression + fired-state tracking when enqueueing (not just when sending). > > Adjusts `RxBasedPixel` logging to reflect enqueue outcomes, and updates stubs/fakes and unit tests across modules to pass the new `type` argument and assert the new behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9985b3a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent afb1639 commit 3868d25

File tree

16 files changed

+179
-28
lines changed

16 files changed

+179
-28
lines changed

app/src/androidTest/java/com/duckduckgo/app/di/StubStatisticsModule.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver
2121
import com.duckduckgo.app.statistics.AtbInitializer
2222
import com.duckduckgo.app.statistics.AtbInitializerListener
2323
import com.duckduckgo.app.statistics.api.PixelSender
24+
import com.duckduckgo.app.statistics.api.PixelSender.EnqueuePixelResult
2425
import com.duckduckgo.app.statistics.api.PixelSender.SendPixelResult
2526
import com.duckduckgo.app.statistics.api.PixelSender.SendPixelResult.PIXEL_SENT
2627
import com.duckduckgo.app.statistics.api.StatisticsService
@@ -38,7 +39,6 @@ import dagger.Module
3839
import dagger.Provides
3940
import dagger.SingleInstanceIn
4041
import dagger.multibindings.IntoSet
41-
import io.reactivex.Completable
4242
import io.reactivex.Single
4343
import kotlinx.coroutines.CoroutineScope
4444
import retrofit2.Retrofit
@@ -96,13 +96,15 @@ class StubStatisticsModule {
9696
pixel: Pixel.PixelName,
9797
parameters: Map<String, String>,
9898
encodedParameters: Map<String, String>,
99+
type: PixelType,
99100
) {
100101
}
101102

102103
override fun enqueueFire(
103104
pixelName: String,
104105
parameters: Map<String, String>,
105106
encodedParameters: Map<String, String>,
107+
type: PixelType,
106108
) {
107109
}
108110
}
@@ -141,8 +143,9 @@ class StubStatisticsModule {
141143
pixelName: String,
142144
parameters: Map<String, String>,
143145
encodedParameters: Map<String, String>,
144-
): Completable {
145-
return Completable.fromAction {}
146+
type: PixelType,
147+
): Single<EnqueuePixelResult> {
148+
return Single.just(EnqueuePixelResult.PIXEL_ENQUEUED)
146149
}
147150
}
148151
}

app/src/test/java/com/duckduckgo/fakes/FakePixel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ internal class FakePixel : Pixel {
4646
pixel: PixelName,
4747
parameters: Map<String, String>,
4848
encodedParameters: Map<String, String>,
49+
type: PixelType,
4950
) {
5051
firedPixels.add(pixel.pixelName)
5152
}
@@ -54,6 +55,7 @@ internal class FakePixel : Pixel {
5455
pixelName: String,
5556
parameters: Map<String, String>,
5657
encodedParameters: Map<String, String>,
58+
type: PixelType,
5759
) {
5860
firedPixels.add(pixelName)
5961
}

autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/pixels/AutoconsentPixelManagerTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.junit.Assert.*
2929
import org.junit.Before
3030
import org.junit.Rule
3131
import org.junit.Test
32+
import org.mockito.kotlin.any
3233
import org.mockito.kotlin.argThat
3334
import org.mockito.kotlin.eq
3435
import org.mockito.kotlin.mock
@@ -165,6 +166,7 @@ class AutoconsentPixelManagerTest {
165166
parameters["init"] == "2" && parameters["popup-found"] == "1"
166167
},
167168
eq(emptyMap()),
169+
any(),
168170
)
169171
}
170172

@@ -185,11 +187,13 @@ class AutoconsentPixelManagerTest {
185187
eq(AutoConsentPixel.AUTOCONSENT_SUMMARY),
186188
argThat { parameters -> parameters["init"] == "1" },
187189
eq(emptyMap()),
190+
any(),
188191
)
189192
verify(mockPixel).enqueueFire(
190193
eq(AutoConsentPixel.AUTOCONSENT_SUMMARY),
191194
argThat { parameters -> parameters["popup-found"] == "1" },
192195
eq(emptyMap()),
196+
any(),
193197
)
194198
}
195199
}

autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/ui/AutoconsentSettingsViewModelTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class AutoconsentSettingsViewModelTest {
191191
pixel: PixelName,
192192
parameters: Map<String, String>,
193193
encodedParameters: Map<String, String>,
194+
type: PixelType,
194195
) {
195196
firedPixels.add(pixel.pixelName)
196197
}
@@ -199,6 +200,7 @@ class AutoconsentSettingsViewModelTest {
199200
pixelName: String,
200201
parameters: Map<String, String>,
201202
encodedParameters: Map<String, String>,
203+
type: PixelType,
202204
) {
203205
firedPixels.add(pixelName)
204206
}

autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/engagement/store/DefaultAutofillEngagementRepositoryTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ class DefaultAutofillEngagementRepositoryTest {
251251
pixel: PixelName,
252252
parameters: Map<String, String>,
253253
encodedParameters: Map<String, String>,
254+
type: PixelType,
254255
) {
255256
firedPixels[pixel.pixelName] = parameters
256257
}
@@ -259,6 +260,7 @@ class DefaultAutofillEngagementRepositoryTest {
259260
pixelName: String,
260261
parameters: Map<String, String>,
261262
encodedParameters: Map<String, String>,
263+
type: PixelType,
262264
) {
263265
firedPixels[pixelName] = parameters
264266
}

feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/impl/metrics/RetentionMetricsAtbLifecyclePluginTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ private class FakePixel : Pixel {
317317
pixel: PixelName,
318318
parameters: Map<String, String>,
319319
encodedParameters: Map<String, String>,
320+
type: PixelType,
320321
) {
321322
firedPixels.add(pixel.pixelName + parameters)
322323
}
@@ -325,6 +326,7 @@ private class FakePixel : Pixel {
325326
pixelName: String,
326327
parameters: Map<String, String>,
327328
encodedParameters: Map<String, String>,
329+
type: PixelType,
328330
) {
329331
firedPixels.add(pixelName + parameters)
330332
}

pir/pir-impl/src/androidTest/java/com/duckduckgo/pir/impl/integration/fakes/FakePixel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class FakePixel : Pixel {
5757
pixel: PixelName,
5858
parameters: Map<String, String>,
5959
encodedParameters: Map<String, String>,
60+
type: PixelType,
6061
) {
6162
enqueueFire(pixel.pixelName, parameters, encodedParameters)
6263
}
@@ -65,6 +66,7 @@ class FakePixel : Pixel {
6566
pixelName: String,
6667
parameters: Map<String, String>,
6768
encodedParameters: Map<String, String>,
69+
type: PixelType,
6870
) {
6971
firedPixels.add(
7072
FiredPixel(

pir/pir-impl/src/test/kotlin/com/duckduckgo/pir/impl/pixels/RealPirPixelSenderTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class RealPirPixelSenderTest {
7676
pixelName = any(),
7777
parameters = paramsCaptor.capture(),
7878
encodedParameters = any(),
79+
type = any(),
7980
)
8081

8182
assert(paramsCaptor.firstValue.isEmpty())
@@ -90,6 +91,7 @@ class RealPirPixelSenderTest {
9091
pixelName = any(),
9192
parameters = paramsCaptor.capture(),
9293
encodedParameters = any(),
94+
type = any(),
9395
)
9496
}
9597

settings/settings-impl/src/test/java/com/duckduckgo/settings/impl/serpsettings/fakes/FakePixel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class FakePixel : Pixel {
4343
pixel: Pixel.PixelName,
4444
parameters: Map<String, String>,
4545
encodedParameters: Map<String, String>,
46+
type: Pixel.PixelType,
4647
) {
4748
firedPixels.add(pixel.pixelName)
4849
}
@@ -51,6 +52,7 @@ class FakePixel : Pixel {
5152
pixelName: String,
5253
parameters: Map<String, String>,
5354
encodedParameters: Map<String, String>,
55+
type: Pixel.PixelType,
5456
) {
5557
firedPixels.add(pixelName)
5658
}

statistics/statistics-api/src/main/java/com/duckduckgo/app/statistics/api/PixelSender.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.duckduckgo.app.statistics.api
1818

1919
import com.duckduckgo.app.statistics.pixels.Pixel.PixelType
20-
import io.reactivex.Completable
2120
import io.reactivex.Single
2221

2322
/**
@@ -47,20 +46,27 @@ interface PixelSender {
4746
* Sends a pixel with the specified name and parameters. Unlike the `sendPixel()` method, this method also persists the pixel in the local database,
4847
* allowing it to be retried in case of network issues or other failures.
4948
*
50-
* This method is safe to call from any thread, as the operation does not start until the returned [Completable] is subscribed to.
49+
* This method is safe to call from any thread, as the operation does not start until the returned [Single] is subscribed to.
5150
*
5251
* @param pixelName The name of the pixel event to be sent.
5352
* @param parameters A map of parameters to be included with the pixel event. These parameters are URL-encoded before being sent.
5453
* @param encodedParameters A map of parameters that are already URL-encoded. Use this when the parameters are pre-encoded.
54+
* @param type The type of pixel event to be sent.
5555
*/
5656
fun enqueuePixel(
5757
pixelName: String,
5858
parameters: Map<String, String>,
5959
encodedParameters: Map<String, String>,
60-
): Completable
60+
type: PixelType,
61+
): Single<EnqueuePixelResult>
6162

6263
enum class SendPixelResult {
6364
PIXEL_SENT,
6465
PIXEL_IGNORED, // Daily or unique pixels may be ignored.
6566
}
67+
68+
enum class EnqueuePixelResult {
69+
PIXEL_ENQUEUED,
70+
PIXEL_IGNORED, // Daily or unique pixels may be ignored.
71+
}
6672
}

0 commit comments

Comments
 (0)