mirror of
https://github.com/google/nomulus
synced 2026-03-26 20:35:18 +00:00
Activate Fee tag normalization in Non-Prod (#2963)
For all flows that use Fee extensions, normalize the fee tags in all non-prod environments. For flows that do not use fee extensions but with fee tags in the header, e.g., HostInfo flows, normalization is not performed.
This commit is contained in:
@@ -20,9 +20,14 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.FeeExtensionXmlTagNormalizer;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.fee.FeeCheckResponseExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.fee06.FeeInfoResponseExtensionV06;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import google.registry.xml.XmlException;
|
||||
@@ -98,8 +103,31 @@ public class EppXmlTransformer {
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
private static boolean hasFeeExtension(EppOutput eppOutput) {
|
||||
if (!eppOutput.isResponse()) {
|
||||
return false;
|
||||
}
|
||||
return eppOutput.getResponse().getExtensions().stream()
|
||||
.map(EppResponse.ResponseExtension::getClass)
|
||||
.filter(EppXmlTransformer::isFeeExtension)
|
||||
.findAny()
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isFeeExtension(Class<?> clazz) {
|
||||
return FeeCheckResponseExtension.class.isAssignableFrom(clazz)
|
||||
|| FeeTransformResponseExtension.class.isAssignableFrom(clazz)
|
||||
|| FeeInfoResponseExtensionV06.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public static byte[] marshal(EppOutput root, ValidationMode validation) throws XmlException {
|
||||
return marshal(OUTPUT_TRANSFORMER, root, validation);
|
||||
byte[] bytes = marshal(OUTPUT_TRANSFORMER, root, validation);
|
||||
if (!RegistryEnvironment.PRODUCTION.equals(RegistryEnvironment.get())
|
||||
&& hasFeeExtension(root)) {
|
||||
return FeeExtensionXmlTagNormalizer.normalize(new String(bytes, UTF_8)).getBytes(UTF_8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -17,8 +17,10 @@ package google.registry.flows;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.flows.FeeExtensionXmlTagNormalizer.feeExtensionInUseRegex;
|
||||
import static google.registry.flows.FeeExtensionXmlTagNormalizer.normalize;
|
||||
import static google.registry.flows.FlowTestCase.verifyFeeTagNormalized;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.validateOutput;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -41,6 +43,13 @@ class FeeExtensionXmlTagNormalizerTest {
|
||||
assertThat(normalized).isEqualTo(xml);
|
||||
}
|
||||
|
||||
@Test
|
||||
void normalize_greetingUnchanged() throws Exception {
|
||||
String xml = loadFile(getClass(), "greeting.xml");
|
||||
String normalized = normalize(xml);
|
||||
assertThat(normalized).isEqualTo(xml);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "normalize_withFeeExtension-{0}")
|
||||
@MethodSource("provideTestCombinations")
|
||||
@SuppressWarnings("unused") // Parameter 'name' is part of test case name
|
||||
@@ -55,6 +64,28 @@ class FeeExtensionXmlTagNormalizerTest {
|
||||
assertThat(normalized).isEqualTo(expected);
|
||||
}
|
||||
|
||||
// Piggyback tests for FlowTestCase.verifyFeeTagNormalized here.
|
||||
@ParameterizedTest(name = "verifyFeeTagNormalized-{0}")
|
||||
@MethodSource("provideTestCombinations")
|
||||
@SuppressWarnings("unused") // Parameter 'name' is part of test case name
|
||||
void verifyFeeTagNormalized_success(
|
||||
String name, String inputXmlFilename, String expectedXmlFilename) throws Exception {
|
||||
String original = loadFile(getClass(), inputXmlFilename);
|
||||
String expected = loadFile(getClass(), expectedXmlFilename);
|
||||
|
||||
if (name.equals("v06")) {
|
||||
// Fee-06 already uses 'fee'. Non-normalized tags only appear in header.
|
||||
verifyFeeTagNormalized(original);
|
||||
} else {
|
||||
assertThrows(
|
||||
AssertionError.class,
|
||||
() -> {
|
||||
verifyFeeTagNormalized(original);
|
||||
});
|
||||
}
|
||||
verifyFeeTagNormalized(expected);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static Stream<Arguments> provideTestCombinations() {
|
||||
return Stream.of(
|
||||
|
||||
@@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.flows.FlowUtils.marshalWithLenientRetry;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.marshal;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.stripBillingEventId;
|
||||
@@ -55,6 +56,7 @@ import google.registry.xml.ValidationMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -284,6 +286,7 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
Arrays.toString(marshal(output, ValidationMode.LENIENT))),
|
||||
e);
|
||||
}
|
||||
verifyFeeTagNormalized(new String(marshalWithLenientRetry(output), UTF_8));
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -298,4 +301,14 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
public EppOutput runFlowAssertResponse(String xml, String... ignoredPaths) throws Exception {
|
||||
return runFlowAssertResponse(CommitMode.LIVE, UserPrivileges.NORMAL, xml, ignoredPaths);
|
||||
}
|
||||
|
||||
// Pattern for non-normalized tags in use. Occurrences in namespace declarations ignored.
|
||||
private static final Pattern NON_NORMALIZED_FEE_TAGS =
|
||||
Pattern.compile("\\bfee11:|\\bfee12:|\\bfee_1_00:");
|
||||
|
||||
static void verifyFeeTagNormalized(String xml) {
|
||||
assertWithMessage("Unexpected un-normalized Fee tags found in message.")
|
||||
.that(NON_NORMALIZED_FEE_TAGS.matcher(xml).find())
|
||||
.isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,48 @@
|
||||
package google.registry.model.eppcommon;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.isFeeExtension;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
|
||||
import static google.registry.testing.TestDataHelper.loadBytes;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.bulktoken.BulkTokenResponseExtension;
|
||||
import google.registry.model.domain.launch.LaunchCheckResponseExtension;
|
||||
import google.registry.model.domain.rgp.RgpInfoExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsInfoExtension;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.xml.bind.annotation.XmlElementRef;
|
||||
import jakarta.xml.bind.annotation.XmlElementRefs;
|
||||
import java.util.Arrays;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Tests for {@link EppXmlTransformer}. */
|
||||
class EppXmlTransformerTest {
|
||||
|
||||
// Non-fee extensions allowed in {@code Response.extensions}.
|
||||
private static final ImmutableSet<Class<?>> NON_FEE_EXTENSIONS =
|
||||
ImmutableSet.of(
|
||||
BulkTokenResponseExtension.class,
|
||||
LaunchCheckResponseExtension.class,
|
||||
RgpInfoExtension.class,
|
||||
SecDnsInfoExtension.class);
|
||||
|
||||
@Test
|
||||
void isFeeExtension_eppResponse() throws Exception {
|
||||
var xmlRefs =
|
||||
EppResponse.class.getDeclaredField("extensions").getAnnotation(XmlElementRefs.class);
|
||||
Arrays.stream(xmlRefs.value())
|
||||
.map(XmlElementRef::type)
|
||||
.filter(type -> !NON_FEE_EXTENSIONS.contains(type))
|
||||
.forEach(
|
||||
type -> assertWithMessage(type.getSimpleName()).that(isFeeExtension(type)).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnmarshalingEppInput() throws Exception {
|
||||
EppInput input = unmarshal(EppInput.class, loadBytes(getClass(), "contact_info.xml").read());
|
||||
|
||||
Reference in New Issue
Block a user