mirror of
https://github.com/google/nomulus
synced 2026-07-24 00:52:42 +00:00
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:
@@ -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"
|
||||
Reference in New Issue
Block a user