Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return all buckets if privacy bucket mappers operative field set is empty #1396

Merged
merged 7 commits into from
Jan 10, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import java.time.Clock
import java.time.ZoneOffset
import org.wfanet.measurement.common.OpenEndTimeRange
import org.wfanet.measurement.common.rangeTo
import org.wfanet.measurement.eventdataprovider.eventfiltration.EventFilters

class PrivacyBucketFilter(
private val privacyBucketMapper: PrivacyBucketMapper,
Expand Down Expand Up @@ -84,12 +83,7 @@ class PrivacyBucketFilter(
vidsIntervalStartPoint,
PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
)
if (
EventFilters.matches(
privacyBucketMapper.toEventMessage(privacyBucketGroup),
program
)
) {
if (privacyBucketMapper.matches(privacyBucketGroup, program)) {
yield(privacyBucketGroup)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,23 @@ package org.wfanet.measurement.eventdataprovider.privacybudgetmanagement

import com.google.protobuf.Message
import org.projectnessie.cel.Program
import org.wfanet.measurement.eventdataprovider.eventfiltration.EventFilters

/** Maps Privacy bucket related objects to event filter related objects and vice versa. */
interface PrivacyBucketMapper {

val operativeFields: Set<String>

/** Maps [filterExpression] to a [Program] by using privacy related fields and [Message] */
fun toPrivacyFilterProgram(filterExpression: String): Program

/** Maps [privacyBucketGroup] to an event [Message] */
fun toEventMessage(privacyBucketGroup: PrivacyBucketGroup): Message

fun matches(privacyBucketGroup: PrivacyBucketGroup, program: Program): Boolean {
if (operativeFields.isEmpty()) {
return true
}
return EventFilters.matches(toEventMessage(privacyBucketGroup), program)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2023 The Cross-Media Measurement Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.testing

import com.google.protobuf.Message
import org.projectnessie.cel.Program
import org.wfanet.measurement.api.v2alpha.event_templates.testing.TestEvent
import org.wfanet.measurement.api.v2alpha.event_templates.testing.testEvent
import org.wfanet.measurement.eventdataprovider.eventfiltration.EventFilters.compileProgram
import org.wfanet.measurement.eventdataprovider.eventfiltration.validation.EventFilterValidationException
import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.PrivacyBucketGroup
import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.PrivacyBucketMapper
import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.PrivacyBudgetManagerException
import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.PrivacyBudgetManagerExceptionType

/** [PrivacyBucketMapper] for [TestEvent] instances that charges all buckets. */
class AlwaysChargingPrivacyBucketMapper : PrivacyBucketMapper {

override val operativeFields = emptySet<String>()

override fun toPrivacyFilterProgram(filterExpression: String): Program =
try {
compileProgram(TestEvent.getDescriptor(), "true == true", operativeFields)
} catch (e: EventFilterValidationException) {
throw PrivacyBudgetManagerException(
PrivacyBudgetManagerExceptionType.INVALID_PRIVACY_BUCKET_FILTER,
e
)
}

override fun toEventMessage(privacyBucketGroup: PrivacyBucketGroup): Message {
return testEvent {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@ import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.PrivacyB

/** [PrivacyBucketMapper] for [TestEvent] instances. */
class TestPrivacyBucketMapper : PrivacyBucketMapper {

override val operativeFields = setOf("person.age_group", "person.gender")

override fun toPrivacyFilterProgram(filterExpression: String): Program =
try {
compileProgram(
TestEvent.getDescriptor(),
filterExpression,
setOf("person.age_group", "person.gender")
)
compileProgram(TestEvent.getDescriptor(), filterExpression, operativeFields)
} catch (e: EventFilterValidationException) {
throw PrivacyBudgetManagerException(
PrivacyBudgetManagerExceptionType.INVALID_PRIVACY_BUCKET_FILTER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ import org.wfanet.measurement.loadtest.config.LoadTestEventKt.privacy

class TestPrivacyBucketMapper : PrivacyBucketMapper {

override val operativeFields = setOf("privacy.filterable")

/** This mapper does not charge any bucket [filterExpression] is ignored. */
override fun toPrivacyFilterProgram(filterExpression: String): Program =
try {
compileProgram(
LoadTestEvent.getDescriptor(),
"privacy.filterable == true",
setOf("privacy.filterable")
)
compileProgram(LoadTestEvent.getDescriptor(), "privacy.filterable == true", operativeFields)
} catch (e: EventFilterValidationException) {
throw PrivacyBudgetManagerException(
PrivacyBudgetManagerExceptionType.INVALID_PRIVACY_BUCKET_FILTER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.wfanet.measurement.common.OpenEndTimeRange
import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.testing.AlwaysChargingPrivacyBucketMapper
import org.wfanet.measurement.eventdataprovider.privacybudgetmanagement.testing.TestPrivacyBucketMapper

private const val MEASUREMENT_CONSUMER_ID = "ACME"
Expand All @@ -30,6 +31,8 @@ private const val MEASUREMENT_CONSUMER_ID = "ACME"
class PrivacyBucketFilterTest {

private val privacyBucketFilter = PrivacyBucketFilter(TestPrivacyBucketMapper())
private val alwaysChargingPrivacyBucketFilter =
PrivacyBucketFilter(AlwaysChargingPrivacyBucketMapper())
private val today: LocalDateTime = LocalDate.now().atTime(4, 20)
private val yesterday: LocalDateTime = today.minusDays(1)
private val startOfTomorrow: LocalDateTime = today.plusDays(1).toLocalDate().atStartOfDay()
Expand Down Expand Up @@ -266,4 +269,239 @@ class PrivacyBucketFilterTest {
)
.hasSize(24)
}

@Test
fun `Mapper succeeds with empty operative fields`() {
val privacyLandscapeMask =
LandscapeMask(
listOf(EventGroupSpec("person.age_group in [1] ", timeRange)),
0.0f,
PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
)

assertThat(
alwaysChargingPrivacyBucketFilter.getPrivacyBucketGroups(
MEASUREMENT_CONSUMER_ID,
privacyLandscapeMask
)
)
.containsExactly(
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.MALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.FEMALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.MALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.FEMALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.MALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.FEMALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.MALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.FEMALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.MALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.FEMALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.MALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.FEMALE,
vidSampleStart = 0.0f,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.MALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.FEMALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.MALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.FEMALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.MALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = yesterday.toLocalDate(),
endingDate = yesterday.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.FEMALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.MALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_18_34,
gender = Gender.FEMALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.MALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.RANGE_35_54,
gender = Gender.FEMALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.MALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
),
PrivacyBucketGroup(
measurementConsumerId = "ACME",
startingDate = today.toLocalDate(),
endingDate = today.toLocalDate(),
ageGroup = AgeGroup.ABOVE_54,
gender = Gender.FEMALE,
vidSampleStart = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH,
vidSampleWidth = PrivacyLandscape.PRIVACY_BUCKET_VID_SAMPLE_WIDTH
)
)
}
}
Loading