diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicPreRegistrationExperimentEnrollmentConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicPreRegistrationExperimentEnrollmentConfiguration.java index 4a5eae09c..d81b1595e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicPreRegistrationExperimentEnrollmentConfiguration.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicPreRegistrationExperimentEnrollmentConfiguration.java @@ -20,12 +20,16 @@ public class DynamicPreRegistrationExperimentEnrollmentConfiguration { @JsonProperty @Valid - private Set excludedCountryCodes = Collections.emptySet(); + private Set excludedE164s = Collections.emptySet(); @JsonProperty @Valid private Set includedCountryCodes = Collections.emptySet(); + @JsonProperty + @Valid + private Set excludedCountryCodes = Collections.emptySet(); + @JsonProperty @Valid @Min(0) @@ -36,14 +40,18 @@ public class DynamicPreRegistrationExperimentEnrollmentConfiguration { return enrolledE164s; } - public Set getExcludedCountryCodes() { - return excludedCountryCodes; + public Set getExcludedE164s() { + return excludedE164s; } public Set getIncludedCountryCodes() { return includedCountryCodes; } + public Set getExcludedCountryCodes() { + return excludedCountryCodes; + } + public int getEnrollmentPercentage() { return enrollmentPercentage; } 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 5c02276ee..f57fb0c96 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManager.java @@ -47,6 +47,10 @@ public class ExperimentEnrollmentManager { return true; } + if (config.getExcludedE164s().contains(e164)) { + return false; + } + { final String countryCode = Util.getCountryCode(e164); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java index a6e16889f..f86639390 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java @@ -94,6 +94,9 @@ class DynamicConfigurationTest { " enrolledE164s:\n" + " - +120255551212\n" + " - +3655323174\n" + + " excludedE164s:\n" + + " - +120255551213\n" + + " - +3655323175\n" + " enrollmentPercentage: 46\n" + " excludedCountryCodes:\n" + " - 47\n" + @@ -118,6 +121,8 @@ class DynamicConfigurationTest { percentageOnly.get().getEnrollmentPercentage()); assertEquals(Collections.emptySet(), percentageOnly.get().getEnrolledE164s()); + assertEquals(Collections.emptySet(), + percentageOnly.get().getExcludedE164s()); } { @@ -129,6 +134,8 @@ class DynamicConfigurationTest { e164sCountryCodesAndPercentage.get().getEnrollmentPercentage()); assertEquals(Set.of("+120255551212", "+3655323174"), e164sCountryCodesAndPercentage.get().getEnrolledE164s()); + assertEquals(Set.of("+120255551213", "+3655323175"), + e164sCountryCodesAndPercentage.get().getExcludedE164s()); assertEquals(Set.of("47"), e164sCountryCodesAndPercentage.get().getExcludedCountryCodes()); assertEquals(Set.of("56"), @@ -142,6 +149,7 @@ class DynamicConfigurationTest { assertEquals(0, e164sAndExcludedCodes.get().getEnrollmentPercentage()); assertEquals(Set.of("+120255551212"), e164sAndExcludedCodes.get().getEnrolledE164s()); + assertTrue(e164sAndExcludedCodes.get().getExcludedE164s().isEmpty()); assertEquals(Set.of("47"), e164sAndExcludedCodes.get().getExcludedCountryCodes()); } 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 f07ee3e01..9f079afb6 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentEnrollmentManagerTest.java @@ -5,7 +5,9 @@ package org.whispersystems.textsecuregcm.experiment; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -37,7 +39,8 @@ class ExperimentEnrollmentManagerTest { private static final UUID ACCOUNT_UUID = UUID.randomUUID(); private static final String UUID_EXPERIMENT_NAME = "uuid_test"; - private static final String E164 = "+12025551212"; + private static final String ENROLLED_164 = "+12025551212"; + private static final String EXCLUDED_164 = "+18005551212"; private static final String E164_EXPERIMENT_NAME = "e164_test"; @BeforeEach @@ -82,35 +85,40 @@ class ExperimentEnrollmentManagerTest { @ParameterizedTest @MethodSource void testIsEnrolled_PreRegistrationExperiment(final String e164, final String experimentName, - final Set enrolledE164s, final Set includedCountryCodes, final Set excludedCountryCodes, + final Set enrolledE164s, final Set excludedE164s, final Set includedCountryCodes, + final Set excludedCountryCodes, final int enrollmentPercentage, - final boolean expectedEnrolled, final String message) { + final boolean expectEnrolled, final String message) { when(preRegistrationExperimentEnrollmentConfiguration.getEnrolledE164s()).thenReturn(enrolledE164s); + when(preRegistrationExperimentEnrollmentConfiguration.getExcludedE164s()).thenReturn(excludedE164s); when(preRegistrationExperimentEnrollmentConfiguration.getEnrollmentPercentage()).thenReturn(enrollmentPercentage); when(preRegistrationExperimentEnrollmentConfiguration.getIncludedCountryCodes()).thenReturn(includedCountryCodes); when(preRegistrationExperimentEnrollmentConfiguration.getExcludedCountryCodes()).thenReturn(excludedCountryCodes); - assertEquals(message, expectedEnrolled, experimentEnrollmentManager.isEnrolled(e164, experimentName)); + assertEquals(expectEnrolled, experimentEnrollmentManager.isEnrolled(e164, experimentName), message); } + @SuppressWarnings("unused") static Stream testIsEnrolled_PreRegistrationExperiment() { return Stream.of( - Arguments.of(E164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), - Collections.emptySet(), 0, false, "default configuration expects no enrollment"), - Arguments - .of(E164, E164_EXPERIMENT_NAME + "-unrelated-experiment", Collections.emptySet(), Collections.emptySet(), - Collections.emptySet(), 0, false, "unknown experiment expects no enrollment"), - Arguments.of(E164, E164_EXPERIMENT_NAME, Set.of(E164), Collections.emptySet(), - Collections.emptySet(), 0, true, "explicitly enrolled E164 overrides 0% rollout"), - Arguments.of(E164, E164_EXPERIMENT_NAME, Set.of(E164), Collections.emptySet(), - Set.of("1"), 0, true, "explicitly enrolled E164 overrides excluded country code"), - Arguments.of(E164, E164_EXPERIMENT_NAME, Collections.emptySet(), Set.of("1"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), + Collections.emptySet(), Collections.emptySet(), 0, false, "default configuration expects no enrollment"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME + "-unrelated-experiment", Collections.emptySet(), + Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), 0, false, + "unknown experiment expects no enrollment"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME, Set.of(ENROLLED_164), Set.of(EXCLUDED_164), + Collections.emptySet(), Collections.emptySet(), 0, true, "explicitly enrolled E164 overrides 0% rollout"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME, Set.of(ENROLLED_164), Set.of(EXCLUDED_164), + Collections.emptySet(), Set.of("1"), 0, true, "explicitly enrolled E164 overrides excluded country code"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), Set.of("1"), Collections.emptySet(), 0, true, "included country code overrides 0% rollout"), - Arguments.of(E164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), - Set.of("1"), 100, false, "excluded country code overrides 100% rollout"), - Arguments.of(E164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), - Collections.emptySet(), 100, true, "enrollment expected for 100% rollout") + Arguments.of(EXCLUDED_164, E164_EXPERIMENT_NAME, Collections.emptySet(), Set.of(EXCLUDED_164), Set.of("1"), + Collections.emptySet(), 100, false, "excluded E164 overrides 100% rollout"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), + Collections.emptySet(), Set.of("1"), 100, false, "excluded country code overrides 100% rollout"), + Arguments.of(ENROLLED_164, E164_EXPERIMENT_NAME, Collections.emptySet(), Collections.emptySet(), + Collections.emptySet(), Collections.emptySet(), 100, true, "enrollment expected for 100% rollout") ); } }