Compare commits

..
Author SHA1 Message Date
Pavlo TkachandGitHub efd5244ebd Add email notification when DNS update fails (#1734) 2022-08-16 12:59:08 -04:00
gbrodmanandGitHub 87e5d19fe5 Allow anchor tenant creation via allocation token behavior (#1735)
* Allow anchor tenant creation via allocation token behavior

This also enforces that non-superusers cannot create registrations on
trademarked names prior to the sunrise period, even if they have an
allocation token with ANCHOR_TENANT behavior.
2022-08-15 12:42:16 -04:00
Lai JiangandGitHub bbb6174c9f Remove InjectExtension (#1739)
It is only used to set the clock used by Ofy, and it admits itself being
an ugly hack...

Also applied IntelliJ suggestions on touched files.
2022-08-12 14:56:53 -04:00
gbrodmanandGitHub 2b826651e6 Create a registry lock permission and corresponding account manager role (#1740)
* Create a registry lock permission and corresponding account manager role

This allows us to distinguish between standard account managers and
users that might have the registry lock permission. This will make the
registry lock password-setting flow easier (user can reset their
password iff they have the REGISTRY_LOCK permission, instead of having a
separate boolean) and allows us to easily determine whether or not a
user should have access to registry lock views in the UI.
2022-08-12 12:18:09 -04:00
61 changed files with 781 additions and 652 deletions
@@ -1300,6 +1300,30 @@ public final class RegistryConfig {
return config.sslCertificateValidation.expirationWarningEmailSubjectText;
}
@Provides
@Config("dnsUpdateFailEmailSubjectText")
public static String provideDnsUpdateFailEmailSubjectText(RegistryConfigSettings config) {
return config.dnsUpdate.dnsUpdateFailEmailSubjectText;
}
@Provides
@Config("dnsUpdateFailEmailBodyText")
public static String provideDnsUpdateFailEmailBodyText(RegistryConfigSettings config) {
return config.dnsUpdate.dnsUpdateFailEmailBodyText;
}
@Provides
@Config("dnsUpdateFailRegistryName")
public static String provideDnsUpdateFailRegistryName(RegistryConfigSettings config) {
return config.dnsUpdate.dnsUpdateFailRegistryName;
}
@Provides
@Config("registrySupportEmail")
public static String provideRegistrySupportEmail(RegistryConfigSettings config) {
return config.dnsUpdate.registrySupportEmail;
}
@Provides
@Config("allowedEcdsaCurves")
public static ImmutableSet<String> provideAllowedEcdsaCurves(RegistryConfigSettings config) {
@@ -42,6 +42,7 @@ public class RegistryConfigSettings {
public RegistryTool registryTool;
public SslCertificateValidation sslCertificateValidation;
public ContactHistory contactHistory;
public DnsUpdate dnsUpdate;
/** Configuration options that apply to the entire App Engine project. */
public static class AppEngine {
@@ -246,4 +247,12 @@ public class RegistryConfigSettings {
public int minMonthsBeforeWipeOut;
public int wipeOutQueryBatchSize;
}
/** Configuration for dns update. */
public static class DnsUpdate {
public String dnsUpdateFailEmailSubjectText;
public String dnsUpdateFailEmailBodyText;
public String dnsUpdateFailRegistryName;
public String registrySupportEmail;
}
}
@@ -477,6 +477,28 @@ contactHistory:
# The batch size for querying ContactHistory table in the database.
wipeOutQueryBatchSize: 500
# Configuration options relevant to the DNS update functionality.
dnsUpdate:
dnsUpdateFailRegistryName: Example name
registrySupportEmail: email@example.com
# Email subject text template to notify partners after repeatedly failing DNS update
dnsUpdateFailEmailSubjectText: "[ACTION REQUIRED]: Incomplete DNS Update"
# Email body text template for failing DNS update that accepts 5 parameters:
# registrar name, domain or host address, 'domain' or 'host' as a string that failed,
# registry support email (see dnsUpdateFailRegistrySupportEmail) and registry display name
dnsUpdateFailEmailBodyText: >
Dear %1$s,
We are contacting you regarding the changes you recently made to one of your %2$ss.
The DNS update for the %3$s %2$s failed to process. Please review your %2$s's DNS records
and ensure that it is valid before trying another update.
If you have any questions or require additional support, please contact us
at %4$s.
Regards,
%5$s
# Configuration options for checking SSL certificates.
sslCertificateValidation:
# A map specifying the maximum amount of days the certificate can be valid.
@@ -14,6 +14,7 @@
package google.registry.dns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.dns.DnsConstants.DNS_PUBLISH_PUSH_QUEUE_NAME;
import static google.registry.dns.DnsModule.PARAM_DNS_WRITER;
import static google.registry.dns.DnsModule.PARAM_DOMAINS;
@@ -22,6 +23,7 @@ import static google.registry.dns.DnsModule.PARAM_LOCK_INDEX;
import static google.registry.dns.DnsModule.PARAM_NUM_PUBLISH_LOCKS;
import static google.registry.dns.DnsModule.PARAM_PUBLISH_TASK_ENQUEUED;
import static google.registry.dns.DnsModule.PARAM_REFRESH_REQUEST_CREATED;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.RequestParameters.PARAM_TLD;
import static google.registry.util.CollectionUtils.nullToEmpty;
@@ -37,6 +39,10 @@ import google.registry.dns.DnsMetrics.ActionStatus;
import google.registry.dns.DnsMetrics.CommitStatus;
import google.registry.dns.DnsMetrics.PublishStatus;
import google.registry.dns.writer.DnsWriter;
import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.tld.Registry;
import google.registry.request.Action;
import google.registry.request.Action.Service;
@@ -46,6 +52,7 @@ import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.lock.LockHandler;
import google.registry.ui.server.SendEmailUtils;
import google.registry.util.Clock;
import google.registry.util.CloudTasksUtils;
import google.registry.util.DomainNameUtils;
@@ -102,6 +109,11 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
private final Clock clock;
private final CloudTasksUtils cloudTasksUtils;
private final Response response;
private final SendEmailUtils sendEmailUtils;
private final String dnsUpdateFailEmailSubjectText;
private final String dnsUpdateFailEmailBodyText;
private final String dnsUpdateFailRegistryName;
private final String registrySupportEmail;
@Inject
public PublishDnsUpdatesAction(
@@ -114,6 +126,10 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
@Parameter(PARAM_HOSTS) Set<String> hosts,
@Parameter(PARAM_TLD) String tld,
@Config("publishDnsUpdatesLockDuration") Duration timeout,
@Config("dnsUpdateFailEmailSubjectText") String dnsUpdateFailEmailSubjectText,
@Config("dnsUpdateFailEmailBodyText") String dnsUpdateFailEmailBodyText,
@Config("dnsUpdateFailRegistryName") String dnsUpdateFailRegistryName,
@Config("registrySupportEmail") String registrySupportEmail,
@Header(APP_ENGINE_RETRY_HEADER) Optional<Integer> appEngineRetryCount,
@Header(CLOUD_TASKS_RETRY_HEADER) Optional<Integer> cloudTasksRetryCount,
DnsQueue dnsQueue,
@@ -122,11 +138,13 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
LockHandler lockHandler,
Clock clock,
CloudTasksUtils cloudTasksUtils,
SendEmailUtils sendEmailUtils,
Response response) {
this.dnsQueue = dnsQueue;
this.dnsWriterProxy = dnsWriterProxy;
this.dnsMetrics = dnsMetrics;
this.timeout = timeout;
this.sendEmailUtils = sendEmailUtils;
this.retryCount =
cloudTasksRetryCount.orElse(
appEngineRetryCount.orElseThrow(
@@ -143,6 +161,10 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
this.clock = clock;
this.cloudTasksUtils = cloudTasksUtils;
this.response = response;
this.dnsUpdateFailEmailBodyText = dnsUpdateFailEmailBodyText;
this.dnsUpdateFailEmailSubjectText = dnsUpdateFailEmailSubjectText;
this.dnsUpdateFailRegistryName = dnsUpdateFailRegistryName;
this.registrySupportEmail = registrySupportEmail;
}
private void recordActionResult(ActionStatus status) {
@@ -209,9 +231,35 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
} else if (retryCount < RETRIES_BEFORE_PERMANENT_FAILURE) {
// If the batch only contains 1 name, allow it more retries
throw e;
} else {
// By the time we get here there's either single domain or a single host
domains.stream()
.findFirst()
.ifPresent(
dn -> {
Optional<Domain> domain = loadByForeignKey(Domain.class, dn, clock.nowUtc());
if (domain.isPresent()) {
notifyWithEmailAboutDnsUpdateFailure(
domain.get().getCurrentSponsorRegistrarId(), dn, false);
} else {
logger.atSevere().log(String.format("Domain entity for %s not found", dn));
}
});
hosts.stream()
.findFirst()
.ifPresent(
hn -> {
Optional<Host> host = loadByForeignKey(Host.class, hn, clock.nowUtc());
if (host.isPresent()) {
notifyWithEmailAboutDnsUpdateFailure(
host.get().getPersistedCurrentSponsorRegistrarId(), hn, true);
} else {
logger.atSevere().log(String.format("Host entity for %s not found", hn));
}
});
}
// If we get here, we should terminate this task as it is likely a perpetually failing task.
// TODO(b/237302821): Send an email notifying partner the dns update failed
recordActionResult(ActionStatus.MAX_RETRIES_EXCEEDED);
response.setStatus(SC_ACCEPTED);
logger.atSevere().withCause(e).log("Terminated task after too many retries");
@@ -219,6 +267,30 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
return null;
}
/** Sends an email to partners regarding a failure during DNS update */
private void notifyWithEmailAboutDnsUpdateFailure(
String registrarId, String hostOrDomainName, Boolean isHost) {
Optional<Registrar> registrar = Registrar.loadByRegistrarIdCached(registrarId);
if (registrar.isPresent()) {
sendEmailUtils.sendEmail(
dnsUpdateFailEmailSubjectText,
String.format(
dnsUpdateFailEmailBodyText,
registrar.get().getRegistrarName(),
hostOrDomainName,
isHost ? "host" : "domain",
registrySupportEmail,
dnsUpdateFailRegistryName),
registrar.get().getContacts().stream()
.filter(c -> c.getTypes().contains(RegistrarPoc.Type.ADMIN))
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableList()));
} else {
logger.atSevere().log(String.format("Could not find registrar %s", registrarId));
}
}
/** Splits the domains and hosts in a batch into smaller batches and adds them to the queue. */
private void splitBatch() {
ImmutableList<String> domainList = ImmutableList.copyOf(domains);
@@ -294,8 +366,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
int domainsPublished = 0;
int domainsRejected = 0;
for (String domain : nullToEmpty(domains)) {
if (!DomainNameUtils.isUnder(
InternetDomainName.from(domain), InternetDomainName.from(tld))) {
if (!DomainNameUtils.isUnder(InternetDomainName.from(domain), InternetDomainName.from(tld))) {
logger.atSevere().log("%s: skipping domain %s not under TLD.", tld, domain);
domainsRejected += 1;
} else {
@@ -310,8 +381,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
int hostsPublished = 0;
int hostsRejected = 0;
for (String host : nullToEmpty(hosts)) {
if (!DomainNameUtils.isUnder(
InternetDomainName.from(host), InternetDomainName.from(tld))) {
if (!DomainNameUtils.isUnder(InternetDomainName.from(host), InternetDomainName.from(tld))) {
logger.atSevere().log("%s: skipping host %s not under TLD.", tld, host);
hostsRejected += 1;
} else {
@@ -153,6 +153,7 @@ import org.joda.time.Duration;
* @error {@link DomainCreateFlow.AnchorTenantCreatePeriodException}
* @error {@link DomainCreateFlow.MustHaveSignedMarksInCurrentPhaseException}
* @error {@link DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException}
* @error {@link DomainCreateFlow.NoTrademarkedRegistrationsBeforeSunriseException}
* @error {@link DomainCreateFlow.SignedMarksOnlyDuringSunriseException}
* @error {@link DomainFlowTmchUtils.NoMarksFoundMatchingDomainException}
* @error {@link DomainFlowTmchUtils.FoundMarkNotYetValidException}
@@ -481,7 +482,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
boolean isValidReservedCreate,
boolean hasSignedMarks)
throws NoGeneralRegistrationsInCurrentPhaseException,
MustHaveSignedMarksInCurrentPhaseException {
MustHaveSignedMarksInCurrentPhaseException,
NoTrademarkedRegistrationsBeforeSunriseException {
// We allow general registration during GA.
TldState currentState = registry.getTldState(now);
if (currentState.equals(GENERAL_AVAILABILITY)) {
@@ -496,16 +498,23 @@ public final class DomainCreateFlow implements TransactionalFlow {
// Bypass most TLD state checks if that behavior is specified by the token
if (behavior.equals(RegistrationBehavior.BYPASS_TLD_STATE)
|| behavior.equals(RegistrationBehavior.ANCHOR_TENANT)) {
// If bypassing TLD state checks, a post-sunrise state is always fine
if (!currentState.equals(START_DATE_SUNRISE)
&& registry.getTldStateTransitions().headMap(now).containsValue(START_DATE_SUNRISE)) {
return;
}
// Non-trademarked names with the state check bypassed are always available
if (!claimsList.getClaimKey(domainLabel).isPresent()) {
return;
}
if (!currentState.equals(START_DATE_SUNRISE)) {
// Trademarked domains cannot be registered until after the sunrise period has ended, unless
// a valid signed mark is provided. Signed marks can only be provided during sunrise.
// Thus, when bypassing TLD state checks, a post-sunrise state is always fine.
if (registry.getTldStateTransitions().headMap(now).containsValue(START_DATE_SUNRISE)) {
return;
} else {
// If sunrise hasn't happened yet, trademarked domains are unavailable
throw new NoTrademarkedRegistrationsBeforeSunriseException(domainLabel);
}
}
}
// Otherwise, signed marks are necessary and sufficient in the sunrise period
if (currentState.equals(START_DATE_SUNRISE)) {
if (!hasSignedMarks) {
@@ -724,6 +733,17 @@ public final class DomainCreateFlow implements TransactionalFlow {
}
}
/** Trademarked domains cannot be registered before the sunrise period. */
static class NoTrademarkedRegistrationsBeforeSunriseException
extends ParameterValuePolicyErrorException {
public NoTrademarkedRegistrationsBeforeSunriseException(String domainLabel) {
super(
String.format(
"The trademarked label %s cannot be registered before the sunrise period.",
domainLabel));
}
}
/** Anchor tenant domain create is for the wrong number of years. */
static class AnchorTenantCreatePeriodException extends ParameterValuePolicyErrorException {
public AnchorTenantCreatePeriodException(int invalidYears) {
@@ -112,6 +112,7 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Add;
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Remove;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.host.Host;
@@ -270,7 +271,13 @@ public class DomainFlowUtils {
&& token.get().getDomainName().get().equals(domainName.toString())) {
return true;
}
// Otherwise check whether the metadata extension is being used by a superuser to specify that
// Otherwise, check to see if we're using the specialized anchor tenant registration behavior on
// the allocation token
if (token.isPresent()
&& token.get().getRegistrationBehavior().equals(RegistrationBehavior.ANCHOR_TENANT)) {
return true;
}
// Otherwise, check whether the metadata extension is being used by a superuser to specify that
// it's an anchor tenant creation.
return metadataExtension.isPresent() && metadataExtension.get().getIsAnchorTenant();
}
@@ -56,7 +56,6 @@ import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationTokenExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.EppInput;
@@ -129,15 +128,12 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
extensionManager.validate();
DateTime now = tm().getTransactionTime();
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
// Currently we do not do anything with this allocation token, but just want it loaded and
// available in this flow in case we use it in the future
Optional<AllocationToken> allocationToken =
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
existingDomain,
Registry.get(existingDomain.getTld()),
registrarId,
now,
eppInput.getSingleExtension(AllocationTokenExtension.class));
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
existingDomain,
Registry.get(existingDomain.getTld()),
registrarId,
now,
eppInput.getSingleExtension(AllocationTokenExtension.class));
verifyOptionalAuthInfo(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
verifyResourceOwnership(registrarId, existingDomain);
@@ -182,9 +178,9 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
getOnlyElement(existingDomain.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW), null);
if (autorenewGrace != null) {
// During a normal transfer, if the domain is in the auto-renew grace period, the auto-renew
// billing event is cancelled and the gaining registrar is charged for the one year renewal.
// billing event is cancelled and the gaining registrar is charged for the one-year renewal.
// But, if the superuser extension is used to request a transfer without an additional year
// then the gaining registrar is not charged for the one year renewal and the losing registrar
// then the gaining registrar is not charged for the one-year renewal and the losing registrar
// still needs to be charged for the auto-renew.
if (billingEvent.isPresent()) {
entitiesToSave.add(
@@ -62,7 +62,6 @@ import google.registry.model.domain.fee.FeeTransferCommandExtension;
import google.registry.model.domain.fee.FeeTransformResponseExtension;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExtension;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationTokenExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
@@ -169,15 +168,12 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
extensionManager.validate();
DateTime now = tm().getTransactionTime();
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
// Currently we do not do anything with this allocation token, but just want it loaded and
// available in this flow in case we use it in the future
Optional<AllocationToken> allocationToken =
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
existingDomain,
Registry.get(existingDomain.getTld()),
gainingClientId,
now,
eppInput.getSingleExtension(AllocationTokenExtension.class));
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
existingDomain,
Registry.get(existingDomain.getTld()),
gainingClientId,
now,
eppInput.getSingleExtension(AllocationTokenExtension.class));
Optional<DomainTransferRequestSuperuserExtension> superuserExtension =
eppInput.getSingleExtension(DomainTransferRequestSuperuserExtension.class);
Period period =
@@ -210,9 +206,12 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
.setId(domainHistoryKey.getId())
.setOtherRegistrarId(existingDomain.getCurrentSponsorRegistrarId());
DateTime automaticTransferTime =
superuserExtension.isPresent()
? now.plusDays(superuserExtension.get().getAutomaticTransferLength())
: now.plus(registry.getAutomaticTransferLength());
superuserExtension
.map(
domainTransferRequestSuperuserExtension ->
now.plusDays(
domainTransferRequestSuperuserExtension.getAutomaticTransferLength()))
.orElseGet(() -> now.plus(registry.getAutomaticTransferLength()));
// If the domain will be in the auto-renew grace period at the moment of transfer, the transfer
// will subsume the autorenew, so we don't add the normal extra year from the transfer.
// The gaining registrar is still billed for the extra year; the losing registrar will get a
@@ -325,7 +324,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
*
* <p>Even if not required, this policy is desirable because it dramatically simplifies the logic
* in transfer flows. Registrars appear to never request 2+ year transfers in practice, and they
* can always decompose an multi-year transfer into a 1-year transfer followed by a manual renewal
* can always decompose a multi-year transfer into a 1-year transfer followed by a manual renewal
* afterwards. The <a href="https://tools.ietf.org/html/rfc5731#section-3.2.4">EPP Domain RFC,
* section 3.2.4</a> says about EPP transfer periods that "the number of units available MAY be
* subject to limits imposed by the server" so we're just limiting the units to one.
@@ -370,7 +369,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
private DomainTransferResponse createResponse(
Period period, Domain existingDomain, Domain newDomain, DateTime now) {
// If the registration were approved this instant, this is what the new expiration would be,
// because we cap at 10 years from the moment of approval. This is different than the server
// because we cap at 10 years from the moment of approval. This is different from the server
// approval new expiration time, which is capped at 10 years from the server approve time.
DateTime approveNowExtendedRegistrationTime =
computeExDateForApprovalTime(existingDomain, now, period);
@@ -63,5 +63,7 @@ public enum ConsolePermission {
/** View announcements in the UI. */
VIEW_ANNOUNCEMENTS,
/** Viewing a record of actions performed in the UI for a particular registrar. */
VIEW_ACTIVITY_LOG
VIEW_ACTIVITY_LOG,
/** View and perform registry locks. */
REGISTRY_LOCK
}
@@ -44,7 +44,8 @@ public class ConsoleRoleDefinitions {
ConsolePermission.VIEW_OPERATIONAL_DATA,
ConsolePermission.SEND_ANNOUNCEMENTS,
ConsolePermission.VIEW_ANNOUNCEMENTS,
ConsolePermission.VIEW_ACTIVITY_LOG);
ConsolePermission.VIEW_ACTIVITY_LOG,
ConsolePermission.REGISTRY_LOCK);
/** Permissions for a registry support lead. */
static final ImmutableSet<ConsolePermission> SUPPORT_LEAD_PERMISSIONS =
@@ -76,10 +77,17 @@ public class ConsoleRoleDefinitions {
ConsolePermission.VIEW_OPERATIONAL_DATA,
ConsolePermission.VIEW_ANNOUNCEMENTS);
/** Permissions for a registrar partner account manager that can perform registry locks. */
static final ImmutableSet<ConsolePermission> ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS =
new ImmutableSet.Builder<ConsolePermission>()
.addAll(ACCOUNT_MANAGER_PERMISSIONS)
.add(ConsolePermission.REGISTRY_LOCK)
.build();
/** Permissions for the tech contact of a registrar. */
static final ImmutableSet<ConsolePermission> TECH_CONTACT_PERMISSIONS =
new ImmutableSet.Builder<ConsolePermission>()
.addAll(ACCOUNT_MANAGER_PERMISSIONS)
.addAll(ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS)
.add(
ConsolePermission.MANAGE_ACCREDITATION,
ConsolePermission.CONFIGURE_EPP_CONNECTION,
@@ -15,6 +15,7 @@
package google.registry.model.console;
import static google.registry.model.console.ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS;
@@ -25,6 +26,8 @@ public enum RegistrarRole {
/** The user is a standard account manager at a registrar. */
ACCOUNT_MANAGER(ACCOUNT_MANAGER_PERMISSIONS),
/** The user is an account manager that can perform registry locks. */
ACCOUNT_MANAGER_WITH_REGISTRY_LOCK(ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS),
/** The user is a technical contact of a registrar. */
TECH_CONTACT(TECH_CONTACT_PERMISSIONS),
/** The user is the primary contact at a registrar. */
@@ -40,12 +40,6 @@ public class User extends ImmutableObject implements Buildable {
/** Roles (which grant permissions) associated with this user. */
private UserRoles userRoles;
/**
* Whether the contact is allowed to set their registry lock password through the registrar
* console. This will be set to false on contact creation and when the user sets a password.
*/
boolean allowedToSetRegistryLockPassword = false;
/**
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
* encoded SHA256 string.
@@ -55,6 +49,10 @@ public class User extends ImmutableObject implements Buildable {
/** Randomly generated hash salt. */
String registryLockPasswordSalt;
public long getId() {
return id;
}
public String getGaiaId() {
return gaiaId;
}
@@ -67,11 +65,7 @@ public class User extends ImmutableObject implements Buildable {
return userRoles;
}
public boolean isAllowedToSetRegistryLockPassword() {
return allowedToSetRegistryLockPassword;
}
public boolean isRegistryLockAllowed() {
public boolean hasRegistryLockPassword() {
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
}
@@ -85,6 +79,22 @@ public class User extends ImmutableObject implements Buildable {
.equals(registryLockPasswordHash);
}
/**
* Whether the user has the registry lock permission on any registrar or globally.
*
* <p>If so, they should be allowed to (re)set their registry lock password.
*/
public boolean hasAnyRegistryLockPermission() {
if (userRoles == null) {
return false;
}
if (userRoles.isAdmin() || userRoles.hasGlobalPermission(ConsolePermission.REGISTRY_LOCK)) {
return true;
}
return userRoles.getRegistrarRoles().values().stream()
.anyMatch(role -> role.hasPermission(ConsolePermission.REGISTRY_LOCK));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
@@ -99,6 +109,7 @@ public class User extends ImmutableObject implements Buildable {
super(user);
}
@Override
public User build() {
checkArgumentNotNull(getInstance().gaiaId, "Gaia ID cannot be null");
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
@@ -123,25 +134,22 @@ public class User extends ImmutableObject implements Buildable {
return this;
}
public Builder setAllowedToSetRegistryLockPassword(boolean allowedToSetRegistryLockPassword) {
if (allowedToSetRegistryLockPassword) {
getInstance().registryLockPasswordSalt = null;
getInstance().registryLockPasswordHash = null;
}
getInstance().allowedToSetRegistryLockPassword = allowedToSetRegistryLockPassword;
public Builder removeRegistryLockPassword() {
getInstance().registryLockPasswordHash = null;
getInstance().registryLockPasswordSalt = null;
return this;
}
public Builder setRegistryLockPassword(String registryLockPassword) {
checkArgument(
getInstance().allowedToSetRegistryLockPassword,
"Not allowed to set registry lock password for this user");
getInstance().hasAnyRegistryLockPermission(), "User has no registry lock permission");
checkArgument(
!getInstance().hasRegistryLockPassword(), "User already has a password, remove it first");
checkArgument(
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
getInstance().registryLockPasswordSalt = base64().encode(SALT_SUPPLIER.get());
getInstance().registryLockPasswordHash =
hashPassword(registryLockPassword, getInstance().registryLockPasswordSalt);
getInstance().allowedToSetRegistryLockPassword = false;
return this;
}
}
@@ -33,7 +33,6 @@ import google.registry.testing.CloudTasksHelper;
import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeSleeper;
import google.registry.testing.InjectExtension;
import google.registry.util.CapturingLogHandler;
import google.registry.util.CloudTasksUtils;
import google.registry.util.JdkLoggerConfig;
@@ -57,12 +56,10 @@ public class AsyncTaskEnqueuerTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private AsyncTaskEnqueuer asyncTaskEnqueuer;
private final CapturingLogHandler logHandler = new CapturingLogHandler();
private final FakeClock clock = new FakeClock(DateTime.parse("2015-05-18T12:34:56Z"));
private CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
@BeforeEach
void beforeEach() {
@@ -34,7 +34,6 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.transaction.QueryComposer.Comparator;
@@ -43,7 +42,6 @@ import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeLockHandler;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
@@ -59,14 +57,11 @@ class DeleteExpiredDomainsActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final FakeResponse response = new FakeResponse();
private DeleteExpiredDomainsAction action;
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
createTld("tld");
EppController eppController =
DaggerEppTestComponent.builder()
@@ -103,7 +98,7 @@ class DeleteExpiredDomainsActionTest {
// A non-autorenewing domain that is past its expiration time and should be deleted.
// (This is the only one that needs a full set of subsidiary resources, for the delete flow to
// to operate on.)
// operate on.)
Domain pendingExpirationDomain = persistNonAutorenewingDomain("fizz.tld");
assertThat(loadByEntity(pendingExpirationDomain).getStatusValues())
@@ -20,7 +20,6 @@ import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.DatabaseHelper.newDomain;
import static google.registry.testing.DatabaseHelper.persistActiveContact;
import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources;
import static google.registry.testing.DatabaseHelper.persistDomainWithPendingTransfer;
@@ -35,14 +34,12 @@ import google.registry.model.domain.Domain;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.ofy.Ofy;
import google.registry.request.Response;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
@@ -62,16 +59,13 @@ public class ResaveEntityActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@Mock private Response response;
private final FakeClock clock = new FakeClock(DateTime.parse("2016-02-11T10:00:00Z"));
private AsyncTaskEnqueuer asyncTaskEnqueuer;
private CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
asyncTaskEnqueuer =
AsyncTaskEnqueuerTest.createForTesting(
cloudTasksHelper.getTestCloudTasksUtils(), clock, Duration.ZERO);
@@ -15,7 +15,6 @@
package google.registry.batch;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.testing.AppEngineExtension.makeRegistrar1;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -40,7 +39,6 @@ import google.registry.model.registrar.RegistrarPoc.Type;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import google.registry.util.SelfSignedCaCertificate;
import google.registry.util.SendEmailService;
import java.security.cert.X509Certificate;
@@ -57,11 +55,11 @@ class SendExpiringCertificateNotificationEmailActionTest {
private static final String EXPIRATION_WARNING_EMAIL_BODY_TEXT =
" Dear %1$s,\n"
+ "\n"
+ '\n'
+ "We would like to inform you that your %2$s certificate will expire at %3$s."
+ "\n"
+ '\n'
+ " Kind update your account using the following steps: "
+ "\n"
+ '\n'
+ " 1. Navigate to support and login using your %4$s@registry.example credentials.\n"
+ " 2. Click Settings -> Privacy on the top left corner.\n"
+ " 3. Click Edit and enter certificate string."
@@ -75,7 +73,6 @@ class SendExpiringCertificateNotificationEmailActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("2021-05-24T20:21:22Z"));
private final SendEmailService sendEmailService = mock(SendEmailService.class);
private CertificateChecker certificateChecker;
@@ -708,7 +705,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
}
/** Returns persisted sample contacts with a customized contact email type. */
private ImmutableList<RegistrarPoc> persistSampleContacts(
private static ImmutableList<RegistrarPoc> persistSampleContacts(
Registrar registrar, RegistrarPoc.Type emailType) {
return persistSimpleResources(
ImmutableList.of(
@@ -38,7 +38,6 @@ import google.registry.testing.AppEngineExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -102,7 +101,6 @@ class WipeOutContactHistoryPiiActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("2021-08-26T20:21:22Z"));
private FakeResponse response;
@@ -24,13 +24,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import google.registry.model.ofy.Ofy;
import google.registry.request.HttpException.NotFoundException;
import google.registry.request.RequestModule;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.CloudTasksHelper.CloudTasksHelperModule;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
@@ -47,8 +45,6 @@ public final class DnsInjectionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final HttpServletRequest req = mock(HttpServletRequest.class);
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
private final StringWriter httpOutput = new StringWriter();
@@ -58,7 +54,6 @@ public final class DnsInjectionTest {
@BeforeEach
void beforeEach() throws Exception {
inject.setStaticField(Ofy.class, "clock", clock);
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
component =
DaggerDnsTestComponent.builder()
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.dns.DnsMetrics.ActionStatus;
@@ -45,7 +46,6 @@ import google.registry.dns.DnsMetrics.CommitStatus;
import google.registry.dns.DnsMetrics.PublishStatus;
import google.registry.dns.writer.DnsWriter;
import google.registry.model.domain.Domain;
import google.registry.model.ofy.Ofy;
import google.registry.model.tld.Registry;
import google.registry.request.HttpException.ServiceUnavailableException;
import google.registry.request.lock.LockHandler;
@@ -55,14 +55,18 @@ import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeLockHandler;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import google.registry.ui.server.SendEmailUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.Optional;
import java.util.Set;
import javax.mail.internet.InternetAddress;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.ArgumentCaptor;
/** Unit tests for {@link PublishDnsUpdatesAction}. */
public class PublishDnsUpdatesActionTest {
@@ -71,7 +75,6 @@ public class PublishDnsUpdatesActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("1971-01-01TZ"));
private final FakeResponse response = new FakeResponse();
private final FakeLockHandler lockHandler = new FakeLockHandler(true);
@@ -80,10 +83,18 @@ public class PublishDnsUpdatesActionTest {
private final DnsQueue dnsQueue = mock(DnsQueue.class);
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
private PublishDnsUpdatesAction action;
private final SendEmailService emailService = mock(SendEmailService.class);
private SendEmailUtils sendEmailUtils;
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
void beforeEach() throws Exception {
sendEmailUtils =
new SendEmailUtils(
new InternetAddress("outgoing@registry.example"),
"UnitTest Registry",
ImmutableList.of("notification@test.example", "notification2@test.example"),
emailService);
createTld("xn--q9jyb4c");
persistResource(
Registry.get("xn--q9jyb4c")
@@ -142,6 +153,10 @@ public class PublishDnsUpdatesActionTest {
hosts,
tld,
Duration.standardSeconds(10),
"Subj",
"Body %1$s %2$s %3$s %4$s %5$s",
"registry@test.com",
"awesomeRegistry",
Optional.ofNullable(retryCount),
Optional.empty(),
dnsQueue,
@@ -150,6 +165,7 @@ public class PublishDnsUpdatesActionTest {
lockHandler,
clock,
cloudTasksHelper.getTestCloudTasksUtils(),
sendEmailUtils,
response);
}
@@ -385,6 +401,37 @@ public class PublishDnsUpdatesActionTest {
assertThat(response.getStatus()).isEqualTo(SC_ACCEPTED);
}
@Test
void testDomainDnsUpdateRetriesExhausted_emailIsSent() {
action =
createAction("xn--q9jyb4c", ImmutableSet.of("example.xn--q9jyb4c"), ImmutableSet.of(), 10);
doThrow(new RuntimeException()).when(dnsWriter).commit();
action.run();
ArgumentCaptor<EmailMessage> contentCaptor = ArgumentCaptor.forClass(EmailMessage.class);
verify(emailService).sendEmail(contentCaptor.capture());
EmailMessage emailMessage = contentCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo("Subj");
assertThat(emailMessage.body())
.isEqualTo(
"Body The Registrar example.xn--q9jyb4c domain awesomeRegistry registry@test.com");
}
@Test
void testHostDnsUpdateRetriesExhausted_emailIsSent() {
action =
createAction(
"xn--q9jyb4c", ImmutableSet.of(), ImmutableSet.of("ns1.example.xn--q9jyb4c"), 10);
doThrow(new RuntimeException()).when(dnsWriter).commit();
action.run();
ArgumentCaptor<EmailMessage> contentCaptor = ArgumentCaptor.forClass(EmailMessage.class);
verify(emailService).sendEmail(contentCaptor.capture());
EmailMessage emailMessage = contentCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo("Subj");
assertThat(emailMessage.body())
.isEqualTo(
"Body The Registrar ns1.example.xn--q9jyb4c host awesomeRegistry registry@test.com");
}
@Test
void testTaskMissingRetryHeaders_throwsException() {
IllegalStateException thrown =
@@ -39,13 +39,12 @@ import google.registry.model.domain.Domain;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.model.ofy.Ofy;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
@@ -76,8 +75,6 @@ public class DnsUpdateWriterTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@Mock private DnsMessageTransport mockResolver;
@Captor private ArgumentCaptor<Update> updateCaptor;
@@ -87,8 +84,6 @@ public class DnsUpdateWriterTest {
@BeforeEach
void beforeEach() throws Exception {
inject.setStaticField(Ofy.class, "clock", clock);
createTld("tld");
when(mockResolver.send(any(Update.class))).thenReturn(messageWithResponseCode(Rcode.NOERROR));
@@ -418,23 +413,23 @@ public class DnsUpdateWriterTest {
assertThat(thrown).hasMessageThat().contains("SERVFAIL");
}
private void assertThatUpdatedZoneIs(Update update, String zoneName) {
Record[] zoneRecords = update.getSectionArray(Section.ZONE);
assertThat(zoneRecords[0].getName().toString()).isEqualTo(zoneName);
private static void assertThatUpdatedZoneIs(Update update, String zoneName) {
List<Record> zoneRecords = update.getSection(Section.ZONE);
assertThat(zoneRecords.get(0).getName().toString()).isEqualTo(zoneName);
}
private void assertThatTotalUpdateSetsIs(Update update, int count) {
private static void assertThatTotalUpdateSetsIs(Update update, int count) {
assertThat(update.getSectionRRsets(Section.UPDATE)).hasSize(count);
}
private void assertThatUpdateDeletes(Update update, String resourceName, int recordType) {
private static void assertThatUpdateDeletes(Update update, String resourceName, int recordType) {
ImmutableList<Record> deleted = findUpdateRecords(update, resourceName, recordType);
// There's only an empty (i.e. "delete") record.
assertThat(deleted.get(0).rdataToString()).hasLength(0);
assertThat(deleted).hasSize(1);
}
private void assertThatUpdateAdds(
private static void assertThatUpdateAdds(
Update update, String resourceName, int recordType, String... resourceData) {
ArrayList<String> expectedData = new ArrayList<>();
Collections.addAll(expectedData, resourceData);
@@ -446,7 +441,7 @@ public class DnsUpdateWriterTest {
assertThat(actualData).containsExactlyElementsIn(expectedData);
}
private ImmutableList<Record> findUpdateRecords(
private static ImmutableList<Record> findUpdateRecords(
Update update, String resourceName, int recordType) {
for (RRset set : update.getSectionRRsets(Section.UPDATE)) {
if (set.getName().toString().equals(resourceName) && set.getType() == recordType) {
@@ -460,7 +455,7 @@ public class DnsUpdateWriterTest {
throw new AssertionError();
}
private Message messageWithResponseCode(int responseCode) {
private static Message messageWithResponseCode(int responseCode) {
Message message = new Message();
message.getHeader().setOpcode(Opcode.UPDATE);
message.getHeader().setFlag(Flags.QR);
@@ -33,16 +33,13 @@ import com.google.cloud.storage.contrib.nio.testing.LocalStorageHelper;
import com.google.common.collect.ImmutableList;
import com.google.common.net.MediaType;
import google.registry.gcs.GcsUtils;
import google.registry.model.ofy.Ofy;
import google.registry.model.tld.Registry;
import google.registry.model.tld.Registry.TldType;
import google.registry.storage.drive.DriveConnection;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.ArgumentCaptor;
@@ -51,8 +48,8 @@ import org.mockito.ArgumentCaptor;
class ExportDomainListsActionTest {
private final GcsUtils gcsUtils = new GcsUtils(LocalStorageHelper.getOptions());
private DriveConnection driveConnection = mock(DriveConnection.class);
private ArgumentCaptor<byte[]> bytesExportedToDrive = ArgumentCaptor.forClass(byte[].class);
private final DriveConnection driveConnection = mock(DriveConnection.class);
private final ArgumentCaptor<byte[]> bytesExportedToDrive = ArgumentCaptor.forClass(byte[].class);
private ExportDomainListsAction action;
private final FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T02:02:02Z"));
@@ -60,11 +57,6 @@ class ExportDomainListsActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withLocalModules().withTaskQueue().build();
@Order(Order.DEFAULT - 1)
@RegisterExtension
public final InjectExtension inject =
new InjectExtension().withStaticFieldOverride(Ofy.class, "clock", clock);
@BeforeEach
void beforeEach() {
createTld("tld");
@@ -42,7 +42,6 @@ import google.registry.request.Response;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeSleeper;
import google.registry.testing.InjectExtension;
import google.registry.util.Retrier;
import java.io.IOException;
import org.junit.jupiter.api.Test;
@@ -59,8 +58,6 @@ public class SyncGroupMembersActionTest {
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final DirectoryGroupsConnection connection = mock(DirectoryGroupsConnection.class);
private final Response response = mock(Response.class);
@@ -76,8 +73,7 @@ public class SyncGroupMembersActionTest {
@Test
void test_getGroupEmailAddressForContactType_convertsToLowercase() {
assertThat(
getGroupEmailAddressForContactType(
"SomeRegistrar", RegistrarPoc.Type.ADMIN, "domain-registry.example"))
getGroupEmailAddressForContactType("SomeRegistrar", ADMIN, "domain-registry.example"))
.isEqualTo("someregistrar-primary-contacts@domain-registry.example");
}
@@ -35,14 +35,12 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.model.common.Cursor;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -60,8 +58,6 @@ public class SyncRegistrarsSheetTest {
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@Captor private ArgumentCaptor<ImmutableList<ImmutableMap<String, String>>> rowsCaptor;
@Mock private SheetSynchronizer sheetSynchronizer;
@@ -76,7 +72,6 @@ public class SyncRegistrarsSheetTest {
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
createTld("example");
// Remove Registrar entities created by AppEngineExtension (and RegistrarContact's, for jpa).
// We don't do this for ofy because ofy's loadAllOf() can't be called in a transaction but
@@ -215,7 +210,7 @@ public class SyncRegistrarsSheetTest {
+ "Phone number and email visible in domain WHOIS query as "
+ "Registrar Abuse contact info: No\n"
+ "Registrar-Console access: No\n"
+ "\n"
+ '\n'
+ "John Doe\n"
+ "john.doe@example.tld\n"
+ "Tel: +1.1234567890\n"
@@ -31,13 +31,11 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import google.registry.flows.EppTestComponent.FakesAndMocksModule;
import google.registry.model.domain.Domain;
import google.registry.model.ofy.Ofy;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.EppLoader;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -52,14 +50,11 @@ class EppPointInTimeTest {
final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
@RegisterExtension final InjectExtension inject = new InjectExtension();
private EppLoader eppLoader;
@BeforeEach
void beforeEach() {
createTld("tld");
inject.setStaticField(Ofy.class, "clock", clock);
}
private void runFlow() throws Exception {
@@ -36,7 +36,6 @@ import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.eppcommon.EppXmlTransformer;
import google.registry.model.ofy.Ofy;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.model.tld.Registry;
import google.registry.monitoring.whitebox.EppMetric;
@@ -44,7 +43,6 @@ import google.registry.persistence.VKey;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import google.registry.util.ProxyHttpHeaders;
import java.util.Map;
import java.util.Objects;
@@ -52,16 +50,12 @@ import java.util.Optional;
import javax.annotation.Nullable;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
public class EppTestCase {
private static final MediaType APPLICATION_EPP_XML_UTF8 =
MediaType.create("application", "epp+xml").withCharset(UTF_8);
@RegisterExtension public final InjectExtension inject = new InjectExtension();
protected final FakeClock clock = new FakeClock();
private SessionMetadata sessionMetadata;
@@ -69,12 +63,6 @@ public class EppTestCase {
private EppMetric.Builder eppMetricBuilder;
private boolean isSuperuser;
@BeforeEach
public void beforeEachEppTestCase() {
// For transactional flows
inject.setStaticField(Ofy.class, "clock", clock);
}
/**
* Set the transport credentials.
*
@@ -92,14 +80,14 @@ public class EppTestCase {
public class CommandAsserter {
private final String inputFilename;
private @Nullable final Map<String, String> inputSubstitutions;
@Nullable private final Map<String, String> inputSubstitutions;
private DateTime now;
private CommandAsserter(
String inputFilename, @Nullable Map<String, String> inputSubstitutions) {
this.inputFilename = inputFilename;
this.inputSubstitutions = inputSubstitutions;
this.now = clock.nowUtc();
now = clock.nowUtc();
}
public CommandAsserter atTime(DateTime now) {
@@ -121,9 +109,88 @@ public class EppTestCase {
inputFilename, inputSubstitutions, outputFilename, outputSubstitutions, now);
}
public String hasSuccessfulLogin() throws Exception {
return assertLoginCommandAndResponse(inputFilename, inputSubstitutions, null, clock.nowUtc());
public void hasSuccessfulLogin() throws Exception {
assertLoginCommandAndResponse(inputFilename, inputSubstitutions, null, clock.nowUtc());
}
private void assertLoginCommandAndResponse(
String inputFilename,
@Nullable Map<String, String> inputSubstitutions,
@Nullable Map<String, String> outputSubstitutions,
DateTime now)
throws Exception {
String outputFilename = "generic_success_response.xml";
clock.setTo(now);
String input = loadFile(EppTestCase.class, inputFilename, inputSubstitutions);
String expectedOutput = loadFile(EppTestCase.class, outputFilename, outputSubstitutions);
setUpSession();
FakeResponse response = executeXmlCommand(input);
// Check that the logged-in header was added to the response
assertThat(response.getHeaders())
.isEqualTo(ImmutableMap.of(ProxyHttpHeaders.LOGGED_IN, "true"));
verifyAndReturnOutput(response.getPayload(), expectedOutput, inputFilename, outputFilename);
}
private String assertCommandAndResponse(
String inputFilename,
@Nullable Map<String, String> inputSubstitutions,
String outputFilename,
@Nullable Map<String, String> outputSubstitutions,
DateTime now)
throws Exception {
clock.setTo(now);
String input = loadFile(EppTestCase.class, inputFilename, inputSubstitutions);
String expectedOutput = loadFile(EppTestCase.class, outputFilename, outputSubstitutions);
setUpSession();
FakeResponse response = executeXmlCommand(input);
// Checks that the Logged-In header is not in the response. If testing the login command, use
// assertLoginCommandAndResponse instead of this method.
assertThat(response.getHeaders()).doesNotContainEntry(ProxyHttpHeaders.LOGGED_IN, "true");
return verifyAndReturnOutput(
response.getPayload(), expectedOutput, inputFilename, outputFilename);
}
}
private void setUpSession() {
if (sessionMetadata == null) {
sessionMetadata =
new HttpSessionMetadata(new FakeHttpSession()) {
@Override
public void invalidate() {
// When a session is invalidated, reset the sessionMetadata field.
super.invalidate();
sessionMetadata = null;
}
};
}
}
private FakeResponse executeXmlCommand(String inputXml) {
EppRequestHandler handler = new EppRequestHandler();
FakeResponse response = new FakeResponse();
handler.response = response;
FakesAndMocksModule fakesAndMocksModule = FakesAndMocksModule.create(clock);
eppMetricBuilder = fakesAndMocksModule.getMetricBuilder();
handler.eppController =
DaggerEppTestComponent.builder()
.fakesAndMocksModule(fakesAndMocksModule)
.build()
.startRequest()
.eppController();
handler.executeEpp(
sessionMetadata,
credentials,
EppRequestSource.UNIT_TEST,
false, // Not dryRun.
isSuperuser,
inputXml.getBytes(UTF_8));
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getContentType()).isEqualTo(APPLICATION_EPP_XML_UTF8);
return response;
}
protected CommandAsserter assertThatCommand(String inputFilename) {
@@ -148,63 +215,7 @@ public class EppTestCase {
assertThatCommand("logout.xml").hasResponse("logout_response.xml");
}
private String assertLoginCommandAndResponse(
String inputFilename,
@Nullable Map<String, String> inputSubstitutions,
@Nullable Map<String, String> outputSubstitutions,
DateTime now)
throws Exception {
String outputFilename = "generic_success_response.xml";
clock.setTo(now);
String input = loadFile(EppTestCase.class, inputFilename, inputSubstitutions);
String expectedOutput = loadFile(EppTestCase.class, outputFilename, outputSubstitutions);
setUpSession();
FakeResponse response = executeXmlCommand(input);
// Check that the logged-in header was added to the response
assertThat(response.getHeaders())
.isEqualTo(ImmutableMap.of(ProxyHttpHeaders.LOGGED_IN, "true"));
return verifyAndReturnOutput(
response.getPayload(), expectedOutput, inputFilename, outputFilename);
}
private String assertCommandAndResponse(
String inputFilename,
@Nullable Map<String, String> inputSubstitutions,
String outputFilename,
@Nullable Map<String, String> outputSubstitutions,
DateTime now)
throws Exception {
clock.setTo(now);
String input = loadFile(EppTestCase.class, inputFilename, inputSubstitutions);
String expectedOutput = loadFile(EppTestCase.class, outputFilename, outputSubstitutions);
setUpSession();
FakeResponse response = executeXmlCommand(input);
// Checks that the Logged-In header is not in the response. If testing the login command, use
// assertLoginCommandAndResponse instead of this method.
assertThat(response.getHeaders()).doesNotContainEntry(ProxyHttpHeaders.LOGGED_IN, "true");
return verifyAndReturnOutput(
response.getPayload(), expectedOutput, inputFilename, outputFilename);
}
private void setUpSession() {
if (sessionMetadata == null) {
sessionMetadata =
new HttpSessionMetadata(new FakeHttpSession()) {
@Override
public void invalidate() {
// When a session is invalidated, reset the sessionMetadata field.
super.invalidate();
EppTestCase.this.sessionMetadata = null;
}
};
}
}
private String verifyAndReturnOutput(
private static String verifyAndReturnOutput(
String actualOutput, String expectedOutput, String inputFilename, String outputFilename)
throws Exception {
// Run the resulting xml through the unmarshaller to verify that it was valid.
@@ -219,30 +230,6 @@ public class EppTestCase {
return actualOutput;
}
private FakeResponse executeXmlCommand(String inputXml) {
EppRequestHandler handler = new EppRequestHandler();
FakeResponse response = new FakeResponse();
handler.response = response;
FakesAndMocksModule fakesAndMocksModule = FakesAndMocksModule.create(clock);
eppMetricBuilder = fakesAndMocksModule.getMetricBuilder();
handler.eppController =
DaggerEppTestComponent.builder()
.fakesAndMocksModule(fakesAndMocksModule)
.build()
.startRequest()
.eppController();
handler.executeEpp(
sessionMetadata,
credentials,
EppRequestSource.UNIT_TEST,
false, // Not dryRun.
isSuperuser,
inputXml.getBytes(UTF_8));
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getContentType()).isEqualTo(APPLICATION_EPP_XML_UTF8);
return response;
}
EppMetric getRecordedEppMetric() {
return eppMetricBuilder.build();
}
@@ -39,7 +39,6 @@ import google.registry.model.domain.GracePeriod;
import google.registry.model.eppcommon.ProtocolDefinition;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.ofy.Ofy;
import google.registry.model.reporting.HistoryEntryDao;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.testing.AppEngineExtension;
@@ -48,7 +47,6 @@ import google.registry.testing.DatabaseHelper;
import google.registry.testing.EppLoader;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.InjectExtension;
import google.registry.testing.TestDataHelper;
import google.registry.util.TypeUtils.TypeInstantiator;
import google.registry.xml.ValidationMode;
@@ -58,7 +56,6 @@ import java.util.Map;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension;
/**
@@ -89,13 +86,6 @@ public abstract class FlowTestCase<F extends Flow> {
private EppMetric.Builder eppMetricBuilder;
// Set the clock for transactional flows. We have to order this before the AppEngineExtension
// which populates data.
@Order(value = Order.DEFAULT - 1)
@RegisterExtension
final InjectExtension inject =
new InjectExtension().withStaticFieldOverride(Ofy.class, "clock", clock);
@RegisterExtension
final AppEngineExtension appEngine =
AppEngineExtension.builder().withClock(clock).withCloudSql().withTaskQueue().build();
@@ -171,13 +161,13 @@ public abstract class FlowTestCase<F extends Flow> {
}
/**
* Helper to facilitate comparison of maps of GracePeriods to BillingEvents. This takes a map of
* GracePeriods to BillingEvents and returns a map of the same entries that ignores the keys
* on the grace periods and the IDs on the billing events (by setting them all to the same dummy
* Helper to facilitate comparison of maps of GracePeriods to BillingEvents. This takes a map of
* GracePeriods to BillingEvents and returns a map of the same entries that ignores the keys on
* the grace periods and the IDs on the billing events (by setting them all to the same dummy
* values), since they will vary between instantiations even when the other data is the same.
*/
private ImmutableMap<GracePeriod, BillingEvent>
canonicalizeGracePeriods(ImmutableMap<GracePeriod, ? extends BillingEvent> gracePeriods) {
private static ImmutableMap<GracePeriod, BillingEvent> canonicalizeGracePeriods(
ImmutableMap<GracePeriod, ? extends BillingEvent> gracePeriods) {
ImmutableMap.Builder<GracePeriod, BillingEvent> builder = new ImmutableMap.Builder<>();
for (Map.Entry<GracePeriod, ? extends BillingEvent> entry : gracePeriods.entrySet()) {
builder.put(
@@ -210,7 +200,7 @@ public abstract class FlowTestCase<F extends Flow> {
* keys match the expected map of grace periods to billing events. For the expected map, the keys
* on the grace periods and IDs on the billing events are ignored.
*/
protected void assertGracePeriods(
protected static void assertGracePeriods(
Iterable<GracePeriod> actual, ImmutableMap<GracePeriod, ? extends BillingEvent> expected) {
assertThat(canonicalizeGracePeriods(Maps.toMap(actual, FlowTestCase::expandGracePeriod)))
.isEqualTo(canonicalizeGracePeriods(expected));
@@ -258,7 +248,7 @@ public abstract class FlowTestCase<F extends Flow> {
return runFlow(CommitMode.LIVE, UserPrivileges.NORMAL);
}
/** Shortcut to call {@link #runFlow(CommitMode, UserPrivileges)} as super user and live run. */
/** Shortcut to call {@link #runFlow(CommitMode, UserPrivileges)} as superuser and live run. */
protected EppOutput runFlowAsSuperuser() throws Exception {
return runFlow(CommitMode.LIVE, UserPrivileges.SUPERUSER);
}
@@ -82,6 +82,7 @@ import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.domain.DomainCreateFlow.AnchorTenantCreatePeriodException;
import google.registry.flows.domain.DomainCreateFlow.MustHaveSignedMarksInCurrentPhaseException;
import google.registry.flows.domain.DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException;
import google.registry.flows.domain.DomainCreateFlow.NoTrademarkedRegistrationsBeforeSunriseException;
import google.registry.flows.domain.DomainCreateFlow.RenewalPriceInfo;
import google.registry.flows.domain.DomainCreateFlow.SignedMarksOnlyDuringSunriseException;
import google.registry.flows.domain.DomainFlowTmchUtils.FoundMarkExpiredException;
@@ -2734,7 +2735,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
}
@Test
void testSuccess_quietPeriod_skipTldCheckWithToken() throws Exception {
void testSuccess_quietPeriod_skipTldStateCheckWithToken() throws Exception {
AllocationToken token =
persistResource(
new AllocationToken.Builder()
@@ -2813,7 +2814,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.build());
persistContactsAndHosts();
setEppInput("domain_create_allocationtoken_claims.xml");
assertThrows(NoGeneralRegistrationsInCurrentPhaseException.class, this::runFlow);
assertThrows(NoTrademarkedRegistrationsBeforeSunriseException.class, this::runFlow);
}
@Test
@@ -2844,4 +2845,285 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(), allocationToken);
}
// ________________________________
// Anchor tenant in quiet period before sunrise:
// Only non-trademarked domains are allowed.
// ________________________________
@Test
void testSuccess_anchorTenant_quietPeriodBeforeSunrise_nonTrademarked_viaToken()
throws Exception {
createTld("tld", QUIET_PERIOD);
AllocationToken token =
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setDomainName("example.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
persistContactsAndHosts();
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
}
@Test
void testFailure_anchorTenant_quietPeriodBeforeSunrise_trademarked_withoutClaims_viaToken() {
createTld("tld", QUIET_PERIOD);
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setDomainName("test-validate.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld", "YEARS", "2"));
persistContactsAndHosts();
assertThrows(NoTrademarkedRegistrationsBeforeSunriseException.class, this::runFlow);
}
@Test
void testFailure_anchorTenant_quietPeriodBeforeSunrise_trademarked_withClaims_viaToken() {
createTld("tld", QUIET_PERIOD);
persistResource(
allocationToken
.asBuilder()
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
setEppInput("domain_create_allocationtoken_claims.xml");
persistContactsAndHosts();
assertThrows(NoTrademarkedRegistrationsBeforeSunriseException.class, this::runFlow);
}
// ________________________________
// Anchor tenant in sunrise:
// Non-trademarked domains and trademarked domains with signed marks are allowed
// ________________________________
@Test
void testSuccess_anchorTenant_inSunrise_nonTrademarked_viaToken() throws Exception {
createTld("tld", START_DATE_SUNRISE);
AllocationToken token =
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setDomainName("example.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
persistContactsAndHosts();
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
}
@Test
void testSuccess_anchorTenant_inSunrise_trademarked_withSignedMark_viaToken() throws Exception {
createTld("tld", START_DATE_SUNRISE);
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
setEppInput(
"domain_create_registration_encoded_signed_mark_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld"));
persistResource(
allocationToken
.asBuilder()
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.setDomainName("test-validate.tld")
.build());
persistContactsAndHosts();
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE, ANCHOR_TENANT), allocationToken);
}
@Test
void testFailure_anchorTenant_inSunrise_trademarked_withoutSignedMark_viaToken() {
createTld("tld", START_DATE_SUNRISE);
persistResource(
new AllocationToken.Builder()
.setTokenType(SINGLE_USE)
.setToken("abc123")
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
persistContactsAndHosts();
assertThrows(MustHaveSignedMarksInCurrentPhaseException.class, this::runFlow);
}
@Test
void testFailure_anchorTenant_inSunrise_trademarked_withoutSignedMark_withClaims_viaToken() {
createTld("tld", START_DATE_SUNRISE);
persistResource(
allocationToken
.asBuilder()
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
setEppInput("domain_create_allocationtoken_claims.xml");
persistContactsAndHosts();
assertThrows(MustHaveSignedMarksInCurrentPhaseException.class, this::runFlow);
}
// ________________________________
// Anchor tenant in a post-sunrise quiet period:
// Non-trademarked domains and trademarked domains with claims are allowed.
// ________________________________
@Test
void testSuccess_anchorTenant_quietPeriodAfterSunrise_nonTrademarked_viaToken() throws Exception {
persistResource(
Registry.get("tld")
.asBuilder()
.setTldStateTransitions(
ImmutableSortedMap.of(
START_OF_TIME,
QUIET_PERIOD,
clock.nowUtc().minusYears(1),
START_DATE_SUNRISE,
clock.nowUtc().minusMonths(1),
QUIET_PERIOD))
.build());
AllocationToken token =
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.setDomainName("example.tld")
.build());
persistContactsAndHosts();
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
}
@Test
void testSuccess_anchorTenant_quietPeriodAfterSunrise_trademarked_withClaims_viaToken()
throws Exception {
persistResource(
Registry.get("tld")
.asBuilder()
.setTldStateTransitions(
ImmutableSortedMap.of(
START_OF_TIME,
QUIET_PERIOD,
clock.nowUtc().minusYears(1),
START_DATE_SUNRISE,
clock.nowUtc().minusMonths(1),
QUIET_PERIOD))
.build());
persistResource(
allocationToken
.asBuilder()
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
setEppInput("domain_create_allocationtoken_claims.xml");
persistContactsAndHosts();
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
}
@Test
void testFailure_anchorTenant_quietPeriodAfterSunrise_trademarked_withoutClaims_viaToken() {
persistResource(
Registry.get("tld")
.asBuilder()
.setTldStateTransitions(
ImmutableSortedMap.of(
START_OF_TIME,
QUIET_PERIOD,
clock.nowUtc().minusYears(1),
START_DATE_SUNRISE,
clock.nowUtc().minusMonths(1),
QUIET_PERIOD))
.build());
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
persistContactsAndHosts();
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example-one.tld", "YEARS", "2"));
assertThrows(MissingClaimsNoticeException.class, this::runFlow);
}
// ________________________________
// Anchor tenant in GA:
// Non-trademarked domains and trademarked domains with claims are allowed.
// ________________________________
@Test
void testSuccess_anchorTenant_ga_nonTrademarked_viaToken() throws Exception {
AllocationToken token =
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.setDomainName("example.tld")
.build());
persistContactsAndHosts();
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
}
@Test
void testSuccess_anchorTenant_ga_trademarked_withClaims_viaToken() throws Exception {
persistResource(
allocationToken
.asBuilder()
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
setEppInput("domain_create_allocationtoken_claims.xml");
persistContactsAndHosts();
runFlow();
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
}
@Test
void testFailure_anchorTenant_ga_trademarked_withoutClaims_viaToken() {
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setDomainName("example-one.tld")
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build());
persistContactsAndHosts();
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example-one.tld", "YEARS", "2"));
assertThrows(MissingClaimsNoticeException.class, this::runFlow);
}
@Test
void testFailure_anchorTenant_mismatchedName_viaToken() throws Exception {
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.setDomainName("example.tld")
.build());
persistContactsAndHosts();
setEppInput(
"domain_create_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example-one.tld", "YEARS", "2"));
assertThrows(AllocationTokenNotValidForDomainException.class, this::runFlow);
}
}
@@ -16,12 +16,9 @@ package google.registry.model;
import static org.joda.time.DateTimeZone.UTC;
import google.registry.model.ofy.Ofy;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Base class of all unit tests for entities which are persisted to Datastore via Objectify. */
@@ -41,8 +38,6 @@ public abstract class EntityTestCase {
@RegisterExtension public final AppEngineExtension appEngine;
@RegisterExtension public InjectExtension inject = new InjectExtension();
protected EntityTestCase() {
this(JpaEntityCoverageCheck.DISABLED);
}
@@ -55,9 +50,4 @@ public abstract class EntityTestCase {
.withClock(fakeClock)
.build();
}
@BeforeEach
public void injectClock() {
inject.setStaticField(Ofy.class, "clock", fakeClock);
}
}
@@ -23,10 +23,8 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.time.DateTimeZone.UTC;
import google.registry.model.host.Host;
import google.registry.model.ofy.Ofy;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
@@ -42,12 +40,9 @@ class EppResourceUtilsTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@BeforeEach
void beforeEach() {
createTld("tld");
inject.setStaticField(Ofy.class, "clock", clock);
}
@Test
@@ -49,21 +49,30 @@ public class ConsoleRoleDefinitionsTest {
// Note: we can't use Truth's IterableSubject to check all the subset/superset restrictions
// because it is generic to iterables and doesn't know about sets.
assertThat(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS))
.isFalse();
assertThat(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS))
.isFalse();
assertThat(
ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS))
.isFalse();
}
}
@@ -58,4 +58,33 @@ public class UserTest {
builder.setUserRoles(new UserRoles.Builder().build());
builder.build();
}
@Test
void testRegistryLockPassword() {
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
new User.Builder()
.setUserRoles(new UserRoles.Builder().build())
.setRegistryLockPassword("foobar")))
.hasMessageThat()
.isEqualTo("User has no registry lock permission");
User user =
new User.Builder()
.setGaiaId("gaiaId")
.setEmailAddress("email@email.com")
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
assertThat(user.hasRegistryLockPassword()).isFalse();
user = user.asBuilder().setRegistryLockPassword("foobar").build();
assertThat(user.hasRegistryLockPassword()).isTrue();
assertThat(user.verifyRegistryLockPassword("foobar")).isTrue();
user = user.asBuilder().removeRegistryLockPassword().build();
assertThat(user.hasRegistryLockPassword()).isFalse();
assertThat(user.verifyRegistryLockPassword("foobar")).isFalse();
}
}
@@ -28,14 +28,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.eppcommon.Trid;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessageExternalKeyConverter.PollMessageExternalKeyParseException;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -47,14 +45,11 @@ public class PollMessageExternalKeyConverterTest {
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension public InjectExtension inject = new InjectExtension();
private HistoryEntry historyEntry;
private FakeClock clock = new FakeClock(DateTime.parse("2007-07-07T01:01:01Z"));
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
createTld("foobar");
historyEntry =
persistResource(
@@ -43,7 +43,6 @@ import google.registry.model.tld.Registry.TldState;
import google.registry.model.tld.label.PremiumList;
import google.registry.model.tld.label.PremiumListDao;
import google.registry.model.tld.label.ReservedList;
import google.registry.testing.DatabaseHelper;
import google.registry.util.SerializeUtils;
import java.math.BigDecimal;
import java.util.Optional;
@@ -61,8 +60,6 @@ public final class RegistryTest extends EntityTestCase {
@BeforeEach
void beforeEach() {
// Auto-increment fakeClock in DatabaseHelper.
inject.setStaticField(DatabaseHelper.class, "clock", fakeClock);
createTld("tld");
}
@@ -27,11 +27,9 @@ import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import google.registry.model.ImmutableObject;
import google.registry.model.ofy.Ofy;
import google.registry.persistence.VKey;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -54,8 +52,6 @@ public class TransactionManagerTest {
new TestEntity("entity2", "bar"),
new TestEntity("entity3", "qux"));
@RegisterExtension public InjectExtension inject = new InjectExtension();
@RegisterExtension
public final AppEngineExtension appEngine =
AppEngineExtension.builder()
@@ -69,7 +65,6 @@ public class TransactionManagerTest {
@BeforeEach
void setUp() {
inject.setStaticField(Ofy.class, "clock", fakeClock);
fakeClock.setAutoIncrementByOneMilli();
}
@@ -24,8 +24,6 @@ import static org.mockito.Mockito.mock;
import com.google.appengine.api.users.User;
import com.google.gson.JsonObject;
import google.registry.model.ofy.Ofy;
import google.registry.request.Action;
import google.registry.request.Actions;
import google.registry.request.auth.AuthLevel;
import google.registry.request.auth.AuthResult;
@@ -33,7 +31,6 @@ import google.registry.request.auth.UserAuthInfo;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import google.registry.util.Idn;
import google.registry.util.TypeUtils;
import java.util.HashMap;
@@ -48,8 +45,6 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
protected static final AuthResult AUTH_RESULT =
AuthResult.create(
AuthLevel.USER,
@@ -72,19 +67,18 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
RdapActionBaseTestCase(Class<A> rdapActionClass) {
this.rdapActionClass = rdapActionClass;
this.actionPath = Actions.getPathForAction(rdapActionClass);
actionPath = Actions.getPathForAction(rdapActionClass);
}
@BeforeEach
public void beforeEachRdapActionBaseTestCase() {
inject.setStaticField(Ofy.class, "clock", clock);
action = TypeUtils.instantiate(rdapActionClass);
action.includeDeletedParam = Optional.empty();
action.formatOutputParam = Optional.empty();
action.response = response;
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
action.rdapMetrics = rdapMetrics;
action.requestMethod = Action.Method.GET;
action.requestMethod = GET;
logout();
}
@@ -38,7 +38,6 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.reporting.HistoryEntry;
@@ -51,7 +50,6 @@ import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
import google.registry.rdap.RdapObjectClasses.TopLevelReplyObject;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -63,8 +61,6 @@ class RdapJsonFormatterTest {
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("1999-01-01T00:00:00Z"));
private RdapJsonFormatter rdapJsonFormatter;
@@ -85,8 +81,6 @@ class RdapJsonFormatterTest {
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
rdapJsonFormatter.rdapAuthorization =
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar");
@@ -299,7 +293,7 @@ class RdapJsonFormatterTest {
}
private JsonObject loadJson(String expectedFileName) {
return new Gson().fromJson(loadFile(this.getClass(), expectedFileName), JsonObject.class);
return new Gson().fromJson(loadFile(getClass(), expectedFileName), JsonObject.class);
}
@Test
@@ -512,7 +506,7 @@ class RdapJsonFormatterTest {
assertThat(
TopLevelReplyObject.create(
new ReplyPayloadBase(BoilerplateType.OTHER) {
@JsonableElement public String key = "value";
@JsonableElement public static final String key = "value";
},
rdapJsonFormatter.createTosNotice())
.toJson())
@@ -524,7 +518,7 @@ class RdapJsonFormatterTest {
assertThat(
TopLevelReplyObject.create(
new ReplyPayloadBase(BoilerplateType.DOMAIN) {
@JsonableElement public String key = "value";
@JsonableElement public static final String key = "value";
},
rdapJsonFormatter.createTosNotice())
.toJson())
@@ -31,11 +31,9 @@ import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.truth.Truth8;
import google.registry.model.common.Cursor;
import google.registry.model.common.Cursor.CursorType;
import google.registry.model.ofy.Ofy;
import google.registry.model.tld.Registry;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -44,8 +42,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link PendingDepositChecker}. */
public class PendingDepositCheckerTest {
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@@ -54,7 +50,6 @@ public class PendingDepositCheckerTest {
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
checker.brdaDayOfWeek = TUESDAY;
checker.brdaInterval = standardDays(7);
checker.clock = clock;
@@ -37,7 +37,6 @@ import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.InjectExtension;
import google.registry.util.JdkLoggerConfig;
import java.util.Optional;
import java.util.logging.Level;
@@ -61,8 +60,6 @@ class AuthenticatedRegistrarAccessorTest {
@RegisterExtension
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension final InjectExtension inject = new InjectExtension();
@Mock private HttpServletRequest req;
@Mock private HttpServletResponse rsp;
@Mock private GroupsConnection groupsConnection;
@@ -142,7 +139,7 @@ class AuthenticatedRegistrarAccessorTest {
verify(lazyGroupsConnection).get();
}
/** Logged out users don't have access to anything. */
/** Logged-out users don't have access to anything. */
@Test
void getAllClientIdWithAccess_loggedOutUser() {
AuthenticatedRegistrarAccessor registrarAccessor =
@@ -22,7 +22,6 @@ import com.google.common.base.Splitter;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeUserService;
import google.registry.testing.InjectExtension;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -34,8 +33,6 @@ class XsrfTokenManagerTest {
@RegisterExtension
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension InjectExtension inject = new InjectExtension();
private final User testUser = new User("test@example.com", "test@example.com");
private final FakeClock clock = new FakeClock(START_OF_TIME);
private final FakeUserService userService = new FakeUserService();
@@ -81,7 +78,7 @@ class XsrfTokenManagerTest {
void testValidate_tokenTimestampTamperedWith() {
String encodedPart = Splitter.on(':').splitToList(token).get(2);
long fakeTimestamp = clock.nowUtc().plusMillis(1).getMillis();
assertThat(xsrfTokenManager.validateToken("1:" + fakeTimestamp + ":" + encodedPart)).isFalse();
assertThat(xsrfTokenManager.validateToken("1:" + fakeTimestamp + ':' + encodedPart)).isFalse();
}
@Test
@@ -32,12 +32,8 @@ import google.registry.model.contact.ContactAddress;
import google.registry.model.contact.ContactResource;
import google.registry.model.contact.PostalInfo;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.ofy.Ofy;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import java.io.IOException;
import org.joda.time.DateTime;
/**
* Datastore fixtures for the development webserver.
@@ -47,14 +43,6 @@ import org.joda.time.DateTime;
*/
public enum Fixture {
INJECTED_FAKE_CLOCK {
@Override
public void load() {
new InjectExtension()
.setStaticField(Ofy.class, "clock", new FakeClock(DateTime.parse("2000-01-01TZ")));
}
},
/** Fixture of two TLDs, three contacts, two domains, and six hosts. */
BASIC {
@Override
@@ -1,211 +0,0 @@
// 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.testing;
import static com.google.common.base.Preconditions.checkState;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
/**
* JUnit extension for overriding {@code private static} fields during a test.
*
* <p>This extension uses reflection to change the value of a field while your test is running and
* then restore it to its original value after it's done (even if the test fails). The injection
* will work even if the field is marked {@code private} (but not if it's {@code final}). The
* downside is that if you rename the field in the future, IDE refactoring won't be smart enough to
* update the injection site.
*
* <p>We encourage you to consider using {@link google.registry.util.NonFinalForTesting
* &#064;NonFinalForTesting} to document your injected fields.
*
* <p>This class is a horrible evil hack, but it alleviates you of the toil of having to break
* encapsulation by making your fields non-{@code private}, using the {@link
* com.google.common.annotations.VisibleForTesting &#064;VisibleForTesting} annotation to document
* why you've reduced visibility, creating a temporary field to store the old value, and then
* writing an {@link org.junit.After &#064;After} method to restore it. So sometimes it feels good
* to be evil; but hopefully one day we'll be able to delete this class and do things
* <i>properly</i> with <a href="http://square.github.io/dagger/">Dagger</a> dependency injection.
*
* <p>You use this class in by declaring it as an {@link
* org.junit.jupiter.api.extension.RegisterExtension &#064;RegisterExtension} field and then call
* {@link #setStaticField} from either your {@link org.junit.jupiter.api.Test &#064;Test} or {@link
* org.junit.jupiter.api.BeforeEach &#064;BeforeEach} methods. For example:
*
* <pre>
* // Doomsday.java
* public class Doomsday {
*
* private static Clock clock = new SystemClock();
*
* public long getTime() {
* return clock.currentTimeMillis();
* }
* }
*
* // DoomsdayTest.java
* public class DoomsdayTest {
*
* &#064;RegisterExtension
* public InjectExtension inject = new InjectExtension();
*
* private final FakeClock clock = new FakeClock();
*
* &#064;BeforeEach
* public void beforeEach() {
* inject.setStaticField(Doomsday.class, "clock", clock);
* }
*
* &#064;Test
* public void test() {
* clock.advanceBy(666L);
* Doomsday doom = new Doomsday();
* assertEquals(666L, doom.getTime());
* }
* }
* </pre>
*
* @see google.registry.util.NonFinalForTesting
*/
public class InjectExtension implements AfterEachCallback, BeforeEachCallback {
private static class Change {
private final Field field;
@Nullable private Object oldValue;
@Nullable private final Object newValue;
private boolean active;
Change(Field field, @Nullable Object oldValue, @Nullable Object newValue, boolean active) {
this.field = field;
this.oldValue = oldValue;
this.newValue = newValue;
this.active = active;
}
}
private final List<Change> changes = new ArrayList<>();
private final Set<Field> injected = new HashSet<>();
/** Adds the specified field override to those set by the extension. */
public InjectExtension withStaticFieldOverride(
Class<?> clazz, String fieldName, @Nullable Object newValue) {
changes.add(new Change(getField(clazz, fieldName), null, newValue, false));
return this;
}
/**
* Sets a static field and be restores its current value after the test completes.
*
* <p>Prefer to use withStaticFieldOverride(), which is more consistent with the extension
* pattern.
*
* <p>The field is allowed to be {@code private}, but it most not be {@code final}.
*
* <p>This method may be called either from either your {@link
* org.junit.jupiter.api.BeforeEach @BeforeEach} method or from the {@link
* org.junit.jupiter.api.Test @Test} method itself. However you may not inject the same field
* multiple times during the same test.
*
* @throws IllegalArgumentException if the static field could not be found or modified.
* @throws IllegalStateException if the field has already been injected during this test.
*/
public void setStaticField(Class<?> clazz, String fieldName, @Nullable Object newValue) {
Field field = getField(clazz, fieldName);
Change change = new Change(field, null, newValue, true);
activateChange(change);
changes.add(change);
injected.add(field);
}
@Override
public void beforeEach(ExtensionContext context) {
for (Change change : changes) {
if (!change.active) {
activateChange(change);
}
}
}
@Override
public void afterEach(ExtensionContext context) {
RuntimeException thrown = null;
for (Change change : changes) {
if (change.active) {
try {
checkState(
change.field.get(null).equals(change.newValue),
"Static field value was changed post-injection: %s.%s",
change.field.getDeclaringClass().getSimpleName(),
change.field.getName());
change.field.set(null, change.oldValue);
} catch (IllegalArgumentException | IllegalStateException | IllegalAccessException e) {
if (thrown == null) {
thrown = new RuntimeException(e);
} else {
thrown.addSuppressed(e);
}
}
}
}
changes.clear();
injected.clear();
if (thrown != null) {
throw thrown;
}
}
private Field getField(Class<?> clazz, String fieldName) {
try {
return clazz.getDeclaredField(fieldName);
} catch (SecurityException | NoSuchFieldException e) {
throw new IllegalArgumentException(
String.format("Static field not found: %s.%s", clazz.getSimpleName(), fieldName), e);
}
}
private void activateChange(Change change) {
Class<?> clazz = change.field.getDeclaringClass();
try {
change.field.setAccessible(true);
change.oldValue = change.field.get(null);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalArgumentException(
String.format(
"Static field not gettable: %s.%s", clazz.getSimpleName(), change.field.getName()),
e);
}
checkState(
!injected.contains(change.field),
"Static field already injected: %s.%s",
clazz.getSimpleName(),
change.field.getName());
try {
change.field.set(null, change.newValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalArgumentException(
String.format(
"Static field not settable: %s.%s", clazz.getSimpleName(), change.field.getName()),
e);
}
change.active = true;
}
}
@@ -24,11 +24,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.model.domain.Domain;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar.Type;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.util.Clock;
import org.joda.time.DateTime;
@@ -45,15 +43,12 @@ public class LordnTaskUtilsTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@BeforeEach
void beforeEach() {
createTld("example");
inject.setStaticField(Ofy.class, "clock", clock);
}
private Domain.Builder newDomainBuilder() {
private static Domain.Builder newDomainBuilder() {
return new Domain.Builder()
.setDomainName("fleece.example")
.setPersistedCurrentSponsorRegistrarId("TheRegistrar")
@@ -48,14 +48,12 @@ import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import google.registry.model.domain.Domain;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.ofy.Ofy;
import google.registry.model.tld.Registry;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeSleeper;
import google.registry.testing.FakeUrlConnectionService;
import google.registry.testing.InjectExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.util.Retrier;
import google.registry.util.TaskQueueUtils;
@@ -95,8 +93,6 @@ class NordnUploadActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final LordnRequestInitializer lordnRequestInitializer =
new LordnRequestInitializer(Optional.of("attack"));
private final NordnUploadAction action = new NordnUploadAction();
@@ -108,7 +104,6 @@ class NordnUploadActionTest {
@BeforeEach
void beforeEach() throws Exception {
inject.setStaticField(Ofy.class, "clock", clock);
when(httpUrlConnection.getInputStream())
.thenReturn(new ByteArrayInputStream("Success".getBytes(UTF_8)));
when(httpUrlConnection.getResponseCode()).thenReturn(SC_ACCEPTED);
@@ -164,7 +159,6 @@ class NordnUploadActionTest {
() -> NordnUploadAction.convertTasksToCsv(null, clock.nowUtc(), "header"));
}
@SuppressWarnings("unchecked")
@Test
void test_loadAllTasks_retryLogic_thirdTrysTheCharm() {
Queue queue = mock(Queue.class);
@@ -230,7 +224,7 @@ class NordnUploadActionTest {
void testRun_claimsMode_payloadMatchesClaimsCsv() {
persistClaimsModeDomain();
action.run();
assertThat(new String(connectionOutputStream.toByteArray(), UTF_8)).contains(CLAIMS_CSV);
assertThat(connectionOutputStream.toString(UTF_8)).contains(CLAIMS_CSV);
}
@Test
@@ -249,7 +243,7 @@ class NordnUploadActionTest {
void testRun_sunriseMode_payloadMatchesSunriseCsv() {
persistSunriseModeDomain();
action.run();
assertThat(new String(connectionOutputStream.toByteArray(), UTF_8)).contains(SUNRISE_CSV);
assertThat(connectionOutputStream.toString(UTF_8)).contains(SUNRISE_CSV);
}
@Test
@@ -258,7 +252,7 @@ class NordnUploadActionTest {
when(httpUrlConnection.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[] {}));
persistSunriseModeDomain();
action.run();
assertThat(new String(connectionOutputStream.toByteArray(), UTF_8)).contains(SUNRISE_CSV);
assertThat(connectionOutputStream.toString(UTF_8)).contains(SUNRISE_CSV);
}
@Test
@@ -288,7 +282,7 @@ class NordnUploadActionTest {
assertThrows(UrlConnectionException.class, action::run);
}
private void persistClaimsModeDomain() {
private static void persistClaimsModeDomain() {
Domain domain = DatabaseHelper.newDomain("claims-landrush1.tld");
persistDomainAndEnqueueLordn(
domain
@@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import google.registry.tmch.TmchXmlSignature.CertificateSignatureException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
@@ -42,8 +41,6 @@ class TmchXmlSignatureTest {
@RegisterExtension
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
// This should be a date which falls within the validity range of the test files contained in the
// testdata/active directory. Note that test files claiming to be valid for a particular date
// range in the file header may not actually be valid the whole time, because they contain an
@@ -25,7 +25,6 @@ import com.google.common.collect.ImmutableList;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessage.Autorenew;
import google.registry.model.poll.PollMessage.OneTime;
@@ -33,24 +32,19 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link AckPollMessagesCommand}. */
public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesCommand> {
private FakeClock clock = new FakeClock(DateTime.parse("2015-02-04T08:16:32.064Z"));
@RegisterExtension public final InjectExtension inject = new InjectExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("2015-02-04T08:16:32.064Z"));
private DomainHistory domainHistory;
@BeforeEach
final void beforeEach() {
inject.setStaticField(Ofy.class, "clock", clock);
command.clock = clock;
createTld("tld");
Domain domain =
@@ -18,20 +18,14 @@ import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
import google.registry.model.ofy.Ofy;
import google.registry.testing.InjectExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link CountDomainsCommand}. */
public class CountDomainsCommandTest extends CommandTestCase<CountDomainsCommand> {
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@BeforeEach
final void beforeEach() {
inject.setStaticField(Ofy.class, "clock", fakeClock);
command.clock = fakeClock;
createTlds("foo", "bar", "baz", "qux");
}
@@ -40,9 +40,7 @@ import com.google.common.collect.Range;
import com.google.common.net.MediaType;
import google.registry.flows.certs.CertificateChecker;
import google.registry.flows.certs.CertificateChecker.InsecureCertificateException;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.testing.InjectExtension;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Optional;
@@ -51,7 +49,6 @@ import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
@@ -60,11 +57,9 @@ class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand>
@Mock private AppEngineConnection connection;
@RegisterExtension final InjectExtension inject = new InjectExtension();
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", fakeClock);
command.setConnection(connection);
command.certificateChecker =
new CertificateChecker(
@@ -26,25 +26,19 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.model.domain.Domain;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.testing.InjectExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link EnqueuePollMessageCommand}. */
class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCommand> {
@RegisterExtension final InjectExtension inject = new InjectExtension();
private Domain domain;
@BeforeEach
void beforeEach() {
createTld("tld");
inject.setStaticField(Ofy.class, "clock", fakeClock);
domain = persistActiveDomain("example.tld");
persistNewRegistrar("AdminRegistrar");
command.registryAdminClientId = "AdminRegistrar";
@@ -21,10 +21,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.InjectExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@@ -33,8 +31,6 @@ import org.mockito.quality.Strictness;
public class GenerateEscrowDepositCommandTest
extends CommandTestCase<GenerateEscrowDepositCommand> {
@RegisterExtension public final InjectExtension inject = new InjectExtension();
CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
@BeforeEach
@@ -22,7 +22,6 @@ import google.registry.keyring.api.Keyring;
import google.registry.rde.Ghostryde;
import google.registry.testing.BouncyCastleProviderExtension;
import google.registry.testing.FakeKeyringModule;
import google.registry.testing.InjectExtension;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.BeforeEach;
@@ -51,8 +50,6 @@ class GhostrydeCommandTest extends CommandTestCase<GhostrydeCommand> {
+ "Haply I may remember, \n"
+ " And haply may forget. \n").getBytes(UTF_8);
@RegisterExtension final InjectExtension inject = new InjectExtension();
@RegisterExtension
final BouncyCastleProviderExtension bouncy = new BouncyCastleProviderExtension();
@@ -78,7 +75,7 @@ class GhostrydeCommandTest extends CommandTestCase<GhostrydeCommand> {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> runCommand("--input=" + inputFile.toString(), "--output=bar.dat"));
() -> runCommand("--input=" + inputFile, "--output=bar.dat"));
assertThat(thrown).hasMessageThat().isEqualTo("Please specify either --encrypt or --decrypt");
}
@@ -87,8 +84,7 @@ class GhostrydeCommandTest extends CommandTestCase<GhostrydeCommand> {
Path inputFile = Files.createFile(tmpDir.resolve("foo.dat"));
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> runCommand("--encrypt", "--input=" + inputFile.toString()));
IllegalArgumentException.class, () -> runCommand("--encrypt", "--input=" + inputFile));
assertThat(thrown).hasMessageThat().isEqualTo("--output path is required in --encrypt mode");
}
@@ -22,13 +22,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.model.common.Cursor;
import google.registry.model.common.Cursor.CursorType;
import google.registry.model.ofy.Ofy;
import google.registry.model.tld.Registry;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link ListCursorsCommand}. */
public class ListCursorsCommandTest extends CommandTestCase<ListCursorsCommand> {
@@ -39,12 +36,9 @@ public class ListCursorsCommandTest extends CommandTestCase<ListCursorsCommand>
private static final String HEADER_TWO =
"--------------------------------------------------------------------------";
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@BeforeEach
void beforeEach() {
fakeClock.setTo(DateTime.parse("1984-12-21T06:07:08.789Z"));
inject.setStaticField(Ofy.class, "clock", fakeClock);
}
@Test
@@ -22,11 +22,9 @@ import static org.mockito.Mockito.verify;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableMultimap;
import google.registry.testing.AppEngineAdminApiHelper;
import google.registry.testing.InjectExtension;
import google.registry.util.AppEngineServiceUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@@ -34,11 +32,9 @@ import org.mockito.quality.Strictness;
/** Unit tests for {@link SetNumInstancesCommand}. */
public class SetNumInstancesCommandTest extends CommandTestCase<SetNumInstancesCommand> {
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@Mock AppEngineServiceUtils appEngineServiceUtils;
private final String projectId = "domain-registry-test";
private static final String projectId = "domain-registry-test";
@BeforeEach
void beforeEach() {
@@ -41,25 +41,19 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.InjectExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link UnrenewDomainCommand}. */
public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainCommand> {
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@BeforeEach
void beforeEach() {
createTld("tld");
fakeClock.setTo(DateTime.parse("2016-12-06T13:55:01Z"));
inject.setStaticField(Ofy.class, "clock", fakeClock);
command.clock = fakeClock;
}
@@ -42,17 +42,14 @@ import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.model.ofy.Ofy;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.InjectExtension;
import google.registry.util.CapturingLogHandler;
import google.registry.util.JdkLoggerConfig;
import java.util.logging.Level;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link UpdateDomainCommand}. */
class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand> {
@@ -61,11 +58,8 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
private Domain domain;
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@BeforeEach
void beforeEach() {
inject.setStaticField(Ofy.class, "clock", fakeClock);
command.clock = fakeClock;
domain = persistActiveDomain("example.tld");
JdkLoggerConfig.getConfig(UpdateDomainCommand.class).addHandler(logHandler);
@@ -28,7 +28,6 @@ import google.registry.request.HttpException.BadRequestException;
import google.registry.request.HttpException.InternalServerErrorException;
import google.registry.request.Response;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.InjectExtension;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -39,8 +38,6 @@ class CreateGroupsActionTest {
@RegisterExtension
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension final InjectExtension inject = new InjectExtension();
private final DirectoryGroupsConnection connection = mock(DirectoryGroupsConnection.class);
private final Response response = mock(Response.class);
@@ -31,17 +31,14 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.common.collect.ImmutableSet;
import google.registry.dns.DnsQueue;
import google.registry.model.ofy.Ofy;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import java.util.Random;
import org.apache.http.HttpStatus;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.ArgumentCaptor;
@@ -53,24 +50,18 @@ public class RefreshDnsForAllDomainsActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T02:02:02Z"));
private final DnsQueue dnsQueue = mock(DnsQueue.class);
private RefreshDnsForAllDomainsAction action;
private FakeResponse response = new FakeResponse();
private final FakeResponse response = new FakeResponse();
@RegisterExtension
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withLocalModules().withTaskQueue().build();
@Order(Order.DEFAULT - 1)
@RegisterExtension
public final InjectExtension inject =
new InjectExtension().withStaticFieldOverride(Ofy.class, "clock", clock);
@BeforeEach
void beforeEach() {
action = new RefreshDnsForAllDomainsAction();
action.smearMinutes = 1;
action.random = new Random();
action.random.setSeed(123L);
action.response = new FakeResponse();
action.clock = clock;
action.dnsQueue = dnsQueue;
action.response = response;
@@ -36,7 +36,6 @@ import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.truth.Truth;
import google.registry.flows.certs.CertificateChecker;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.request.JsonActionRunner;
import google.registry.request.JsonResponse;
@@ -48,7 +47,6 @@ import google.registry.request.auth.UserAuthInfo;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import google.registry.ui.server.SendEmailUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
@@ -81,8 +79,6 @@ public abstract class RegistrarSettingsActionTestCase {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@Mock HttpServletRequest req;
@Mock HttpServletResponse rsp;
@Mock SendEmailService emailService;
@@ -129,7 +125,6 @@ public abstract class RegistrarSettingsActionTestCase {
clock);
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
inject.setStaticField(Ofy.class, "clock", clock);
when(req.getMethod()).thenReturn("POST");
when(rsp.getWriter()).thenReturn(new PrintWriter(writer));
when(req.getContentType()).thenReturn("application/json");
@@ -47,7 +47,6 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.Host;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.model.tld.Registry;
import google.registry.model.transfer.DomainTransferData;
@@ -57,7 +56,6 @@ import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.FakeSleeper;
import google.registry.testing.FullFieldsTestEntityHelper;
import google.registry.testing.InjectExtension;
import google.registry.testing.TestCacheExtension;
import google.registry.util.Retrier;
import google.registry.whois.WhoisMetrics.WhoisMetric;
@@ -80,8 +78,6 @@ public class WhoisActionTest {
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withCloudSql().withClock(clock).build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@RegisterExtension
public final TestCacheExtension testCacheExtension =
new TestCacheExtension.Builder()
@@ -109,7 +105,6 @@ public class WhoisActionTest {
@BeforeEach
void setUp() {
createTlds("lol", "xn--q9jyb4c", "1.test");
inject.setStaticField(Ofy.class, "clock", clock);
}
@Test
@@ -119,7 +114,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_no_command.txt"));
}
private Domain makeDomainWithRegistrar(Registrar registrar) {
private static Domain makeDomainWithRegistrar(Registrar registrar) {
return makeDomain(
"cat.lol",
persistResource(makeContactResource("5372808-ERL", "Goblin Market", "lol@cat.lol")),
@@ -287,8 +282,7 @@ public class WhoisActionTest {
persistResource(FullFieldsTestEntityHelper.makeHost("ns1.cat.lol", "1.2.3.4")),
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.cat.lol", "bad:f00d:cafe::15:beef")),
persistResource(
(registrar = makeRegistrar("example", "Example Registrar", ACTIVE))))
persistResource(registrar = makeRegistrar("example", "Example Registrar", ACTIVE)))
.asBuilder()
.setDeletionTime(clock.nowUtc().minusDays(1))
.build());
@@ -339,7 +333,7 @@ public class WhoisActionTest {
persistResource(
FullFieldsTestEntityHelper.makeHost("ns2.google.lol", "4311::f143")),
persistResource(
(registrar = makeRegistrar("example", "Example Registrar", ACTIVE))))
registrar = makeRegistrar("example", "Example Registrar", ACTIVE)))
.asBuilder()
.setCreationTimeForTest(clock.nowUtc())
.build());
@@ -36,14 +36,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import google.registry.model.contact.ContactResource;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.model.tld.Registry;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.FullFieldsTestEntityHelper;
import google.registry.testing.InjectExtension;
import google.registry.whois.WhoisMetrics.WhoisMetric;
import java.io.IOException;
import java.io.Reader;
@@ -65,8 +63,6 @@ class WhoisHttpActionTest {
@RegisterExtension
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
@RegisterExtension final InjectExtension inject = new InjectExtension();
private final FakeResponse response = new FakeResponse();
private final FakeClock clock = new FakeClock(DateTime.parse("2009-06-29T20:13:00Z"));
@@ -88,7 +84,6 @@ class WhoisHttpActionTest {
@BeforeEach
void beforeEach() {
createTlds("lol", "xn--q9jyb4c", "1.test");
inject.setStaticField(Ofy.class, "clock", clock);
}
@Test
+1
View File
@@ -374,6 +374,7 @@ An EPP flow that creates a new domain resource.
* The allocation token was already redeemed.
* 2306
* Anchor tenant domain create is for the wrong number of years.
* Trademarked domains cannot be registered before the sunrise period.
* The provided mark is not yet valid.
* The provided mark has expired.
* Domain names can only contain a-z, 0-9, '.' and '-'.