Add nomulus tool command for FeatureFlags (#2480)

* Add registryTool commands for FeatureFlags

* Fix merge conflicts

* Add required parameters and inject mapper

* Use optionals in cache to negative cahe missing objects

* Fix spelling

* Change back to bulk load in cache

* Add FeatureName enum

* Change variable name

* Use FeatureName in main parameter
This commit is contained in:
sarahcaseybot
2024-07-09 20:05:15 +00:00
committed by GitHub
parent 092e3dca47
commit 74f0a8dd7b
16 changed files with 750 additions and 111 deletions
@@ -15,6 +15,9 @@
package google.registry.model.common;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_PROHIBITED;
import static google.registry.model.common.FeatureFlag.FeatureName.TEST_FEATURE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
import static google.registry.testing.DatabaseHelper.loadByEntity;
@@ -42,8 +45,8 @@ public class FeatureFlagTest extends EntityTestCase {
void testSuccess_persistence() {
FeatureFlag featureFlag =
new FeatureFlag.Builder()
.setFeatureName("testFlag")
.setStatus(
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
@@ -58,15 +61,15 @@ public class FeatureFlagTest extends EntityTestCase {
void testSuccess_getSingleFlag() {
FeatureFlag featureFlag =
new FeatureFlag.Builder()
.setFeatureName("testFlag")
.setStatus(
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
.build())
.build();
persistResource(featureFlag);
assertThat(FeatureFlag.get("testFlag")).isEqualTo(featureFlag);
assertThat(FeatureFlag.get(TEST_FEATURE)).isEqualTo(featureFlag);
}
@Test
@@ -74,8 +77,8 @@ public class FeatureFlagTest extends EntityTestCase {
FeatureFlag featureFlag1 =
persistResource(
new FeatureFlag.Builder()
.setFeatureName("testFlag1")
.setStatus(
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
@@ -84,8 +87,8 @@ public class FeatureFlagTest extends EntityTestCase {
FeatureFlag featureFlag2 =
persistResource(
new FeatureFlag.Builder()
.setFeatureName("testFlag2")
.setStatus(
.setFeatureName(MINIMUM_DATASET_CONTACTS_OPTIONAL)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(3), INACTIVE)
@@ -94,14 +97,18 @@ public class FeatureFlagTest extends EntityTestCase {
FeatureFlag featureFlag3 =
persistResource(
new FeatureFlag.Builder()
.setFeatureName("testFlag3")
.setStatus(
.setFeatureName(MINIMUM_DATASET_CONTACTS_PROHIBITED)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.build())
.build());
ImmutableSet<FeatureFlag> featureFlags =
FeatureFlag.get(ImmutableSet.of("testFlag1", "testFlag2", "testFlag3"));
FeatureFlag.getAll(
ImmutableSet.of(
TEST_FEATURE,
MINIMUM_DATASET_CONTACTS_OPTIONAL,
MINIMUM_DATASET_CONTACTS_PROHIBITED));
assertThat(featureFlags.size()).isEqualTo(3);
assertThat(featureFlags).containsExactly(featureFlag1, featureFlag2, featureFlag3);
}
@@ -110,8 +117,8 @@ public class FeatureFlagTest extends EntityTestCase {
void testFailure_getMultipleFlagsOneMissing() {
persistResource(
new FeatureFlag.Builder()
.setFeatureName("testFlag1")
.setStatus(
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
@@ -119,8 +126,8 @@ public class FeatureFlagTest extends EntityTestCase {
.build());
persistResource(
new FeatureFlag.Builder()
.setFeatureName("testFlag2")
.setStatus(
.setFeatureName(MINIMUM_DATASET_CONTACTS_OPTIONAL)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(3), INACTIVE)
@@ -129,74 +136,48 @@ public class FeatureFlagTest extends EntityTestCase {
FeatureFlagNotFoundException thrown =
assertThrows(
FeatureFlagNotFoundException.class,
() -> FeatureFlag.get(ImmutableSet.of("missingFlag", "testFlag1", "testFlag2")));
() ->
FeatureFlag.getAll(
ImmutableSet.of(
TEST_FEATURE,
MINIMUM_DATASET_CONTACTS_OPTIONAL,
MINIMUM_DATASET_CONTACTS_PROHIBITED)));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("No feature flag object(s) found for missingFlag");
.isEqualTo("No feature flag object(s) found for MINIMUM_DATASET_CONTACTS_PROHIBITED");
}
@Test
void testFailure_featureFlagNotPresent() {
FeatureFlagNotFoundException thrown =
assertThrows(FeatureFlagNotFoundException.class, () -> FeatureFlag.get("fakeFlag"));
assertThat(thrown).hasMessageThat().isEqualTo("No feature flag object(s) found for fakeFlag");
}
@Test
void testFailure_resetFeatureName() {
FeatureFlag featureFlag =
new FeatureFlag.Builder()
.setFeatureName("testFlag")
.setStatus(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
.build())
.build();
IllegalStateException thrown =
assertThrows(
IllegalStateException.class,
() -> featureFlag.asBuilder().setFeatureName("differentName"));
assertThat(thrown).hasMessageThat().isEqualTo("Feature name can only be set once");
assertThrows(FeatureFlagNotFoundException.class, () -> FeatureFlag.get(TEST_FEATURE));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("No feature flag object(s) found for TEST_FEATURE");
}
@Test
void testFailure_nullFeatureName() {
FeatureFlag.Builder featureFlagBuilder =
new FeatureFlag.Builder()
.setStatus(
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
.build());
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> featureFlagBuilder.build());
assertThat(thrown).hasMessageThat().isEqualTo("Feature name must not be null or empty");
}
@Test
void testFailure_emptyFeatureName() {
FeatureFlag.Builder featureFlagBuilder =
new FeatureFlag.Builder()
.setFeatureName("")
.setStatus(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
.build());
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> featureFlagBuilder.build());
assertThat(thrown).hasMessageThat().isEqualTo("Feature name must not be null or empty");
assertThat(thrown).hasMessageThat().isEqualTo("FeatureName cannot be null");
}
@Test
void testFailure_invalidStatusMap() {
FeatureFlag.Builder featureFlagBuilder = new FeatureFlag.Builder().setFeatureName("testFlag");
FeatureFlag.Builder featureFlagBuilder = new FeatureFlag.Builder().setFeatureName(TEST_FEATURE);
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
featureFlagBuilder.setStatus(
featureFlagBuilder.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(DateTime.now(UTC).plusWeeks(8), ACTIVE)
.build()));
@@ -0,0 +1,208 @@
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_PROHIBITED;
import static google.registry.model.common.FeatureFlag.FeatureName.TEST_FEATURE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.model.common.FeatureFlag;
import google.registry.model.common.FeatureFlag.FeatureStatus;
import google.registry.model.common.TimedTransitionProperty;
import google.registry.testing.FakeClock;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link ConfigureFeatureFlagCommand}. */
public class ConfigureFeatureFlagCommandTest extends CommandTestCase<ConfigureFeatureFlagCommand> {
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
@Test
void testCreate() throws Exception {
DateTime featureStart = clock.nowUtc().plusWeeks(2);
runCommandForced(
"TEST_FEATURE",
"--status_map",
String.format("%s=INACTIVE,%s=ACTIVE", START_OF_TIME, featureStart));
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(1);
}
@Test
void testCreate_multipleFlags() throws Exception {
DateTime featureStart = clock.nowUtc().plusWeeks(2);
runCommandForced(
"TEST_FEATURE",
"MINIMUM_DATASET_CONTACTS_OPTIONAL",
"MINIMUM_DATASET_CONTACTS_PROHIBITED",
"--status_map",
String.format("%s=INACTIVE,%s=ACTIVE", START_OF_TIME, featureStart));
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.get(MINIMUM_DATASET_CONTACTS_OPTIONAL).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.get(MINIMUM_DATASET_CONTACTS_PROHIBITED).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(3);
}
@Test
void testUpdate() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.build())
.build());
DateTime featureStart = clock.nowUtc().plusWeeks(6);
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(ImmutableSortedMap.of(START_OF_TIME, INACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(1);
runCommandForced(
"TEST_FEATURE",
"--status_map",
String.format("%s=INACTIVE,%s=ACTIVE", START_OF_TIME, featureStart));
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(1);
}
@Test
void testConfigure_multipleFlags() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.build())
.build());
DateTime featureStart = clock.nowUtc().plusWeeks(6);
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(ImmutableSortedMap.of(START_OF_TIME, INACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(1);
runCommandForced(
"TEST_FEATURE",
"MINIMUM_DATASET_CONTACTS_OPTIONAL",
"MINIMUM_DATASET_CONTACTS_PROHIBITED",
"--status_map",
String.format("%s=INACTIVE,%s=ACTIVE", START_OF_TIME, featureStart));
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.get(MINIMUM_DATASET_CONTACTS_OPTIONAL).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.get(MINIMUM_DATASET_CONTACTS_PROHIBITED).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(
ImmutableSortedMap.of(START_OF_TIME, INACTIVE, featureStart, ACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(3);
}
@Test
void testCreate_invalidFeatureName() throws Exception {
ParameterException thrown =
assertThrows(
ParameterException.class,
() ->
runCommandForced(
"INVALID_NAME", "--status_map", String.format("%s=ACTIVE", START_OF_TIME)));
assertThat(thrown)
.hasMessageThat()
.contains("Invalid value for [Main class] parameter. Allowed values");
}
@Test
void testCreate_invalidStatusMap() throws Exception {
DateTime featureStart = clock.nowUtc().plusWeeks(2);
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
runCommandForced(
"TEST_FEATURE", "--status_map", String.format("%s=ACTIVE", featureStart)));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Must provide transition entry for the start of time (Unix Epoch)");
}
@Test
void testUpdate_invalidStatusMap() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.build())
.build());
DateTime featureStart = clock.nowUtc().plusWeeks(6);
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
.isEqualTo(
TimedTransitionProperty.fromValueMap(ImmutableSortedMap.of(START_OF_TIME, INACTIVE)));
assertThat(FeatureFlag.getAllUncached()).hasSize(1);
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
runCommandForced(
"TEST_FEATURE", "--status_map", String.format("%s=ACTIVE", featureStart)));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Must provide transition entry for the start of time (Unix Epoch)");
}
}
@@ -0,0 +1,130 @@
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.FeatureName.TEST_FEATURE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.model.EntityYamlUtils;
import google.registry.model.common.FeatureFlag;
import google.registry.model.common.FeatureFlag.FeatureFlagNotFoundException;
import google.registry.model.common.FeatureFlag.FeatureStatus;
import google.registry.testing.FakeClock;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link GetFeatureFlagCommand}. */
public class GetFeatureFlagCommandTest extends CommandTestCase<GetFeatureFlagCommand> {
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
@BeforeEach
void beforeEach() {
command.objectMapper = EntityYamlUtils.createObjectMapper();
}
@Test
void testSuccess() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(clock.nowUtc().plusWeeks(8), ACTIVE)
.build())
.build());
runCommand("TEST_FEATURE");
assertInStdout(
"featureName: \"TEST_FEATURE\"\n"
+ "status:\n"
+ " \"1970-01-01T00:00:00.000Z\": \"INACTIVE\"\n"
+ " \"2000-02-26T00:00:00.000Z\": \"ACTIVE\"");
}
@Test
void testSuccess_multipleArguments() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(clock.nowUtc().plusWeeks(8), ACTIVE)
.build())
.build());
persistResource(
new FeatureFlag.Builder()
.setFeatureName(MINIMUM_DATASET_CONTACTS_OPTIONAL)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(clock.nowUtc().plusWeeks(3), ACTIVE)
.put(clock.nowUtc().plusWeeks(6), INACTIVE)
.build())
.build());
runCommand("TEST_FEATURE", "MINIMUM_DATASET_CONTACTS_OPTIONAL");
assertInStdout(
"featureName: \"TEST_FEATURE\"\n"
+ "status:\n"
+ " \"1970-01-01T00:00:00.000Z\": \"INACTIVE\"\n"
+ " \"2000-02-26T00:00:00.000Z\": \"ACTIVE\""
+ "\n\n"
+ "featureName: \"MINIMUM_DATASET_CONTACTS_OPTIONAL\"\n"
+ "status:\n"
+ " \"1970-01-01T00:00:00.000Z\": \"INACTIVE\"\n"
+ " \"2000-01-22T00:00:00.000Z\": \"ACTIVE\"\n"
+ " \"2000-02-12T00:00:00.000Z\": \"INACTIVE\"");
}
@Test
void testFailure_featureFlagDoesNotExist() {
FeatureFlagNotFoundException thrown =
assertThrows(FeatureFlagNotFoundException.class, () -> runCommand("TEST_FEATURE"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("No feature flag object(s) found for TEST_FEATURE");
}
@Test
void testFailure_oneFlagDoesNotExist() {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(clock.nowUtc().plusWeeks(8), ACTIVE)
.build())
.build());
assertThrows(
FeatureFlagNotFoundException.class,
() -> runCommand("TEST_FEATURE", "MINIMUM_DATASET_CONTACTS_OPTIONAL"));
}
@Test
void testFailure_noTldName() {
assertThrows(ParameterException.class, this::runCommand);
}
}
@@ -0,0 +1,89 @@
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.tools;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_PROHIBITED;
import static google.registry.model.common.FeatureFlag.FeatureName.TEST_FEATURE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.TestDataHelper.loadFile;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.model.EntityYamlUtils;
import google.registry.model.common.FeatureFlag;
import google.registry.model.common.FeatureFlag.FeatureStatus;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class ListFeatureFlagsCommandTest extends CommandTestCase<ListFeatureFlagsCommand> {
@BeforeEach
void beforeEach() {
command.mapper = EntityYamlUtils.createObjectMapper();
fakeClock.setTo(DateTime.parse("1984-12-21T06:07:08.789Z"));
}
@Test
void testSuccess_oneFlag() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(fakeClock.nowUtc().plusWeeks(8), ACTIVE)
.build())
.build());
runCommand();
assertInStdout(loadFile(getClass(), "oneFlag.yaml"));
}
@Test
void test_success_manyFlags() throws Exception {
persistResource(
new FeatureFlag.Builder()
.setFeatureName(TEST_FEATURE)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(fakeClock.nowUtc().plusWeeks(8), ACTIVE)
.build())
.build());
persistResource(
new FeatureFlag.Builder()
.setFeatureName(MINIMUM_DATASET_CONTACTS_OPTIONAL)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, INACTIVE)
.put(fakeClock.nowUtc().plusWeeks(1), ACTIVE)
.put(fakeClock.nowUtc().plusWeeks(8), INACTIVE)
.put(fakeClock.nowUtc().plusWeeks(10), ACTIVE)
.build())
.build());
persistResource(
new FeatureFlag.Builder()
.setFeatureName(MINIMUM_DATASET_CONTACTS_PROHIBITED)
.setStatusMap(
ImmutableSortedMap.<DateTime, FeatureStatus>naturalOrder()
.put(START_OF_TIME, ACTIVE)
.build())
.build());
runCommand();
assertInStdout(loadFile(getClass(), "threeFlags.yaml"));
}
}
@@ -0,0 +1,4 @@
featureName: "TEST_FEATURE"
status:
"1970-01-01T00:00:00.000Z": "INACTIVE"
"1985-02-15T06:07:08.789Z": "ACTIVE"
@@ -0,0 +1,15 @@
featureName: "TEST_FEATURE"
status:
"1970-01-01T00:00:00.000Z": "INACTIVE"
"1985-02-15T06:07:08.789Z": "ACTIVE"
featureName: "MINIMUM_DATASET_CONTACTS_OPTIONAL"
status:
"1970-01-01T00:00:00.000Z": "INACTIVE"
"1984-12-28T06:07:08.789Z": "ACTIVE"
"1985-02-15T06:07:08.789Z": "INACTIVE"
"1985-03-01T06:07:08.789Z": "ACTIVE"
featureName: "MINIMUM_DATASET_CONTACTS_PROHIBITED"
status:
"1970-01-01T00:00:00.000Z": "ACTIVE"