Use History Entry type for flows in VerifyOteServlet

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161855429
This commit is contained in:
bbilbo 2017-07-13 13:31:54 -07:00 committed by Ben McIlwain
parent 4887811fc3
commit 9688638c75
13 changed files with 809 additions and 154 deletions

View file

@ -14,10 +14,10 @@
package google.registry.tools.server; package google.registry.tools.server;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.not; import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Maps.toMap; import static com.google.common.collect.Maps.toMap;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.EppXmlTransformer.unmarshal;
import static google.registry.flows.picker.FlowPicker.getFlowClass;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.DomainNameUtils.ACE_PREFIX; import static google.registry.util.DomainNameUtils.ACE_PREFIX;
@ -25,6 +25,7 @@ import static google.registry.util.DomainNameUtils.ACE_PREFIX;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
@ -32,29 +33,6 @@ import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multiset; import com.google.common.collect.Multiset;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.Flow;
import google.registry.flows.contact.ContactCreateFlow;
import google.registry.flows.contact.ContactDeleteFlow;
import google.registry.flows.contact.ContactTransferApproveFlow;
import google.registry.flows.contact.ContactTransferCancelFlow;
import google.registry.flows.contact.ContactTransferRejectFlow;
import google.registry.flows.contact.ContactTransferRequestFlow;
import google.registry.flows.contact.ContactUpdateFlow;
import google.registry.flows.domain.DomainApplicationCreateFlow;
import google.registry.flows.domain.DomainApplicationDeleteFlow;
import google.registry.flows.domain.DomainApplicationUpdateFlow;
import google.registry.flows.domain.DomainCreateFlow;
import google.registry.flows.domain.DomainDeleteFlow;
import google.registry.flows.domain.DomainRenewFlow;
import google.registry.flows.domain.DomainRestoreRequestFlow;
import google.registry.flows.domain.DomainTransferApproveFlow;
import google.registry.flows.domain.DomainTransferCancelFlow;
import google.registry.flows.domain.DomainTransferRejectFlow;
import google.registry.flows.domain.DomainTransferRequestFlow;
import google.registry.flows.domain.DomainUpdateFlow;
import google.registry.flows.host.HostCreateFlow;
import google.registry.flows.host.HostDeleteFlow;
import google.registry.flows.host.HostUpdateFlow;
import google.registry.model.domain.DomainCommand; import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.fee.FeeCreateCommandExtension; import google.registry.model.domain.fee.FeeCreateCommandExtension;
import google.registry.model.domain.launch.LaunchCreateExtension; import google.registry.model.domain.launch.LaunchCreateExtension;
@ -64,6 +42,7 @@ import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper; import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.host.HostCommand; import google.registry.model.host.HostCommand;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.request.Action; import google.registry.request.Action;
import google.registry.request.JsonActionRunner; import google.registry.request.JsonActionRunner;
import google.registry.request.JsonActionRunner.JsonAction; import google.registry.request.JsonActionRunner.JsonAction;
@ -95,7 +74,9 @@ public class VerifyOteAction implements Runnable, JsonAction {
public static final String PATH = "/_dr/admin/verifyOte"; public static final String PATH = "/_dr/admin/verifyOte";
@Inject JsonActionRunner jsonActionRunner; @Inject JsonActionRunner jsonActionRunner;
@Inject VerifyOteAction() {}
@Inject
VerifyOteAction() {}
@Override @Override
public void run() { public void run() {
@ -113,7 +94,8 @@ public class VerifyOteAction implements Runnable, JsonAction {
@Override @Override
public Object apply(@Nonnull String registrar) { public Object apply(@Nonnull String registrar) {
return checkRegistrar(registrar, summarize); return checkRegistrar(registrar, summarize);
}}); }
});
} }
/** Checks whether the provided registrar has passed OT&E and returns relevant information. */ /** Checks whether the provided registrar has passed OT&E and returns relevant information. */
@ -121,138 +103,158 @@ public class VerifyOteAction implements Runnable, JsonAction {
HistoryEntryStats historyEntryStats = HistoryEntryStats historyEntryStats =
new HistoryEntryStats().recordRegistrarHistory(registrarName); new HistoryEntryStats().recordRegistrarHistory(registrarName);
List<String> failureMessages = historyEntryStats.findFailures(); List<String> failureMessages = historyEntryStats.findFailures();
String passedFraction = String.format( String passedFraction =
"%2d/%2d", StatType.NUM_REQUIREMENTS - failureMessages.size(), StatType.NUM_REQUIREMENTS); String.format(
"%2d/%2d",
StatType.NUM_REQUIREMENTS - failureMessages.size(), StatType.NUM_REQUIREMENTS);
String status = failureMessages.isEmpty() ? "PASS" : "FAIL"; String status = failureMessages.isEmpty() ? "PASS" : "FAIL";
return summarize return summarize
? String.format( ? String.format(
"Num actions: %4d - Reqs passed: %s - Overall: %s", "Num actions: %4d - Reqs passed: %s - Overall: %s",
historyEntryStats.statCounts.size(), historyEntryStats.statCounts.size(), passedFraction, status)
passedFraction,
status)
: String.format( : String.format(
"%s\n%s\nRequirements passed: %s\nOverall OT&E status: %s\n", "%s\n%s\nRequirements passed: %s\nOverall OT&E status: %s\n",
historyEntryStats, historyEntryStats, Joiner.on('\n').join(failureMessages), passedFraction, status);
Joiner.on('\n').join(failureMessages),
passedFraction,
status);
} }
private static final Predicate<EppInput> HAS_CLAIMS_NOTICE = new Predicate<EppInput>() { private static final Predicate<EppInput> HAS_CLAIMS_NOTICE =
@Override new Predicate<EppInput>() {
public boolean apply(@Nonnull EppInput eppInput) { @Override
LaunchCreateExtension launchCreate = public boolean apply(@Nonnull EppInput eppInput) {
eppInput.getSingleExtension(LaunchCreateExtension.class); LaunchCreateExtension launchCreate =
return launchCreate != null && launchCreate.getNotice() != null; eppInput.getSingleExtension(LaunchCreateExtension.class);
}}; return launchCreate != null && launchCreate.getNotice() != null;
private static final Predicate<EppInput> HAS_FEE = new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return eppInput.getSingleExtension(FeeCreateCommandExtension.class) != null;
}};
private static final Predicate<EppInput> HAS_SEC_DNS = new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return (eppInput.getSingleExtension(SecDnsCreateExtension.class) != null)
|| (eppInput.getSingleExtension(SecDnsUpdateExtension.class) != null);
}};
private static final Predicate<EppInput> IS_SUNRISE = new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
LaunchCreateExtension launchCreate =
eppInput.getSingleExtension(LaunchCreateExtension.class);
return launchCreate != null && !isNullOrEmpty(launchCreate.getSignedMarks());
}};
private static final Predicate<EppInput> IS_IDN = new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return ((DomainCommand.Create) ((ResourceCommandWrapper)
eppInput.getCommandWrapper().getCommand()).getResourceCommand())
.getFullyQualifiedDomainName().startsWith(ACE_PREFIX);
}};
private static final Predicate<EppInput> IS_SUBORDINATE = new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return !isNullOrEmpty(((HostCommand.Create) ((ResourceCommandWrapper)
eppInput.getCommandWrapper().getCommand()).getResourceCommand())
.getInetAddresses());
}};
private static Predicate<EppInput> isFlow(final Class<? extends Flow> flowClass) {
return new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
try {
return flowClass.equals(getFlowClass(eppInput));
} catch (EppException e) {
throw new RuntimeException(e);
} }
}}; };
}
private static final Predicate<EppInput> HAS_FEE =
new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return eppInput.getSingleExtension(FeeCreateCommandExtension.class) != null;
}
};
private static final Predicate<EppInput> HAS_SEC_DNS =
new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return (eppInput.getSingleExtension(SecDnsCreateExtension.class) != null)
|| (eppInput.getSingleExtension(SecDnsUpdateExtension.class) != null);
}
};
private static final Predicate<EppInput> IS_SUNRISE =
new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
LaunchCreateExtension launchCreate =
eppInput.getSingleExtension(LaunchCreateExtension.class);
return launchCreate != null && !isNullOrEmpty(launchCreate.getSignedMarks());
}
};
private static final Predicate<EppInput> IS_IDN =
new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return ((DomainCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand())
.getFullyQualifiedDomainName()
.startsWith(ACE_PREFIX);
}
};
private static final Predicate<EppInput> IS_SUBORDINATE =
new Predicate<EppInput>() {
@Override
public boolean apply(@Nonnull EppInput eppInput) {
return !isNullOrEmpty(
((HostCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand())
.getInetAddresses());
}
};
/** Enum defining the distinct statistics (types of registrar actions) to record. */ /** Enum defining the distinct statistics (types of registrar actions) to record. */
public enum StatType { public enum StatType {
CONTACT_CREATES(0, isFlow(ContactCreateFlow.class)), CONTACT_CREATES(0, equalTo(Type.CONTACT_CREATE)),
CONTACT_DELETES(0, isFlow(ContactDeleteFlow.class)), CONTACT_DELETES(0, equalTo(Type.CONTACT_DELETE)),
CONTACT_TRANSFER_APPROVES(0, isFlow(ContactTransferApproveFlow.class)), CONTACT_TRANSFER_APPROVES(0, equalTo(Type.CONTACT_TRANSFER_APPROVE)),
CONTACT_TRANSFER_CANCELS(0, isFlow(ContactTransferCancelFlow.class)), CONTACT_TRANSFER_CANCELS(0, equalTo(Type.CONTACT_TRANSFER_CANCEL)),
CONTACT_TRANSFER_REJECTS(0, isFlow(ContactTransferRejectFlow.class)), CONTACT_TRANSFER_REJECTS(0, equalTo(Type.CONTACT_TRANSFER_REJECT)),
CONTACT_TRANSFER_REQUESTS(0, isFlow(ContactTransferRequestFlow.class)), CONTACT_TRANSFER_REQUESTS(0, equalTo(Type.CONTACT_TRANSFER_REQUEST)),
CONTACT_UPDATES(0, isFlow(ContactUpdateFlow.class)), CONTACT_UPDATES(0, equalTo(Type.CONTACT_UPDATE)),
DOMAIN_APPLICATION_CREATES(0, isFlow(DomainApplicationCreateFlow.class)), DOMAIN_APPLICATION_CREATES(0, equalTo(Type.DOMAIN_APPLICATION_CREATE)),
DOMAIN_APPLICATION_CREATES_LANDRUSH( DOMAIN_APPLICATION_CREATES_LANDRUSH(
1, isFlow(DomainApplicationCreateFlow.class), not(IS_SUNRISE)), 1, equalTo(Type.DOMAIN_APPLICATION_CREATE), not(IS_SUNRISE)),
DOMAIN_APPLICATION_CREATES_SUNRISE(1, isFlow(DomainApplicationCreateFlow.class), IS_SUNRISE), DOMAIN_APPLICATION_CREATES_SUNRISE(1, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE),
DOMAIN_APPLICATION_DELETES(2, isFlow(DomainApplicationDeleteFlow.class)), DOMAIN_APPLICATION_DELETES(2, equalTo(Type.DOMAIN_APPLICATION_DELETE)),
DOMAIN_APPLICATION_UPDATES(2, isFlow(DomainApplicationUpdateFlow.class)), DOMAIN_APPLICATION_UPDATES(2, equalTo(Type.DOMAIN_APPLICATION_UPDATE)),
DOMAIN_CREATES(0, isFlow(DomainCreateFlow.class)), DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
DOMAIN_CREATES_ASCII(1, isFlow(DomainCreateFlow.class), not(IS_IDN)), DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), not(IS_IDN)),
DOMAIN_CREATES_IDN(1, isFlow(DomainCreateFlow.class), IS_IDN), DOMAIN_CREATES_IDN(1, equalTo(Type.DOMAIN_CREATE), IS_IDN),
DOMAIN_CREATES_WITH_CLAIMS_NOTICE(1, isFlow(DomainCreateFlow.class), HAS_CLAIMS_NOTICE), DOMAIN_CREATES_WITH_CLAIMS_NOTICE(1, equalTo(Type.DOMAIN_CREATE), HAS_CLAIMS_NOTICE),
DOMAIN_CREATES_WITH_FEE(1, isFlow(DomainCreateFlow.class), HAS_FEE), DOMAIN_CREATES_WITH_FEE(1, equalTo(Type.DOMAIN_CREATE), HAS_FEE),
DOMAIN_CREATES_WITH_SEC_DNS(1, isFlow(DomainCreateFlow.class), HAS_SEC_DNS), DOMAIN_CREATES_WITH_SEC_DNS(1, equalTo(Type.DOMAIN_CREATE), HAS_SEC_DNS),
DOMAIN_CREATES_WITHOUT_SEC_DNS(0, isFlow(DomainCreateFlow.class), not(HAS_SEC_DNS)), DOMAIN_CREATES_WITHOUT_SEC_DNS(0, equalTo(Type.DOMAIN_CREATE), not(HAS_SEC_DNS)),
DOMAIN_DELETES(2, isFlow(DomainDeleteFlow.class)), DOMAIN_DELETES(2, equalTo(Type.DOMAIN_DELETE)),
DOMAIN_RENEWS(0, isFlow(DomainRenewFlow.class)), DOMAIN_RENEWS(0, equalTo(Type.DOMAIN_RENEW)),
DOMAIN_RESTORES(1, isFlow(DomainRestoreRequestFlow.class)), DOMAIN_RESTORES(1, equalTo(Type.DOMAIN_RESTORE)),
DOMAIN_TRANSFER_APPROVES(1, isFlow(DomainTransferApproveFlow.class)), DOMAIN_TRANSFER_APPROVES(1, equalTo(Type.DOMAIN_TRANSFER_APPROVE)),
DOMAIN_TRANSFER_CANCELS(1, isFlow(DomainTransferCancelFlow.class)), DOMAIN_TRANSFER_CANCELS(1, equalTo(Type.DOMAIN_TRANSFER_CANCEL)),
DOMAIN_TRANSFER_REJECTS(1, isFlow(DomainTransferRejectFlow.class)), DOMAIN_TRANSFER_REJECTS(1, equalTo(Type.DOMAIN_TRANSFER_REJECT)),
DOMAIN_TRANSFER_REQUESTS(1, isFlow(DomainTransferRequestFlow.class)), DOMAIN_TRANSFER_REQUESTS(1, equalTo(Type.DOMAIN_TRANSFER_REQUEST)),
DOMAIN_UPDATES(0, isFlow(DomainUpdateFlow.class)), DOMAIN_UPDATES(0, equalTo(Type.DOMAIN_UPDATE)),
DOMAIN_UPDATES_WITH_SEC_DNS(1, isFlow(DomainUpdateFlow.class), HAS_SEC_DNS), DOMAIN_UPDATES_WITH_SEC_DNS(1, equalTo(Type.DOMAIN_UPDATE), HAS_SEC_DNS),
DOMAIN_UPDATES_WITHOUT_SEC_DNS(0, isFlow(DomainUpdateFlow.class), not(HAS_SEC_DNS)), DOMAIN_UPDATES_WITHOUT_SEC_DNS(0, equalTo(Type.DOMAIN_UPDATE), not(HAS_SEC_DNS)),
HOST_CREATES(0, isFlow(HostCreateFlow.class)), HOST_CREATES(0, equalTo(Type.HOST_CREATE)),
HOST_CREATES_EXTERNAL(0, isFlow(HostCreateFlow.class), not(IS_SUBORDINATE)), HOST_CREATES_EXTERNAL(0, equalTo(Type.HOST_CREATE), not(IS_SUBORDINATE)),
HOST_CREATES_SUBORDINATE(1, isFlow(HostCreateFlow.class), IS_SUBORDINATE), HOST_CREATES_SUBORDINATE(1, equalTo(Type.HOST_CREATE), IS_SUBORDINATE),
HOST_DELETES(1, isFlow(HostDeleteFlow.class)), HOST_DELETES(1, equalTo(Type.HOST_DELETE)),
HOST_UPDATES(1, isFlow(HostUpdateFlow.class)), HOST_UPDATES(1, equalTo(Type.HOST_UPDATE)),
UNCLASSIFIED_FLOWS(0, Predicates.<EppInput>alwaysFalse()); UNCLASSIFIED_FLOWS(0, Predicates.<HistoryEntry.Type>alwaysFalse());
/** The number of StatTypes with a non-zero requirement. */ /** The number of StatTypes with a non-zero requirement. */
private static final int NUM_REQUIREMENTS = FluentIterable.from(values()) private static final int NUM_REQUIREMENTS =
.filter(new Predicate<StatType>() { FluentIterable.from(values())
@Override .filter(
public boolean apply(@Nonnull StatType statType) { new Predicate<StatType>() {
return statType.requirement > 0; @Override
}}) public boolean apply(@Nonnull StatType statType) {
.size(); return statType.requirement > 0;
}
})
.size();
/** Required number of times registrars must complete this action. */ /** Required number of times registrars must complete this action. */
final int requirement; final int requirement;
/** Filters to determine if this action was performed by an EppInput. */ /** Filter to check the HistoryEntry Type */
private Predicate<EppInput>[] filters; @SuppressWarnings("ImmutableEnumChecker") // Predicates are immutable.
private final Predicate<HistoryEntry.Type> typeFilter;
@SafeVarargs /** Optional filter on the EppInput. */
StatType(int requirement, Predicate<EppInput>... filters) { @SuppressWarnings("ImmutableEnumChecker") // Predicates are immutable.
private final Optional<Predicate<EppInput>> eppInputFilter;
StatType(int requirement, Predicate<HistoryEntry.Type> typeFilter) {
this(requirement, typeFilter, null);
}
StatType(
int requirement,
Predicate<HistoryEntry.Type> typeFilter,
Predicate<EppInput> eppInputFilter) {
this.requirement = requirement; this.requirement = requirement;
this.filters = filters; this.typeFilter = typeFilter;
if (eppInputFilter == null) {
this.eppInputFilter = Optional.absent();
} else {
this.eppInputFilter = Optional.of(eppInputFilter);
}
} }
/** Returns a more human-readable translation of the enum constant. */ /** Returns a more human-readable translation of the enum constant. */
@ -260,9 +262,15 @@ public class VerifyOteAction implements Runnable, JsonAction {
return Ascii.toLowerCase(this.name().replace('_', ' ')); return Ascii.toLowerCase(this.name().replace('_', ' '));
} }
/** An {@link EppInput} might match multiple actions, so check if this action matches. */ /**
boolean matches(EppInput eppInput) { * Check if the {@link HistoryEntry} type matches as well as the {@link EppInput} if supplied.
return Predicates.and(filters).apply(eppInput); */
boolean matches(HistoryEntry.Type historyType, Optional<EppInput> eppInput) {
if (eppInputFilter.isPresent() && eppInput.isPresent()) {
return typeFilter.apply(historyType) && eppInputFilter.get().apply(eppInput.get());
} else {
return typeFilter.apply(historyType);
}
} }
} }
@ -293,22 +301,18 @@ public class VerifyOteAction implements Runnable, JsonAction {
} }
/** Interprets the data in the provided HistoryEntry and increments counters. */ /** Interprets the data in the provided HistoryEntry and increments counters. */
void record(HistoryEntry historyEntry) throws EppException { void record(final HistoryEntry historyEntry) throws EppException {
byte[] xmlBytes = historyEntry.getXmlBytes(); byte[] xmlBytes = historyEntry.getXmlBytes();
// xmlBytes can be null on contact create and update for safe-harbor compliance. // xmlBytes can be null on contact create and update for safe-harbor compliance.
// final Optional<EppInput> eppInput =
// TODO(b/26161587): inspect the history entry itself to handle this properly. (xmlBytes == null) ? Optional.absent() : Optional.of(unmarshal(EppInput.class, xmlBytes));
if (xmlBytes == null) {
return;
}
final EppInput eppInput = unmarshal(EppInput.class, xmlBytes);
if (!statCounts.addAll( if (!statCounts.addAll(
FluentIterable.from(EnumSet.allOf(StatType.class)) FluentIterable.from(EnumSet.allOf(StatType.class))
.filter( .filter(
new Predicate<StatType>() { new Predicate<StatType>() {
@Override @Override
public boolean apply(@Nonnull StatType statType) { public boolean apply(@Nonnull StatType statType) {
return statType.matches(eppInput); return statType.matches(historyEntry.getType(), eppInput);
} }
}) })
.toList())) { .toList())) {
@ -317,17 +321,17 @@ public class VerifyOteAction implements Runnable, JsonAction {
} }
/** /**
* Returns a list of failure messages describing any cases where the passed stats fail to * Returns a list of failure messages describing any cases where the passed stats fail to meet
* meet the required thresholds, or the empty list if all requirements are met. * the required thresholds, or the empty list if all requirements are met.
*/ */
List<String> findFailures() { List<String> findFailures() {
List<String> messages = new ArrayList<>(); List<String> messages = new ArrayList<>();
for (StatType statType : StatType.values()) { for (StatType statType : StatType.values()) {
if (statCounts.count(statType) < statType.requirement) { if (statCounts.count(statType) < statType.requirement) {
messages.add(String.format( messages.add(
"Failure: %s %s found.", String.format(
(statType.requirement == 1 ? "No" : "Not enough"), "Failure: %s %s found.",
statType.description())); (statType.requirement == 1 ? "No" : "Not enough"), statType.description()));
} }
} }
return messages; return messages;

View file

@ -0,0 +1,80 @@
// Copyright 2017 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.testing.DatastoreHelper.persistResource;
import static org.mockito.Matchers.anyMapOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.model.registrar.Registrar;
import google.registry.tools.ServerSideCommand.Connection;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
/** Unit tests for {@link VerifyOteCommand}. */
public class VerifyOteCommandTest extends CommandTestCase<VerifyOteCommand> {
@Mock private Connection connection;
@Before
public void init() throws Exception {
command.setConnection(connection);
ImmutableMap<String, Object> response =
ImmutableMap.<String, Object>of(
"blobio", "Num actions: 19 - Reqs passed: 19/19 - Overall: PASS");
when(connection.sendJson(anyString(), anyMapOf(String.class, Object.class)))
.thenReturn(ImmutableMap.<String, Object>of("blobio", response));
}
@Test
public void testSuccess_pass() throws Exception {
Registrar registrar =
Registrar.loadByClientId("TheRegistrar")
.asBuilder()
.setClientId("blobio-1")
.setRegistrarName("blobio-1")
.build();
persistResource(registrar);
runCommand("blobio");
verify(connection)
.sendJson(
eq("/_dr/admin/verifyOte"),
eq(ImmutableMap.of("summarize", "false", "registrars", ImmutableList.of("blobio"))));
assertInStdout("blobio OT&E status");
assertInStdout("Overall: PASS");
}
@Test
public void testFailure_registrarDoesntExist() throws Exception {
thrown.expect(VerifyException.class, "Registrar blobio does not exist.");
runCommand("blobio");
}
@Test
public void testFailure_noRegistrarsNoCheckAll() throws Exception {
thrown.expect(
IllegalArgumentException.class,
"Must provide at least one registrar name, or supply --check-all with no names.");
runCommand("");
}
}

View file

@ -0,0 +1,272 @@
// Copyright 2017 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.server;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatastoreHelper.deleteResource;
import static google.registry.testing.DatastoreHelper.persistResource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.testing.AppEngineRule;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link VerifyOteAction}. */
@RunWith(JUnit4.class)
public class VerifyOteActionTest {
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
private final VerifyOteAction action = new VerifyOteAction();
HistoryEntry hostDeleteHistoryEntry;
@Before
public void init() throws Exception {
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_APPLICATION_CREATE)
.setXmlBytes(ToolsTestData.get("domain_create_complete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_APPLICATION_CREATE)
.setXmlBytes(ToolsTestData.get("domain_create_sunrise.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_APPLICATION_DELETE)
.setXmlBytes(ToolsTestData.get("domain_delete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-2")
.setType(Type.DOMAIN_APPLICATION_DELETE)
.setXmlBytes(ToolsTestData.get("domain_delete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_APPLICATION_UPDATE)
.setXmlBytes(ToolsTestData.get("domain_update_complete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-2")
.setType(Type.DOMAIN_APPLICATION_UPDATE)
.setXmlBytes(ToolsTestData.get("domain_update_complete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.get("domain_create_idn.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.get("domain_create_claim_notice.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.get("domain_create_anchor_tenant_fee_standard.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.get("allocate_domain.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(ToolsTestData.get("domain_delete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-2")
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(ToolsTestData.get("domain_delete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_RESTORE)
.setXmlBytes(ToolsTestData.get("domain_restore.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_APPROVE)
.setXmlBytes(ToolsTestData.get("domain_transfer_approve.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_CANCEL)
.setXmlBytes(ToolsTestData.get("domain_transfer_cancel.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_REJECT)
.setXmlBytes(ToolsTestData.get("domain_transfer_reject.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_REQUEST)
.setXmlBytes(ToolsTestData.get("domain_transfer_request.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_UPDATE)
.setXmlBytes(ToolsTestData.get("domain_update_with_secdns.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_CREATE)
.setXmlBytes(ToolsTestData.get("host_create_complete.xml").read())
.build());
hostDeleteHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_DELETE)
.setXmlBytes(ToolsTestData.get("host_delete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_UPDATE)
.setXmlBytes(ToolsTestData.get("host_update.xml").read())
.build());
}
@Test
public void testSuccess_passSummarize() throws Exception {
Map<String, Object> response =
action.handleJsonRequest(
ImmutableMap.of("summarize", "true", "registrars", ImmutableList.of("blobio")));
for (Entry<String, Object> registrar : response.entrySet()) {
assertThat(registrar.getKey()).matches("blobio");
assertThat(registrar.getValue().toString()).containsMatch("Reqs passed: 19/19");
assertThat(registrar.getValue().toString()).containsMatch("Overall: PASS");
}
}
@Test
public void testSuccess_passNotSummarized() throws Exception {
Map<String, Object> response =
action.handleJsonRequest(
ImmutableMap.of("summarize", "false", "registrars", ImmutableList.of("blobio")));
for (Entry<String, Object> registrar : response.entrySet()) {
assertThat(registrar.getKey()).matches("blobio");
String expectedOteStatus =
"domain application creates landrush: 1\n"
+ "domain application creates sunrise: 1\n"
+ "domain application deletes: 2\n"
+ "domain application updates: 2\n"
+ ".*"
+ "domain creates idn: 1\n"
+ "domain creates with claims notice: 1\n"
+ "domain creates with fee: 1\n"
+ "domain creates with sec dns: 1\n"
+ ".*"
+ "domain deletes: 2\n"
+ ".*"
+ "domain restores: 1\n"
+ "domain transfer approves: 1\n"
+ "domain transfer cancels: 1\n"
+ "domain transfer rejects: 1\n"
+ "domain transfer requests: 1\n"
+ ".*"
+ "domain updates with sec dns: 1\n"
+ ".*"
+ "host creates subordinate: 1\n"
+ "host deletes: 1\n"
+ "host updates: 1\n"
+ ".*"
+ "Requirements passed: 19/19\n"
+ "Overall OT&E status: PASS\n";
Pattern expectedOteStatusPattern = Pattern.compile(expectedOteStatus, Pattern.DOTALL);
assertThat(registrar.getValue().toString()).containsMatch(expectedOteStatusPattern);
}
}
@Test
public void testFailure_missingHostDelete() throws Exception {
deleteResource(hostDeleteHistoryEntry);
Map<String, Object> response =
action.handleJsonRequest(
ImmutableMap.of("summarize", "false", "registrars", ImmutableList.of("blobio")));
for (Entry<String, Object> registrar : response.entrySet()) {
assertThat(registrar.getKey()).matches("blobio");
String oteStatus = registrar.getValue().toString();
String expectedOteStatus =
"domain application creates landrush: 1\n"
+ "domain application creates sunrise: 1\n"
+ "domain application deletes: 2\n"
+ "domain application updates: 2\n"
+ ".*"
+ "domain creates idn: 1\n"
+ "domain creates with claims notice: 1\n"
+ "domain creates with fee: 1\n"
+ "domain creates with sec dns: 1\n"
+ ".*"
+ "domain deletes: 2\n"
+ ".*"
+ "domain restores: 1\n"
+ "domain transfer approves: 1\n"
+ "domain transfer cancels: 1\n"
+ "domain transfer rejects: 1\n"
+ "domain transfer requests: 1\n"
+ ".*"
+ "domain updates with sec dns: 1\n"
+ ".*"
+ "host creates subordinate: 1\n"
+ "host deletes: 0\n"
+ "host updates: 1\n"
+ ".*"
+ "Requirements passed: 18/19\n"
+ "Overall OT&E status: FAIL\n";
Pattern expectedOteStatusPattern = Pattern.compile(expectedOteStatus, Pattern.DOTALL);
assertThat(oteStatus).containsMatch(expectedOteStatusPattern);
}
}
}

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example-one.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:ns>
<domain:hostObj>ns1.example.net</domain:hostObj>
<domain:hostObj>ns2.example.net</domain:hostObj>
</domain:ns>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<launch:create xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="registration">
<launch:phase>claims</launch:phase>
<launch:notice>
<launch:noticeID>370d0b7c9223372036854775807</launch:noticeID>
<launch:notAfter>2010-08-16T09:00:00.0Z</launch:notAfter>
<launch:acceptedDate>2009-08-16T09:00:00.0Z</launch:acceptedDate>
</launch:notice>
</launch:create>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,22 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>xn--abc-873b2e7eb1k8a4lpjvv.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:ns>
<domain:hostObj>ns1.example.net</domain:hostObj>
<domain:hostObj>ns2.example.net</domain:hostObj>
</domain:ns>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>exampleone.tld</domain:name>
<domain:ns>
<domain:hostObj>ns1.example.net</domain:hostObj>
<domain:hostObj>ns2.example.net</domain:hostObj>
</domain:ns>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<launch:create
xmlns:launch="urn:ietf:params:xml:ns:launch-1.0"
type="application">
<launch:phase>sunrise</launch:phase>
<smd:signedMark xmlns:smd="urn:ietf:params:xml:ns:signedMark-1.0" id="signedMark">
<smd:id>1-2</smd:id>
<smd:issuerInfo issuerID="2">
<smd:org>Example Inc.</smd:org>
<smd:email>support@example.tld</smd:email>
<smd:url>http://www.example.tld</smd:url>
<smd:voice x="1234">+1.7035555555</smd:voice>
</smd:issuerInfo>
<smd:notBefore>2009-08-16T09:00:00.0Z</smd:notBefore>
<smd:notAfter>2010-08-16T09:00:00.0Z</smd:notAfter>
<mark:mark xmlns:mark="urn:ietf:params:xml:ns:mark-1.0">
<mark:trademark>
<mark:id>1234-2</mark:id>
<mark:markName>Example One</mark:markName>
<mark:holder entitlement="owner">
<mark:org>Example Inc.</mark:org>
<mark:addr>
<mark:street>123 Example Dr.</mark:street>
<mark:street>Suite 100</mark:street>
<mark:city>Reston</mark:city>
<mark:sp>VA</mark:sp>
<mark:pc>20190</mark:pc>
<mark:cc>US</mark:cc>
</mark:addr>
</mark:holder>
<mark:jurisdiction>US</mark:jurisdiction>
<mark:class>35</mark:class>
<mark:class>36</mark:class>
<mark:label>example-one</mark:label>
<mark:label>exampleone</mark:label>
<mark:goodsAndServices>Dirigendas et eiusmodi featuring infringo in airfare et cartam servicia.</mark:goodsAndServices>
<mark:regNum>234235</mark:regNum>
<mark:regDate>2009-08-16T09:00:00.0Z</mark:regDate>
<mark:exDate>2015-08-16T09:00:00.0Z</mark:exDate>
</mark:trademark>
</mark:mark>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod
Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="#signedMark">
<Transforms>
<Transform
Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>
miF4M2aTd1Y3tKOzJtiyl2VpzAnVPnV1Hq7Zax+yzrA=
</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
MELpHTWEVfG1JcsG1/a//o54OnlJ5A864+X5JwfqgGBBeZSzGHNzwzTKFzIyyyfn
lGxVwNMoBV5aSvkF7oEKMNVzfcl/P0czNQZ/LJ83p3Ol27/iUNsqgCaGf9Zupw+M
XT4Q2lOrIw+qSx5g7q9T83siMLvkD5uEYlU5dPqgsObLTW8/doTQrA14RcxgY4kG
a4+t5B1cT+5VaghTOPb8uUSEDKjnOsGdy8p24wgyK9n8h0CTSS2ZQ6Zq/RmQeT7D
sbceUHheQ+mkQWIljpMQqsiBjw5XXh4jkEgfAzrb6gkYEF+X8ReuPZuOYC4QjIET
yx8ifN4KE3GIbMXeF4LDsA==
</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>
o/cwvXhbVYl0RDWWvoyeZpETVZVVcMCovUVNg/swWinuMgEWgVQFrz0xA04pEhXC
FVv4evbUpekJ5buqU1gmQyOsCKQlhOHTdPjvkC5upDqa51Flk0TMaMkIQjs7aUKC
mA4RG4tTTGK/EjR1ix8/D0gHYVRldy1YPrMP+ou75bOVnIos+HifrAtrIv4qEqwL
L4FTZAUpaCa2BmgXfy2CSRQbxD5Or1gcSa3vurh5sPMCNxqaXmIXmQipS+DuEBqM
M8tldaN7RYojUEKrGVsNk5i9y2/7sjn1zyyUPf7vL4GgDYqhJYWV61DnXgx/Jd6C
WxvsnDF6scscQzUTEl+hyw==
</Modulus>
<Exponent>
AQAB
</Exponent>
</RSAKeyValue>
</KeyValue>
<X509Data>
<X509Certificate>
MIIESTCCAzGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCQ0ExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRMwEQYDVQQKEwpJQ0FO
TiBUTUNIMRswGQYDVQQDExJJQ0FOTiBUTUNIIFRFU1QgQ0EwHhcNMTMwMjA4MDAw
MDAwWhcNMTgwMjA3MjM1OTU5WjBsMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
FDASBgNVBAcTC0xvcyBBbmdlbGVzMRcwFQYDVQQKEw5WYWxpZGF0b3IgVE1DSDEh
MB8GA1UEAxMYVmFsaWRhdG9yIFRNQ0ggVEVTVCBDRVJUMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAo/cwvXhbVYl0RDWWvoyeZpETVZVVcMCovUVNg/sw
WinuMgEWgVQFrz0xA04pEhXCFVv4evbUpekJ5buqU1gmQyOsCKQlhOHTdPjvkC5u
pDqa51Flk0TMaMkIQjs7aUKCmA4RG4tTTGK/EjR1ix8/D0gHYVRldy1YPrMP+ou7
5bOVnIos+HifrAtrIv4qEqwLL4FTZAUpaCa2BmgXfy2CSRQbxD5Or1gcSa3vurh5
sPMCNxqaXmIXmQipS+DuEBqMM8tldaN7RYojUEKrGVsNk5i9y2/7sjn1zyyUPf7v
L4GgDYqhJYWV61DnXgx/Jd6CWxvsnDF6scscQzUTEl+hywIDAQABo4H/MIH8MAwG
A1UdEwEB/wQCMAAwHQYDVR0OBBYEFPZEcIQcD/Bj2IFz/LERuo2ADJviMIGMBgNV
HSMEgYQwgYGAFO0/7kEh3FuEKS+Q/kYHaD/W6wihoWakZDBiMQswCQYDVQQGEwJV
UzELMAkGA1UECBMCQ0ExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRMwEQYDVQQKEwpJ
Q0FOTiBUTUNIMRswGQYDVQQDExJJQ0FOTiBUTUNIIFRFU1QgQ0GCAQEwDgYDVR0P
AQH/BAQDAgeAMC4GA1UdHwQnMCUwI6AhoB+GHWh0dHA6Ly9jcmwuaWNhbm4ub3Jn
L3RtY2guY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQB2qSy7ui+43cebKUKwWPrzz9y/
IkrMeJGKjo40n+9uekaw3DJ5EqiOf/qZ4pjBD++oR6BJCb6NQuQKwnoAz5lE4Ssu
y5+i93oT3HfyVc4gNMIoHm1PS19l7DBKrbwbzAea/0jKWVzrvmV7TBfjxD3AQo1R
bU5dBr6IjbdLFlnO5x0G0mrG7x5OUPuurihyiURpFDpwH8KAH1wMcCpXGXFRtGKk
wydgyVYAty7otkl/z3bZkCVT34gPvF70sR6+QxUy8u0LzF5A/beYaZpxSYG31amL
AdXitTWFipaIGea9lEGFM0L9+Bg7XzNn4nVLXokyEB3bgS4scG6QznX23FGk
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</smd:signedMark>
</launch:create>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,17 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<domain:update
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:chg/>
</domain:update>
</update>
<extension>
<rgp:update xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
<rgp:restore op="request"/>
</rgp:update>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,11 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<transfer op="approve">
<domain:transfer
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
</domain:transfer>
</transfer>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,11 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<transfer op="cancel">
<domain:transfer
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
</domain:transfer>
</transfer>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,11 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<transfer op="reject">
<domain:transfer
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
</domain:transfer>
</transfer>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,15 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<transfer op="request">
<domain:transfer
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">1</domain:period>
<domain:authInfo>
<domain:pw roid="JD1234-REP">2fooBAR</domain:pw>
</domain:authInfo>
</domain:transfer>
</transfer>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,28 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<domain:update
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:chg/>
</domain:update>
</update>
<extension>
<rgp:update xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
<rgp:restore op="request"/>
</rgp:update>
<secDNS:update
xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
<secDNS:add>
<secDNS:dsData>
<secDNS:keyTag>12346</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>38EC35D5B3A34B44C39B</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,14 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<host:update
xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>example.tld</host:name>
<host:chg>
<host:name>example2.tld</host:name>
</host:chg>
</host:update>
</update>
<clTRID>ABC-12345</clTRID>
</command>
</epp>