diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicExperimentEnrollmentConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicExperimentEnrollmentConfiguration.java index 04885c33f..9d9f019a6 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicExperimentEnrollmentConfiguration.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicExperimentEnrollmentConfiguration.java @@ -26,8 +26,8 @@ public class DynamicExperimentEnrollmentConfiguration { /** * What percentage of enrolled UUIDs should the experiment be enabled for. *

- * Unlike {@link this#enrollmentPercentage}, this is not stable by UUID. The same UUID may be - * enrolled/unenrolled across calls. + * Unlike {@link this#enrollmentPercentage}, this is not stable by UUID. The same UUID may be enrolled/unenrolled + * across calls. */ @JsonProperty @Valid @@ -49,6 +49,14 @@ public class DynamicExperimentEnrollmentConfiguration { @NotNull private final UuidSelector uuidSelector = new UuidSelector(); + + /** + * UUIDs that the experiment should always be disabled for. This takes precedence over uuidSelector. + */ + @Valid + @NotNull + private final Set excludedUuids = Collections.emptySet(); + /** * If the UUID is not enrolled via {@link UuidSelector#uuids}, what is the percentage chance it should be enrolled. *

@@ -67,4 +75,9 @@ public class DynamicExperimentEnrollmentConfiguration { public UuidSelector getUuidSelector() { return uuidSelector; } + + public Set getExcludedUuids() { + return excludedUuids; + } } + diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManager.java index cf95dead8..cfecdc8e8 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManager.java @@ -5,11 +5,11 @@ package org.whispersystems.textsecuregcm.experiment; +import com.google.common.annotations.VisibleForTesting; import java.util.Optional; import java.util.Random; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; -import com.google.common.annotations.VisibleForTesting; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicExperimentEnrollmentConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicPreRegistrationExperimentEnrollmentConfiguration; @@ -47,6 +47,9 @@ public class ExperimentEnrollmentManager { } Optional isAccountEnrolled(final UUID accountUuid, DynamicExperimentEnrollmentConfiguration config) { + if (config.getExcludedUuids().contains(accountUuid)) { + return Optional.of(false); + } if (config.getUuidSelector().getUuids().contains(accountUuid)) { final int r = random.nextInt(100); return Optional.of(r < config.getUuidSelector().getUuidEnrollmentPercentage()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManagerTest.java index 45a7fea6c..c3352a166 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManagerTest.java @@ -45,6 +45,7 @@ class ExperimentEnrollmentManagerTest { private Random random; private static final UUID ACCOUNT_UUID = UUID.randomUUID(); + private static final UUID EXCLUDED_UUID = UUID.randomUUID(); private static final String UUID_EXPERIMENT_NAME = "uuid_test"; private static final String E164_AND_UUID_EXPERIMENT_NAME = "e164_uuid_test"; @@ -98,6 +99,12 @@ class ExperimentEnrollmentManagerTest { when(experimentEnrollmentConfiguration.getEnrollmentPercentage()).thenReturn(100); assertTrue(experimentEnrollmentManager.isEnrolled(account.getUuid(), UUID_EXPERIMENT_NAME)); + + when(experimentEnrollmentConfiguration.getExcludedUuids()).thenReturn(Set.of(EXCLUDED_UUID)); + when(experimentEnrollmentConfiguration.getEnrollmentPercentage()).thenReturn(100); + when(uuidSelector.getUuidEnrollmentPercentage()).thenReturn(100); + when(uuidSelector.getUuids()).thenReturn(Set.of(EXCLUDED_UUID)); + assertFalse(experimentEnrollmentManager.isEnrolled(EXCLUDED_UUID, UUID_EXPERIMENT_NAME)); } @Test