Refactor most of OT&E verification code to exist in utils class

This does not change existing functionality but will allow us to use this common code in the yet-to-be-created web console action as well.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=227159346
This commit is contained in:
jianglai 2018-12-28 12:28:58 -08:00
parent 2777018d6a
commit 2e7d71b238
22 changed files with 754 additions and 470 deletions

View file

@ -361,7 +361,7 @@ public final class OteAccountBuilder {
}
/** Returns the ClientIds of the OT&E, with the TLDs each has access to. */
private static ImmutableMap<String, String> createClientIdToTldMap(String baseClientId) {
static ImmutableMap<String, String> createClientIdToTldMap(String baseClientId) {
checkArgument(
REGISTRAR_PATTERN.matcher(baseClientId).matches(),
"Invalid registrar name: %s",

View file

@ -0,0 +1,277 @@
// Copyright 2018 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.model;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
import com.google.common.base.Ascii;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multiset;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.cmd.Query;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.fee.FeeCreateCommandExtension;
import google.registry.model.domain.launch.LaunchCreateExtension;
import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.host.HostCommand;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.xml.XmlException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/** Represents stats derived from HistoryEntry objects on actions taken by registrars. */
public class OteStats {
/**
* Returns the statistics about the OT&E actions that have been taken by a particular registrar.
*/
public static OteStats getFromRegistrar(String registrarName) {
return new OteStats().recordRegistrarHistory(registrarName);
}
private OteStats() {}
private static final Predicate<EppInput> HAS_CLAIMS_NOTICE =
eppInput -> {
Optional<LaunchCreateExtension> launchCreate =
eppInput.getSingleExtension(LaunchCreateExtension.class);
return launchCreate.isPresent() && launchCreate.get().getNotice() != null;
};
private static final Predicate<EppInput> HAS_SEC_DNS =
eppInput ->
eppInput.getSingleExtension(SecDnsCreateExtension.class).isPresent()
|| eppInput.getSingleExtension(SecDnsUpdateExtension.class).isPresent();
private static final Predicate<EppInput> IS_SUNRISE =
eppInput -> {
Optional<LaunchCreateExtension> launchCreate =
eppInput.getSingleExtension(LaunchCreateExtension.class);
return launchCreate.isPresent() && !isNullOrEmpty(launchCreate.get().getSignedMarks());
};
private static final Predicate<EppInput> IS_IDN =
eppInput ->
((DomainCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand())
.getFullyQualifiedDomainName()
.startsWith(ACE_PREFIX);
private static final Predicate<EppInput> IS_SUBORDINATE =
eppInput ->
!isNullOrEmpty(
((HostCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand())
.getInetAddresses());
/** Enum defining the distinct statistics (types of registrar actions) to record. */
public enum StatType {
CONTACT_CREATES(0, equalTo(Type.CONTACT_CREATE)),
CONTACT_DELETES(0, equalTo(Type.CONTACT_DELETE)),
CONTACT_TRANSFER_APPROVES(0, equalTo(Type.CONTACT_TRANSFER_APPROVE)),
CONTACT_TRANSFER_CANCELS(0, equalTo(Type.CONTACT_TRANSFER_CANCEL)),
CONTACT_TRANSFER_REJECTS(0, equalTo(Type.CONTACT_TRANSFER_REJECT)),
CONTACT_TRANSFER_REQUESTS(0, equalTo(Type.CONTACT_TRANSFER_REQUEST)),
CONTACT_UPDATES(0, equalTo(Type.CONTACT_UPDATE)),
DOMAIN_APPLICATION_CREATES(0, equalTo(Type.DOMAIN_APPLICATION_CREATE)),
DOMAIN_APPLICATION_CREATES_LANDRUSH(
0, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE.negate()),
DOMAIN_APPLICATION_CREATES_SUNRISE(0, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE),
DOMAIN_APPLICATION_DELETES(0, equalTo(Type.DOMAIN_APPLICATION_DELETE)),
DOMAIN_APPLICATION_UPDATES(0, equalTo(Type.DOMAIN_APPLICATION_UPDATE)),
DOMAIN_AUTORENEWS(0, equalTo(Type.DOMAIN_AUTORENEW)),
DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), IS_IDN.negate()),
DOMAIN_CREATES_IDN(1, equalTo(Type.DOMAIN_CREATE), IS_IDN),
DOMAIN_CREATES_START_DATE_SUNRISE(1, equalTo(Type.DOMAIN_CREATE), IS_SUNRISE),
DOMAIN_CREATES_WITH_CLAIMS_NOTICE(1, equalTo(Type.DOMAIN_CREATE), HAS_CLAIMS_NOTICE),
DOMAIN_CREATES_WITH_FEE(
1,
equalTo(Type.DOMAIN_CREATE),
eppInput -> eppInput.getSingleExtension(FeeCreateCommandExtension.class).isPresent()),
DOMAIN_CREATES_WITH_SEC_DNS(1, equalTo(Type.DOMAIN_CREATE), HAS_SEC_DNS),
DOMAIN_CREATES_WITHOUT_SEC_DNS(0, equalTo(Type.DOMAIN_CREATE), HAS_SEC_DNS.negate()),
DOMAIN_DELETES(2, equalTo(Type.DOMAIN_DELETE)),
DOMAIN_RENEWS(0, equalTo(Type.DOMAIN_RENEW)),
DOMAIN_RESTORES(1, equalTo(Type.DOMAIN_RESTORE)),
DOMAIN_TRANSFER_APPROVES(1, equalTo(Type.DOMAIN_TRANSFER_APPROVE)),
DOMAIN_TRANSFER_CANCELS(1, equalTo(Type.DOMAIN_TRANSFER_CANCEL)),
DOMAIN_TRANSFER_REJECTS(1, equalTo(Type.DOMAIN_TRANSFER_REJECT)),
DOMAIN_TRANSFER_REQUESTS(1, equalTo(Type.DOMAIN_TRANSFER_REQUEST)),
DOMAIN_UPDATES(0, equalTo(Type.DOMAIN_UPDATE)),
DOMAIN_UPDATES_WITH_SEC_DNS(1, equalTo(Type.DOMAIN_UPDATE), HAS_SEC_DNS),
DOMAIN_UPDATES_WITHOUT_SEC_DNS(0, equalTo(Type.DOMAIN_UPDATE), HAS_SEC_DNS.negate()),
HOST_CREATES(0, equalTo(Type.HOST_CREATE)),
HOST_CREATES_EXTERNAL(0, equalTo(Type.HOST_CREATE), IS_SUBORDINATE.negate()),
HOST_CREATES_SUBORDINATE(1, equalTo(Type.HOST_CREATE), IS_SUBORDINATE),
HOST_DELETES(1, equalTo(Type.HOST_DELETE)),
HOST_UPDATES(1, equalTo(Type.HOST_UPDATE)),
UNCLASSIFIED_FLOWS(0, Predicates.alwaysFalse());
/** StatTypes with a non-zero requirement */
public static final ImmutableList<StatType> REQUIRED_STAT_TYPES =
Arrays.stream(values())
.filter(statType -> statType.requirement > 0)
.collect(toImmutableList());
/** Required number of times registrars must complete this action. */
private final int requirement;
/** Filter to check the HistoryEntry Type */
@SuppressWarnings("ImmutableEnumChecker") // Predicates are immutable.
private final Predicate<HistoryEntry.Type> typeFilter;
/** Optional filter on the EppInput. */
@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.typeFilter = typeFilter;
if (eppInputFilter == null) {
this.eppInputFilter = Optional.empty();
} else {
this.eppInputFilter = Optional.of(eppInputFilter);
}
}
/** Returns the number of times this StatType must be performed. */
public int getRequirement() {
return requirement;
}
/** Returns a more human-readable translation of the enum constant. */
private String description() {
return Ascii.toLowerCase(this.name().replace('_', ' '));
}
/**
* Check if the {@link HistoryEntry} type matches as well as the {@link EppInput} if supplied.
*/
private boolean matches(HistoryEntry.Type historyType, Optional<EppInput> eppInput) {
if (eppInputFilter.isPresent() && eppInput.isPresent()) {
return typeFilter.test(historyType) && eppInputFilter.get().test(eppInput.get());
} else {
return typeFilter.test(historyType);
}
}
}
/** Stores counts of how many times each action type was performed. */
private final Multiset<StatType> statCounts = HashMultiset.create();
/**
* Records data on what actions have been performed by the four numbered OT&amp;E variants of the
* registrar name.
*
* <p>Stops when it notices that all tests have passed.
*/
private OteStats recordRegistrarHistory(String registrarName) {
ImmutableCollection<String> clientIds =
OteAccountBuilder.createClientIdToTldMap(registrarName).keySet();
Query<HistoryEntry> query =
ofy()
.load()
.type(HistoryEntry.class)
.filter("clientId in", clientIds)
.order("modificationTime");
for (HistoryEntry historyEntry : query) {
try {
record(historyEntry);
} catch (XmlException e) {
throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e);
}
// Break out early if all tests were passed.
if (wereAllTestsPassed()) {
break;
}
}
return this;
}
/** Interprets the data in the provided HistoryEntry and increments counters. */
private void record(final HistoryEntry historyEntry) throws XmlException {
byte[] xmlBytes = historyEntry.getXmlBytes();
// xmlBytes can be null on contact create and update for safe-harbor compliance.
final Optional<EppInput> eppInput =
(xmlBytes == null) ? Optional.empty() : Optional.of(unmarshal(EppInput.class, xmlBytes));
if (!statCounts.addAll(
EnumSet.allOf(StatType.class).stream()
.filter(statType -> statType.matches(historyEntry.getType(), eppInput))
.collect(toImmutableList()))) {
statCounts.add(StatType.UNCLASSIFIED_FLOWS);
}
}
private boolean wereAllTestsPassed() {
return Arrays.stream(StatType.values()).allMatch(s -> statCounts.count(s) >= s.requirement);
}
/** Returns the total number of actions taken */
public int getSize() {
return statCounts.size();
}
/** Returns the number of times that a particular StatType was seen */
public int getCount(StatType statType) {
return statCounts.count(statType);
}
/**
* Returns a list of failures, any cases where the passed stats fail to meet the required
* thresholds, or the empty list if all requirements are met.
*/
public ImmutableList<StatType> getFailures() {
return StatType.REQUIRED_STAT_TYPES.stream()
.filter(statType -> statCounts.count(statType) < statType.requirement)
.collect(toImmutableList());
}
/** Returns a string showing all possible actions and how many times each was performed. */
@Override
public String toString() {
return String.format(
"%s\nTOTAL: %d",
EnumSet.allOf(StatType.class).stream()
.map(stat -> String.format("%s: %d", stat.description(), statCounts.count(stat)))
.collect(Collectors.joining("\n")),
statCounts.size());
}
}

View file

@ -14,47 +14,19 @@
package google.registry.tools.server;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Maps.toMap;
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
import com.google.common.base.Ascii;
import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multiset;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.cmd.Query;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.fee.FeeCreateCommandExtension;
import google.registry.model.domain.launch.LaunchCreateExtension;
import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.host.HostCommand;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import com.google.common.collect.Maps;
import google.registry.model.OteStats;
import google.registry.model.OteStats.StatType;
import google.registry.request.Action;
import google.registry.request.JsonActionRunner;
import google.registry.request.JsonActionRunner.JsonAction;
import google.registry.request.auth.Auth;
import google.registry.xml.XmlException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.inject.Inject;
/**
@ -64,8 +36,7 @@ import javax.inject.Inject;
@Action(
path = VerifyOteAction.PATH,
method = Action.Method.POST,
auth = Auth.AUTH_INTERNAL_OR_ADMIN
)
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
public class VerifyOteAction implements Runnable, JsonAction {
public static final String PATH = "/_dr/admin/verifyOte";
@ -84,252 +55,31 @@ public class VerifyOteAction implements Runnable, JsonAction {
@SuppressWarnings("unchecked")
public Map<String, Object> handleJsonRequest(Map<String, ?> json) {
final boolean summarize = Boolean.parseBoolean((String) json.get("summarize"));
return toMap(
(List<String>) json.get("registrars"), registrar -> checkRegistrar(registrar, summarize));
Map<String, OteStats> registrarResults =
toMap((List<String>) json.get("registrars"), OteStats::getFromRegistrar);
return Maps.transformValues(registrarResults, stats -> transformOteStats(stats, summarize));
}
/** Checks whether the provided registrar has passed OT&amp;E and returns relevant information. */
private String checkRegistrar(String registrarName, boolean summarize) {
HistoryEntryStats historyEntryStats =
new HistoryEntryStats().recordRegistrarHistory(registrarName);
List<String> failureMessages = historyEntryStats.findFailures();
int testsPassed = StatType.NUM_REQUIREMENTS - failureMessages.size();
String status = failureMessages.isEmpty() ? "PASS" : "FAIL";
private String transformOteStats(OteStats stats, boolean summarize) {
List<StatType> failures = stats.getFailures();
int numRequiredTests = StatType.REQUIRED_STAT_TYPES.size();
int testsPassed = numRequiredTests - failures.size();
String status = failures.isEmpty() ? "PASS" : "FAIL";
return summarize
? String.format(
"# actions: %4d - Reqs: [%s] %2d/%2d - Overall: %s",
historyEntryStats.statCounts.size(),
historyEntryStats.toSummary(),
testsPassed,
StatType.NUM_REQUIREMENTS,
status)
stats.getSize(), getSummary(stats), testsPassed, numRequiredTests, status)
: String.format(
"%s\n%s\nRequirements passed: %2d/%2d\nOverall OT&E status: %s\n",
historyEntryStats,
Joiner.on('\n').join(failureMessages),
testsPassed,
StatType.NUM_REQUIREMENTS,
status);
stats, Joiner.on('\n').join(failures), testsPassed, numRequiredTests, status);
}
private static final Predicate<EppInput> HAS_CLAIMS_NOTICE =
eppInput -> {
Optional<LaunchCreateExtension> launchCreate =
eppInput.getSingleExtension(LaunchCreateExtension.class);
return launchCreate.isPresent() && launchCreate.get().getNotice() != null;
};
private static final Predicate<EppInput> HAS_SEC_DNS =
eppInput ->
(eppInput.getSingleExtension(SecDnsCreateExtension.class).isPresent())
|| (eppInput.getSingleExtension(SecDnsUpdateExtension.class).isPresent());
private static final Predicate<EppInput> IS_SUNRISE =
eppInput -> {
Optional<LaunchCreateExtension> launchCreate =
eppInput.getSingleExtension(LaunchCreateExtension.class);
return launchCreate.isPresent() && !isNullOrEmpty(launchCreate.get().getSignedMarks());
};
private static final Predicate<EppInput> IS_IDN =
eppInput ->
((DomainCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand())
.getFullyQualifiedDomainName()
.startsWith(ACE_PREFIX);
private static final Predicate<EppInput> IS_SUBORDINATE =
eppInput ->
!isNullOrEmpty(
((HostCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
.getResourceCommand())
.getInetAddresses());
/** Enum defining the distinct statistics (types of registrar actions) to record. */
public enum StatType {
CONTACT_CREATES(0, equalTo(Type.CONTACT_CREATE)),
CONTACT_DELETES(0, equalTo(Type.CONTACT_DELETE)),
CONTACT_TRANSFER_APPROVES(0, equalTo(Type.CONTACT_TRANSFER_APPROVE)),
CONTACT_TRANSFER_CANCELS(0, equalTo(Type.CONTACT_TRANSFER_CANCEL)),
CONTACT_TRANSFER_REJECTS(0, equalTo(Type.CONTACT_TRANSFER_REJECT)),
CONTACT_TRANSFER_REQUESTS(0, equalTo(Type.CONTACT_TRANSFER_REQUEST)),
CONTACT_UPDATES(0, equalTo(Type.CONTACT_UPDATE)),
DOMAIN_APPLICATION_CREATES(0, equalTo(Type.DOMAIN_APPLICATION_CREATE)),
DOMAIN_APPLICATION_CREATES_LANDRUSH(
0, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE.negate()),
DOMAIN_APPLICATION_CREATES_SUNRISE(0, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE),
DOMAIN_APPLICATION_DELETES(0, equalTo(Type.DOMAIN_APPLICATION_DELETE)),
DOMAIN_APPLICATION_UPDATES(0, equalTo(Type.DOMAIN_APPLICATION_UPDATE)),
DOMAIN_AUTORENEWS(0, equalTo(Type.DOMAIN_AUTORENEW)),
DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), IS_IDN.negate()),
DOMAIN_CREATES_IDN(1, equalTo(Type.DOMAIN_CREATE), IS_IDN),
DOMAIN_CREATES_START_DATE_SUNRISE(1, equalTo(Type.DOMAIN_CREATE), IS_SUNRISE),
DOMAIN_CREATES_WITH_CLAIMS_NOTICE(1, equalTo(Type.DOMAIN_CREATE), HAS_CLAIMS_NOTICE),
DOMAIN_CREATES_WITH_FEE(
1,
equalTo(Type.DOMAIN_CREATE),
eppInput -> eppInput.getSingleExtension(FeeCreateCommandExtension.class).isPresent()),
DOMAIN_CREATES_WITH_SEC_DNS(1, equalTo(Type.DOMAIN_CREATE), HAS_SEC_DNS),
DOMAIN_CREATES_WITHOUT_SEC_DNS(0, equalTo(Type.DOMAIN_CREATE), HAS_SEC_DNS.negate()),
DOMAIN_DELETES(2, equalTo(Type.DOMAIN_DELETE)),
DOMAIN_RENEWS(0, equalTo(Type.DOMAIN_RENEW)),
DOMAIN_RESTORES(1, equalTo(Type.DOMAIN_RESTORE)),
DOMAIN_TRANSFER_APPROVES(1, equalTo(Type.DOMAIN_TRANSFER_APPROVE)),
DOMAIN_TRANSFER_CANCELS(1, equalTo(Type.DOMAIN_TRANSFER_CANCEL)),
DOMAIN_TRANSFER_REJECTS(1, equalTo(Type.DOMAIN_TRANSFER_REJECT)),
DOMAIN_TRANSFER_REQUESTS(1, equalTo(Type.DOMAIN_TRANSFER_REQUEST)),
DOMAIN_UPDATES(0, equalTo(Type.DOMAIN_UPDATE)),
DOMAIN_UPDATES_WITH_SEC_DNS(1, equalTo(Type.DOMAIN_UPDATE), HAS_SEC_DNS),
DOMAIN_UPDATES_WITHOUT_SEC_DNS(0, equalTo(Type.DOMAIN_UPDATE), HAS_SEC_DNS.negate()),
HOST_CREATES(0, equalTo(Type.HOST_CREATE)),
HOST_CREATES_EXTERNAL(0, equalTo(Type.HOST_CREATE), IS_SUBORDINATE.negate()),
HOST_CREATES_SUBORDINATE(1, equalTo(Type.HOST_CREATE), IS_SUBORDINATE),
HOST_DELETES(1, equalTo(Type.HOST_DELETE)),
HOST_UPDATES(1, equalTo(Type.HOST_UPDATE)),
UNCLASSIFIED_FLOWS(0, Predicates.alwaysFalse());
/** The number of StatTypes with a non-zero requirement. */
private static final int NUM_REQUIREMENTS =
(int) Stream.of(values()).filter(statType -> statType.requirement > 0).count();
/** Required number of times registrars must complete this action. */
final int requirement;
/** Filter to check the HistoryEntry Type */
@SuppressWarnings("ImmutableEnumChecker") // Predicates are immutable.
private final Predicate<HistoryEntry.Type> typeFilter;
/** Optional filter on the EppInput. */
@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.typeFilter = typeFilter;
if (eppInputFilter == null) {
this.eppInputFilter = Optional.empty();
} else {
this.eppInputFilter = Optional.of(eppInputFilter);
}
}
/** Returns a more human-readable translation of the enum constant. */
String description() {
return Ascii.toLowerCase(this.name().replace('_', ' '));
}
/**
* Check if the {@link HistoryEntry} type matches as well as the {@link EppInput} if supplied.
*/
boolean matches(HistoryEntry.Type historyType, Optional<EppInput> eppInput) {
if (eppInputFilter.isPresent() && eppInput.isPresent()) {
return typeFilter.test(historyType) && eppInputFilter.get().test(eppInput.get());
} else {
return typeFilter.test(historyType);
}
}
}
/** Class to represent stats derived from HistoryEntry objects on actions taken by registrars. */
static class HistoryEntryStats {
/** Stores counts of how many times each action type was performed. */
Multiset<StatType> statCounts = HashMultiset.create();
/**
* Records data in the passed historyEntryStats object on what actions have been performed by
* the four numbered OT&amp;E variants of the registrar name.
*
* <p>Stops when it notices that all tests have passed.
*/
HistoryEntryStats recordRegistrarHistory(String registrarName) {
ImmutableList<String> clientIds =
IntStream.rangeClosed(1, 4)
.mapToObj(i -> String.format("%s-%d", registrarName, i))
.collect(toImmutableList());
Query<HistoryEntry> query =
ofy()
.load()
.type(HistoryEntry.class)
.filter("clientId in", clientIds)
.order("modificationTime");
for (HistoryEntry historyEntry : query) {
try {
record(historyEntry);
} catch (XmlException e) {
throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e);
}
// Break out early if all tests were passed.
if (wereAllTestsPassed()) {
break;
}
}
return this;
}
/** Interprets the data in the provided HistoryEntry and increments counters. */
void record(final HistoryEntry historyEntry) throws XmlException {
byte[] xmlBytes = historyEntry.getXmlBytes();
// xmlBytes can be null on contact create and update for safe-harbor compliance.
final Optional<EppInput> eppInput =
(xmlBytes == null) ? Optional.empty() : Optional.of(unmarshal(EppInput.class, xmlBytes));
if (!statCounts.addAll(
EnumSet.allOf(StatType.class).stream()
.filter(statType -> statType.matches(historyEntry.getType(), eppInput))
.collect(toImmutableList()))) {
statCounts.add(StatType.UNCLASSIFIED_FLOWS);
}
}
boolean wereAllTestsPassed() {
return Arrays.stream(StatType.values()).allMatch(s -> statCounts.count(s) >= s.requirement);
}
/**
* Returns a list of failure messages describing any cases where the passed stats fail to meet
* the required thresholds, or the empty list if all requirements are met.
*/
List<String> findFailures() {
List<String> messages = new ArrayList<>();
for (StatType statType : StatType.values()) {
if (statCounts.count(statType) < statType.requirement) {
messages.add(
String.format(
"Failure: %s %s found.",
(statType.requirement == 1 ? "No" : "Not enough"), statType.description()));
}
}
return messages;
}
/** Returns a string showing all possible actions and how many times each was performed. */
@Override
public String toString() {
return String.format(
"%s\nTOTAL: %d",
EnumSet.allOf(StatType.class)
.stream()
.map(stat -> String.format("%s: %d", stat.description(), statCounts.count(stat)))
.collect(Collectors.joining("\n")),
statCounts.size());
}
/** Returns a string showing the results of each test, one character per test. */
String toSummary() {
return EnumSet.allOf(StatType.class)
.stream()
.filter(statType -> statType.requirement > 0)
private String getSummary(OteStats stats) {
return StatType.REQUIRED_STAT_TYPES.stream()
.sorted()
.map(statType -> (statCounts.count(statType) < statType.requirement) ? "." : "-")
.map(statType -> (stats.getCount(statType) < statType.getRequirement()) ? "." : "-")
.collect(Collectors.joining(""));
}
}
}

