mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-22 07:28:02 +01:00
Collapse the feature flag system into the dynamic config system.
This commit is contained in:
committed by
Jon Chambers
parent
d6319aeb92
commit
ff448950ed
@@ -20,79 +20,112 @@ import static org.junit.Assert.*;
|
||||
|
||||
public class DynamicConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void testParseExperimentConfig() throws JsonProcessingException {
|
||||
{
|
||||
final String emptyConfigYaml = "test: true";
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
@Test
|
||||
public void testParseExperimentConfig() throws JsonProcessingException {
|
||||
{
|
||||
final String emptyConfigYaml = "test: true";
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertFalse(emptyConfig.getExperimentEnrollmentConfiguration("test").isPresent());
|
||||
}
|
||||
|
||||
{
|
||||
final String experimentConfigYaml =
|
||||
"experiments:\n" +
|
||||
" percentageOnly:\n" +
|
||||
" enrollmentPercentage: 12\n" +
|
||||
" uuidsAndPercentage:\n" +
|
||||
" enrolledUuids:\n" +
|
||||
" - 717b1c09-ed0b-4120-bb0e-f4697534b8e1\n" +
|
||||
" - 279f264c-56d7-4bbf-b9da-de718ff90903\n" +
|
||||
" enrollmentPercentage: 77\n" +
|
||||
" uuidsOnly:\n" +
|
||||
" enrolledUuids:\n" +
|
||||
" - 71618739-114c-4b1f-bb0d-6478a44eb600";
|
||||
|
||||
final DynamicConfiguration config = DynamicConfigurationManager.OBJECT_MAPPER.readValue(experimentConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertFalse(config.getExperimentEnrollmentConfiguration("unconfigured").isPresent());
|
||||
|
||||
assertTrue(config.getExperimentEnrollmentConfiguration("percentageOnly").isPresent());
|
||||
assertEquals(12, config.getExperimentEnrollmentConfiguration("percentageOnly").get().getEnrollmentPercentage());
|
||||
assertEquals(Collections.emptySet(), config.getExperimentEnrollmentConfiguration("percentageOnly").get().getEnrolledUuids());
|
||||
|
||||
assertTrue(config.getExperimentEnrollmentConfiguration("uuidsAndPercentage").isPresent());
|
||||
assertEquals(77, config.getExperimentEnrollmentConfiguration("uuidsAndPercentage").get().getEnrollmentPercentage());
|
||||
assertEquals(Set.of(UUID.fromString("717b1c09-ed0b-4120-bb0e-f4697534b8e1"), UUID.fromString("279f264c-56d7-4bbf-b9da-de718ff90903")),
|
||||
config.getExperimentEnrollmentConfiguration("uuidsAndPercentage").get().getEnrolledUuids());
|
||||
|
||||
assertTrue(config.getExperimentEnrollmentConfiguration("uuidsOnly").isPresent());
|
||||
assertEquals(0, config.getExperimentEnrollmentConfiguration("uuidsOnly").get().getEnrollmentPercentage());
|
||||
assertEquals(Set.of(UUID.fromString("71618739-114c-4b1f-bb0d-6478a44eb600")),
|
||||
config.getExperimentEnrollmentConfiguration("uuidsOnly").get().getEnrolledUuids());
|
||||
}
|
||||
assertFalse(emptyConfig.getExperimentEnrollmentConfiguration("test").isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRemoteDeprecationConfig() throws JsonProcessingException {
|
||||
{
|
||||
final String emptyConfigYaml = "test: true";
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
{
|
||||
final String experimentConfigYaml =
|
||||
"experiments:\n" +
|
||||
" percentageOnly:\n" +
|
||||
" enrollmentPercentage: 12\n" +
|
||||
" uuidsAndPercentage:\n" +
|
||||
" enrolledUuids:\n" +
|
||||
" - 717b1c09-ed0b-4120-bb0e-f4697534b8e1\n" +
|
||||
" - 279f264c-56d7-4bbf-b9da-de718ff90903\n" +
|
||||
" enrollmentPercentage: 77\n" +
|
||||
" uuidsOnly:\n" +
|
||||
" enrolledUuids:\n" +
|
||||
" - 71618739-114c-4b1f-bb0d-6478a44eb600";
|
||||
|
||||
assertNotNull(emptyConfig.getRemoteDeprecationConfiguration());
|
||||
}
|
||||
final DynamicConfiguration config = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(experimentConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
{
|
||||
final String experimentConfigYaml =
|
||||
"remoteDeprecation:\n" +
|
||||
" minimumVersions:\n" +
|
||||
" IOS: 1.2.3\n" +
|
||||
" ANDROID: 4.5.6\n" +
|
||||
assertFalse(config.getExperimentEnrollmentConfiguration("unconfigured").isPresent());
|
||||
|
||||
" versionsPendingDeprecation:\n" +
|
||||
" DESKTOP: 7.8.9\n" +
|
||||
assertTrue(config.getExperimentEnrollmentConfiguration("percentageOnly").isPresent());
|
||||
assertEquals(12, config.getExperimentEnrollmentConfiguration("percentageOnly").get().getEnrollmentPercentage());
|
||||
assertEquals(Collections.emptySet(),
|
||||
config.getExperimentEnrollmentConfiguration("percentageOnly").get().getEnrolledUuids());
|
||||
|
||||
" blockedVersions:\n" +
|
||||
" DESKTOP:\n" +
|
||||
" - 1.4.0-beta.2";
|
||||
assertTrue(config.getExperimentEnrollmentConfiguration("uuidsAndPercentage").isPresent());
|
||||
assertEquals(77,
|
||||
config.getExperimentEnrollmentConfiguration("uuidsAndPercentage").get().getEnrollmentPercentage());
|
||||
assertEquals(Set.of(UUID.fromString("717b1c09-ed0b-4120-bb0e-f4697534b8e1"),
|
||||
UUID.fromString("279f264c-56d7-4bbf-b9da-de718ff90903")),
|
||||
config.getExperimentEnrollmentConfiguration("uuidsAndPercentage").get().getEnrolledUuids());
|
||||
|
||||
final DynamicConfiguration config = DynamicConfigurationManager.OBJECT_MAPPER.readValue(experimentConfigYaml, DynamicConfiguration.class);
|
||||
final DynamicRemoteDeprecationConfiguration remoteDeprecationConfiguration = config.getRemoteDeprecationConfiguration();
|
||||
|
||||
assertEquals(Map.of(ClientPlatform.IOS, new Semver("1.2.3"), ClientPlatform.ANDROID, new Semver("4.5.6")), remoteDeprecationConfiguration.getMinimumVersions());
|
||||
assertEquals(Map.of(ClientPlatform.DESKTOP, new Semver("7.8.9")), remoteDeprecationConfiguration.getVersionsPendingDeprecation());
|
||||
assertEquals(Map.of(ClientPlatform.DESKTOP, Set.of(new Semver("1.4.0-beta.2"))), remoteDeprecationConfiguration.getBlockedVersions());
|
||||
assertTrue(remoteDeprecationConfiguration.getVersionsPendingBlock().isEmpty());
|
||||
}
|
||||
assertTrue(config.getExperimentEnrollmentConfiguration("uuidsOnly").isPresent());
|
||||
assertEquals(0, config.getExperimentEnrollmentConfiguration("uuidsOnly").get().getEnrollmentPercentage());
|
||||
assertEquals(Set.of(UUID.fromString("71618739-114c-4b1f-bb0d-6478a44eb600")),
|
||||
config.getExperimentEnrollmentConfiguration("uuidsOnly").get().getEnrolledUuids());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRemoteDeprecationConfig() throws JsonProcessingException {
|
||||
{
|
||||
final String emptyConfigYaml = "test: true";
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertNotNull(emptyConfig.getRemoteDeprecationConfiguration());
|
||||
}
|
||||
|
||||
{
|
||||
final String experimentConfigYaml =
|
||||
"remoteDeprecation:\n" +
|
||||
" minimumVersions:\n" +
|
||||
" IOS: 1.2.3\n" +
|
||||
" ANDROID: 4.5.6\n" +
|
||||
|
||||
" versionsPendingDeprecation:\n" +
|
||||
" DESKTOP: 7.8.9\n" +
|
||||
|
||||
" blockedVersions:\n" +
|
||||
" DESKTOP:\n" +
|
||||
" - 1.4.0-beta.2";
|
||||
|
||||
final DynamicConfiguration config = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(experimentConfigYaml, DynamicConfiguration.class);
|
||||
final DynamicRemoteDeprecationConfiguration remoteDeprecationConfiguration = config
|
||||
.getRemoteDeprecationConfiguration();
|
||||
|
||||
assertEquals(Map.of(ClientPlatform.IOS, new Semver("1.2.3"), ClientPlatform.ANDROID, new Semver("4.5.6")),
|
||||
remoteDeprecationConfiguration.getMinimumVersions());
|
||||
assertEquals(Map.of(ClientPlatform.DESKTOP, new Semver("7.8.9")),
|
||||
remoteDeprecationConfiguration.getVersionsPendingDeprecation());
|
||||
assertEquals(Map.of(ClientPlatform.DESKTOP, Set.of(new Semver("1.4.0-beta.2"))),
|
||||
remoteDeprecationConfiguration.getBlockedVersions());
|
||||
assertTrue(remoteDeprecationConfiguration.getVersionsPendingBlock().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseFeatureFlags() throws JsonProcessingException {
|
||||
{
|
||||
final String emptyConfigYaml = "test: true";
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertTrue(emptyConfig.getActiveFeatureFlags().isEmpty());
|
||||
}
|
||||
|
||||
{
|
||||
final String emptyConfigYaml =
|
||||
"featureFlags:\n"
|
||||
+ " - testFlag";
|
||||
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertTrue(emptyConfig.getActiveFeatureFlags().contains("testFlag"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.opentable.db.postgres.embedded.LiquibasePreparer;
|
||||
import com.opentable.db.postgres.junit.EmbeddedPostgresRules;
|
||||
import com.opentable.db.postgres.junit.PreparedDbRule;
|
||||
import org.jdbi.v3.core.Jdbi;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class FeatureFlagsManagerTest {
|
||||
|
||||
private FeatureFlagsManager featureFlagsManager;
|
||||
|
||||
@Rule
|
||||
public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(LiquibasePreparer.forClasspathLocation("accountsdb.xml"));
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final FaultTolerantDatabase database = new FaultTolerantDatabase("featureFlagsTest",
|
||||
Jdbi.create(db.getTestDatabase()),
|
||||
new CircuitBreakerConfiguration());
|
||||
|
||||
featureFlagsManager = new FeatureFlagsManager(new FeatureFlags(database), mock(ScheduledExecutorService.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFeatureFlagActive() {
|
||||
final String flagName = "testFlag";
|
||||
|
||||
assertFalse(featureFlagsManager.isFeatureFlagActive(flagName));
|
||||
|
||||
featureFlagsManager.setFeatureFlag(flagName, true);
|
||||
assertTrue(featureFlagsManager.isFeatureFlagActive(flagName));
|
||||
|
||||
featureFlagsManager.setFeatureFlag(flagName, false);
|
||||
assertFalse(featureFlagsManager.isFeatureFlagActive(flagName));
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.opentable.db.postgres.embedded.LiquibasePreparer;
|
||||
import com.opentable.db.postgres.junit.EmbeddedPostgresRules;
|
||||
import com.opentable.db.postgres.junit.PreparedDbRule;
|
||||
import org.jdbi.v3.core.Jdbi;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class FeatureFlagsTest {
|
||||
|
||||
@Rule
|
||||
public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(LiquibasePreparer.forClasspathLocation("accountsdb.xml"));
|
||||
|
||||
private FeatureFlags featureFlags;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final FaultTolerantDatabase database = new FaultTolerantDatabase("featureFlagsTest",
|
||||
Jdbi.create(db.getTestDatabase()),
|
||||
new CircuitBreakerConfiguration());
|
||||
|
||||
this.featureFlags = new FeatureFlags(database);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFlagIsFlagActive() {
|
||||
assertTrue(featureFlags.getFeatureFlags().isEmpty());
|
||||
|
||||
featureFlags.setFlag("testFlag", true);
|
||||
assertEquals(Map.of("testFlag", true), featureFlags.getFeatureFlags());
|
||||
|
||||
featureFlags.setFlag("testFlag", false);
|
||||
assertEquals(Map.of("testFlag", false), featureFlags.getFeatureFlags());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteFlag() {
|
||||
assertTrue(featureFlags.getFeatureFlags().isEmpty());
|
||||
|
||||
featureFlags.setFlag("testFlag", true);
|
||||
assertEquals(Map.of("testFlag", true), featureFlags.getFeatureFlags());
|
||||
|
||||
featureFlags.deleteFlag("testFlag");
|
||||
assertTrue(featureFlags.getFeatureFlags().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVacuum() {
|
||||
featureFlags.setFlag("testFlag", true);
|
||||
assertEquals(Map.of("testFlag", true), featureFlags.getFeatureFlags());
|
||||
|
||||
featureFlags.vacuum();
|
||||
assertEquals(Map.of("testFlag", true), featureFlags.getFeatureFlags());
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.metrics.PushLatencyManager;
|
||||
import org.whispersystems.textsecuregcm.redis.AbstractRedisClusterTest;
|
||||
@@ -63,11 +64,12 @@ public class MessagePersisterIntegrationTest extends AbstractRedisClusterTest {
|
||||
|
||||
final MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(messagesDynamoDbRule.getDynamoDB(), MessagesDynamoDbRule.TABLE_NAME, Duration.ofDays(7));
|
||||
final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
final DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||
|
||||
notificationExecutorService = Executors.newSingleThreadExecutor();
|
||||
messagesCache = new MessagesCache(getRedisCluster(), getRedisCluster(), notificationExecutorService);
|
||||
messagesManager = new MessagesManager(messagesDynamoDb, messagesCache, mock(PushLatencyManager.class));
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager, mock(FeatureFlagsManager.class), PERSIST_DELAY);
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager, dynamicConfigurationManager, PERSIST_DELAY);
|
||||
|
||||
account = mock(Account.class);
|
||||
|
||||
@@ -76,6 +78,7 @@ public class MessagePersisterIntegrationTest extends AbstractRedisClusterTest {
|
||||
when(account.getNumber()).thenReturn("+18005551234");
|
||||
when(account.getUuid()).thenReturn(accountUuid);
|
||||
when(accountsManager.get(accountUuid)).thenReturn(Optional.of(account));
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
|
||||
messagesCache.start();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.redis.AbstractRedisClusterTest;
|
||||
|
||||
@@ -54,7 +55,8 @@ public class MessagePersisterTest extends AbstractRedisClusterTest {
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
final DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||
|
||||
messagesDynamoDb = mock(MessagesDynamoDb.class);
|
||||
accountsManager = mock(AccountsManager.class);
|
||||
@@ -63,10 +65,11 @@ public class MessagePersisterTest extends AbstractRedisClusterTest {
|
||||
|
||||
when(accountsManager.get(DESTINATION_ACCOUNT_UUID)).thenReturn(Optional.of(account));
|
||||
when(account.getNumber()).thenReturn(DESTINATION_ACCOUNT_NUMBER);
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
|
||||
notificationExecutorService = Executors.newSingleThreadExecutor();
|
||||
messagesCache = new MessagesCache(getRedisCluster(), getRedisCluster(), notificationExecutorService);
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager, mock(FeatureFlagsManager.class), PERSIST_DELAY);
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager, dynamicConfigurationManager, PERSIST_DELAY);
|
||||
|
||||
doAnswer(invocation -> {
|
||||
final UUID destinationUuid = invocation.getArgument(0);
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class DeleteFeatureFlagTaskTest {
|
||||
|
||||
private FeatureFlagsManager featureFlagsManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
featureFlagsManager = mock(FeatureFlagsManager.class);
|
||||
|
||||
when(featureFlagsManager.getAllFlags()).thenReturn(Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute() {
|
||||
final DeleteFeatureFlagTask task = new DeleteFeatureFlagTask(featureFlagsManager);
|
||||
|
||||
task.execute(Map.of("flag", List.of("test-flag-1", "test-flag-2")), mock(PrintWriter.class));
|
||||
verify(featureFlagsManager).deleteFeatureFlag("test-flag-1");
|
||||
verify(featureFlagsManager).deleteFeatureFlag("test-flag-2");
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SetFeatureFlagTaskTest {
|
||||
|
||||
private FeatureFlagsManager featureFlagsManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
featureFlagsManager = mock(FeatureFlagsManager.class);
|
||||
|
||||
when(featureFlagsManager.getAllFlags()).thenReturn(Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute() {
|
||||
final SetFeatureFlagTask task = new SetFeatureFlagTask(featureFlagsManager);
|
||||
|
||||
task.execute(Map.of("flag", List.of("test-flag"), "active", List.of("true")), mock(PrintWriter.class));
|
||||
|
||||
verify(featureFlagsManager).setFeatureFlag("test-flag", true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user