View file

@ -0,0 +1,147 @@
// Copyright 2018 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.model;
import static com.google.common.truth.Truth.assertThat;
import google.registry.model.OteStats.StatType;
import google.registry.testing.AppEngineRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class OteStatsTest {
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
@Before
public void init() throws Exception {
OteStatsTestHelper.setupHistoryEntries();
}
@Test
public void testSuccess_allPass() {
OteStats stats = OteStats.getFromRegistrar("blobio");
assertThat(stats.getFailures()).isEmpty();
assertThat(stats.getSize()).isEqualTo(31);
}
@Test
public void testSuccess_someFailures() {
OteStatsTestHelper.deleteHostDeleteHistoryEntry();
OteStatsTestHelper.deleteDomainCreateHistoryEntry();
OteStatsTestHelper.deleteDomainRestoreHistoryEntry();
OteStats stats = OteStats.getFromRegistrar("blobio");
assertThat(stats.getFailures())
.containsExactly(
StatType.DOMAIN_CREATES_IDN, StatType.DOMAIN_RESTORES, StatType.HOST_DELETES)
.inOrder();
assertThat(stats.getSize()).isEqualTo(35);
}
@Test
public void testSuccess_toString() {
OteStats stats = OteStats.getFromRegistrar("blobio");
String expected =
"contact creates: 0\n"
+ "contact deletes: 0\n"
+ "contact transfer approves: 0\n"
+ "contact transfer cancels: 0\n"
+ "contact transfer rejects: 0\n"
+ "contact transfer requests: 0\n"
+ "contact updates: 0\n"
+ "domain application creates: 0\n"
+ "domain application creates landrush: 0\n"
+ "domain application creates sunrise: 0\n"
+ "domain application deletes: 0\n"
+ "domain application updates: 0\n"
+ "domain autorenews: 0\n"
+ "domain creates: 5\n"
+ "domain creates ascii: 4\n"
+ "domain creates idn: 1\n"
+ "domain creates start date sunrise: 1\n"
+ "domain creates with claims notice: 1\n"
+ "domain creates with fee: 1\n"
+ "domain creates with sec dns: 1\n"
+ "domain creates without sec dns: 4\n"
+ "domain deletes: 2\n"
+ "domain renews: 0\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: 1\n"
+ "domain updates with sec dns: 1\n"
+ "domain updates without sec dns: 0\n"
+ "host creates: 1\n"
+ "host creates external: 0\n"
+ "host creates subordinate: 1\n"
+ "host deletes: 1\n"
+ "host updates: 1\n"
+ "unclassified flows: 0\n"
+ "TOTAL: 31";
assertThat(stats.toString()).isEqualTo(expected);
}
@Test
public void testMissingHostDeletes_toString() {
OteStatsTestHelper.deleteHostDeleteHistoryEntry();
OteStats stats = OteStats.getFromRegistrar("blobio");
String expected =
"contact creates: 0\n"
+ "contact deletes: 0\n"
+ "contact transfer approves: 0\n"
+ "contact transfer cancels: 0\n"
+ "contact transfer rejects: 0\n"
+ "contact transfer requests: 0\n"
+ "contact updates: 0\n"
+ "domain application creates: 0\n"
+ "domain application creates landrush: 0\n"
+ "domain application creates sunrise: 0\n"
+ "domain application deletes: 0\n"
+ "domain application updates: 0\n"
+ "domain autorenews: 0\n"
+ "domain creates: 5\n"
+ "domain creates ascii: 4\n"
+ "domain creates idn: 1\n"
+ "domain creates start date sunrise: 1\n"
+ "domain creates with claims notice: 1\n"
+ "domain creates with fee: 1\n"
+ "domain creates with sec dns: 1\n"
+ "domain creates without sec dns: 4\n"
+ "domain deletes: 2\n"
+ "domain renews: 0\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: 1\n"
+ "domain updates with sec dns: 1\n"
+ "domain updates without sec dns: 0\n"
+ "host creates: 1\n"
+ "host creates external: 0\n"
+ "host creates subordinate: 1\n"
+ "host deletes: 0\n"
+ "host updates: 10\n"
+ "unclassified flows: 0\n"
+ "TOTAL: 39";
assertThat(stats.toString()).isEqualTo(expected);
}
}

View file

@ -0,0 +1,159 @@
// 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.model;
import static google.registry.testing.DatastoreHelper.deleteResource;
import static google.registry.testing.DatastoreHelper.persistPremiumList;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.TestDataHelper.loadBytes;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import google.registry.model.eppcommon.Trid;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import java.io.IOException;
public final class OteStatsTestHelper {
private static HistoryEntry hostDeleteHistoryEntry;
private static HistoryEntry domainCreateHistoryEntry;
private static HistoryEntry domainRestoreHistoryEntry;
public static void setupHistoryEntries() throws IOException {
persistPremiumList("default_sandbox_list", "sandbox,USD 1000");
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_sunrise.xml"))
.build());
domainCreateHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_idn.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_claim_notice.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_dsdata.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(getBytes("domain_delete.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-2")
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(getBytes("domain_delete.xml"))
.build());
domainRestoreHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_RESTORE)
.setXmlBytes(getBytes("domain_restore.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_APPROVE)
.setXmlBytes(getBytes("domain_transfer_approve.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_CANCEL)
.setXmlBytes(getBytes("domain_transfer_cancel.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_REJECT)
.setXmlBytes(getBytes("domain_transfer_reject.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_REQUEST)
.setXmlBytes(getBytes("domain_transfer_request.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_UPDATE)
.setXmlBytes(getBytes("domain_update_with_secdns.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_CREATE)
.setXmlBytes(getBytes("host_create_complete.xml"))
.build());
hostDeleteHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_DELETE)
.setXmlBytes(getBytes("host_delete.xml"))
.build());
// Persist 10 host updates for a total of 25 history entries. Since these also sort last by
// modification time, when these cause all tests to pass, only the first will be recorded and
// the rest will be skipped.
for (int i = 0; i < 10; i++) {
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_UPDATE)
.setXmlBytes(getBytes("host_update.xml"))
.setTrid(Trid.create(null, String.format("blahtrid-%d", i)))
.setModificationTime(END_OF_TIME)
.build());
}
}
public static void deleteHostDeleteHistoryEntry() {
deleteResource(hostDeleteHistoryEntry);
}
public static void deleteDomainCreateHistoryEntry() {
deleteResource(domainCreateHistoryEntry);
}
public static void deleteDomainRestoreHistoryEntry() {
deleteResource(domainRestoreHistoryEntry);
}
private static byte[] getBytes(String filename) throws IOException {
return loadBytes(OteStatsTestHelper.class, filename).read();
}
}

View file

@ -0,0 +1,29 @@
<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.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">jd1234</domain:contact>
<domain:contact type="tech">jd1234</domain:contact>
<domain:authInfo>
<domain:pw>abcdefghijklmnop</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
<metadata:reason>anchor-tenant-test</metadata:reason>
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
<metadata:anchorTenant>true</metadata:anchorTenant>
</metadata:metadata>
<fee:create xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:currency>USD</fee:currency>
<fee:fee>26.00</fee:fee>
</fee:create>
</extension>
<clTRID>RegistryTool</clTRID>
</command>
</epp>

View file

@ -0,0 +1,17 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<delete>
<domain:delete
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
</domain:delete>
</delete>
<extension>
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
<metadata:reason>Deleted by registry administrator: Test</metadata:reason>
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
</metadata:metadata>
</extension>
<clTRID>RegistryTool</clTRID>
</command>
</epp>

View file

@ -0,0 +1,13 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<host:create xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>example.tld</host:name>
<host:addr ip="v4">162.100.102.99</host:addr>
<host:addr ip="v4">4.5.6.7</host:addr>
<host:addr ip="v6">2001:0db8:85a3:0000:0000:8a2e:0370:7334</host:addr>
</host:create>
</create>
<clTRID>RegistryTool</clTRID>
</command>
</epp>

View file

@ -0,0 +1,17 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<delete>
<host:delete
xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns1.example.tld</host:name>
</host:delete>
</delete>
<extension>
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
<metadata:reason>Deleted by registry administrator: Test</metadata:reason>
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
</metadata:metadata>
</extension>
<clTRID>RegistryTool</clTRID>
</command>
</epp>

View file

@ -18,6 +18,7 @@ java_library(
"//java/google/registry/request",
"//java/google/registry/tools/server",
"//java/google/registry/util",
"//javatests/google/registry/model",
"//javatests/google/registry/testing",
"//javatests/google/registry/testing/mapreduce",
"//third_party/objectify:objectify-v4_1",

View file

@ -15,18 +15,12 @@
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 static google.registry.util.DateTimeUtils.END_OF_TIME;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.model.eppcommon.Trid;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.model.OteStatsTestHelper;
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;
@ -42,149 +36,28 @@ public class VerifyOteActionTest {
private final VerifyOteAction action = new VerifyOteAction();
private HistoryEntry hostDeleteHistoryEntry;
private HistoryEntry domainCreateHistoryEntry;
private HistoryEntry domainRestoreHistoryEntry;
@Before
public void init() throws Exception {
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.loadBytes("domain_create_sunrise.xml").read())
.build());
domainCreateHistoryEntry = persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.loadBytes("domain_create_idn.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.loadBytes("domain_create_claim_notice.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.loadBytes("domain_create_anchor_tenant_fee_standard.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(ToolsTestData.loadBytes("domain_create_dsdata.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(ToolsTestData.loadBytes("domain_delete.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-2")
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(ToolsTestData.loadBytes("domain_delete.xml").read())
.build());
domainRestoreHistoryEntry = persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_RESTORE)
.setXmlBytes(ToolsTestData.loadBytes("domain_restore.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_APPROVE)
.setXmlBytes(ToolsTestData.loadBytes("domain_transfer_approve.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_CANCEL)
.setXmlBytes(ToolsTestData.loadBytes("domain_transfer_cancel.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_REJECT)
.setXmlBytes(ToolsTestData.loadBytes("domain_transfer_reject.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_TRANSFER_REQUEST)
.setXmlBytes(ToolsTestData.loadBytes("domain_transfer_request.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.DOMAIN_UPDATE)
.setXmlBytes(ToolsTestData.loadBytes("domain_update_with_secdns.xml").read())
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_CREATE)
.setXmlBytes(ToolsTestData.loadBytes("host_create_complete.xml").read())
.build());
hostDeleteHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_DELETE)
.setXmlBytes(ToolsTestData.loadBytes("host_delete.xml").read())
.build());
// Persist 10 host updates for a total of 25 history entries. Since these also sort last by
// modification time, when these cause all tests to pass, only the first will be recorded and
// the rest will be skipped.
for (int i = 0; i < 10; i++) {
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setType(Type.HOST_UPDATE)
.setXmlBytes(ToolsTestData.loadBytes("host_update.xml").read())
.setTrid(Trid.create(null, String.format("blahtrid-%d", i)))
.setModificationTime(END_OF_TIME)
.build());
}
OteStatsTestHelper.setupHistoryEntries();
}
@Test
public void testSuccess_summarize_allPass() {
Map<String, Object> response =
action.handleJsonRequest(
ImmutableMap.of("summarize", "true", "registrars", ImmutableList.of("blobio")));
assertThat(response)
.containsExactly(
"blobio", "# actions: 31 - Reqs: [----------------] 16/16 - Overall: PASS");
assertThat(getResponse(true))
.isEqualTo("# actions: 31 - Reqs: [----------------] 16/16 - Overall: PASS");
}
@Test
public void testSuccess_summarize_someFailures() {
deleteResource(hostDeleteHistoryEntry);
deleteResource(domainCreateHistoryEntry);
deleteResource(domainRestoreHistoryEntry);
Map<String, Object> response =
action.handleJsonRequest(
ImmutableMap.of("summarize", "true", "registrars", ImmutableList.of("blobio")));
assertThat(response)
.containsExactly(
"blobio", "# actions: 35 - Reqs: [-.-----.------.-] 13/16 - Overall: FAIL");
public void testFailure_summarize_someFailures() {
OteStatsTestHelper.deleteDomainCreateHistoryEntry();
OteStatsTestHelper.deleteDomainRestoreHistoryEntry();
OteStatsTestHelper.deleteHostDeleteHistoryEntry();
assertThat(getResponse(true))
.isEqualTo("# actions: 35 - Reqs: [-.-----.------.-] 13/16 - Overall: FAIL");
}
@Test
public void testSuccess_passNotSummarized() {
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 creates idn: 1\n"
+ "domain creates start date sunrise: 1\n"
@ -209,22 +82,12 @@ public class VerifyOteActionTest {
+ "Requirements passed: 16/16\n"
+ "Overall OT&E status: PASS\n";
Pattern expectedOteStatusPattern = Pattern.compile(expectedOteStatus, Pattern.DOTALL);
assertThat(registrar.getValue().toString()).containsMatch(expectedOteStatusPattern);
}
assertThat(getResponse(false)).containsMatch(expectedOteStatusPattern);
}
@Test
public void testFailure_missingHostDelete() {
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();
OteStatsTestHelper.deleteHostDeleteHistoryEntry();
String expectedOteStatus =
"domain creates idn: 1\n"
+ "domain creates start date sunrise: 1\n"
@ -249,7 +112,18 @@ public class VerifyOteActionTest {
+ "Requirements passed: 15/16\n"
+ "Overall OT&E status: FAIL\n";
Pattern expectedOteStatusPattern = Pattern.compile(expectedOteStatus, Pattern.DOTALL);
assertThat(oteStatus).containsMatch(expectedOteStatusPattern);
}
assertThat(getResponse(false)).containsMatch(expectedOteStatusPattern);
}
private String getResponse(boolean summarize) {
Map<String, Object> response =
action.handleJsonRequest(
ImmutableMap.of(
"summarize",
Boolean.toString(summarize),
"registrars",
ImmutableList.of("blobio")));
assertThat(response).containsKey("blobio");
return response.get("blobio").toString();
}
}