1
0
mirror of https://github.com/google/nomulus synced 2026-07-06 16:16:38 +00:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Ben McIlwain 6b5ec36eed Better configure DocumentBuilderFactory to help prevent XXE (#2132)
For more information see: https://community.veracode.com/s/article/Java-Remediation-Guidance-for-XXE
2023-08-30 10:17:37 -04:00
sarahcaseybot ebf07833e5 Only allow CREATE EPP commands on BULK_PRICING tokens (#2131)
* Only allow CREATE EPP commands on BULK_PRICING tokens

* small fixes
2023-08-29 16:00:29 -04:00
Weimin Yu ee3ece8c56 Use gmail to send invoices (#2130) 2023-08-29 14:25:54 -04:00
Ben McIlwain 57592d787c Add a new MutatingFlow interface and make most flows use TransactionalFlow (#2129)
The old semantics for TransactionalFlow meant "anything that needs to mutate the
database", but then FlowRunner was not creating transactions for
non-transactional flows even though nearly every flow needs a transaction (as
nearly every flow needs to hit the database for some purpose).  So now
TransactionalFlow simply means "any flow that needs the database", and
MutatingFlow means "a flow that mutates the database". In the future we will
have FlowRunner use a read-only transaction for TransactionalFlow and then a
normal writes-allowed transaction for MutatingFlow. That is a TODO.

This also fixes up some transact() calls inside caches to be reTransact(), as we
rightly can't move the transaction outside them as from some callsites we
legitimately do not know whether a transaction will be needed at all (depending
on whether said data is already in memory). And it removes the replicaTm() calls
which weren't actually doing anything as they were always nested inside of normal
tm()s, thus causing confusion.
2023-08-28 17:04:41 -04:00
Weimin Yu e6f9b1c7e6 Using Gmail for most use cases (#2126)
* Using Gmail for most use cases
2023-08-28 11:11:59 -04:00
gbrodman 7b59c4abbf Alphabetize YAML output by property name (#2128)
This makes printing the TLDs prettier and makes it easier to find
fields.
2023-08-25 16:30:37 -04:00
Ben McIlwain f01adfb060 Add tm().reTransact() methods and refactor away some inner transactions (#2125)
In the future, reTransact() will be the only way to initiate a transaction that
doesn't fail when called inside an outer wrapping transaction (when wrapped,
it's a no-op). It should be used sparingly, with a preference towards
refactoring the code to move transactions outwards (which this PR also
contains).

Note that this PR includes some potential efficiency gains caused by existing
poor use of transactions. E.g. in the file RefreshDnsAction, the existing code
was using two separate transactions to refresh the DNS for domains and hosts
(one is hidden in loadAndVerifyExistence(), whereas now as of this PR it has a
single wrapping transaction to do so.
2023-08-25 14:03:25 -04:00
Ben McIlwain 739a15851d Remove a couple unnecessary inner transact() calls (#2124)
Also refactors a function to no longer unnecessarily return a low level Iterable
type.
2023-08-24 18:10:44 -04:00
sarahcaseybot 2c961b6283 Inject getTldCommand in RegistryToolComponent (#2123) 2023-08-24 16:56:40 -04:00
Weimin Yu bcb2b2c784 Use Gmail for RegistryLock emails (#2122) 2023-08-24 15:18:47 -04:00
Lai Jiang a91ed0f1ad Allow nested transactions when per-transaction isolation level is on (#2121)
It turns out that disallowing all nested transaction is impractical. So
in this PR we make it possible to run nested transactions (which are not
really nested as far as SQL is concerned, but rather lexically nested
calls to tm().transact() which will NOT open new transactions when
called within a transaction) as long as there is no conflict between the
specified isolation levels between the enclosing and the enclosed
transactions.

Note that this will change the behavior of calling tm().transact() with
no isolation level override, or a null override INSIDE a transaction.
The lack of the override will allow the nested transaction to run at
whatever level the enclosing transaction runs at, instead of at the
default level specified in the config file.
2023-08-24 14:35:59 -04:00
123 changed files with 837 additions and 481 deletions
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.groups.GmailClient;
import google.registry.model.domain.Domain;
import google.registry.model.domain.RegistryLock;
import google.registry.model.eppcommon.StatusValue;
@@ -40,7 +41,6 @@ import google.registry.request.auth.Auth;
import google.registry.tools.DomainLockUtils;
import google.registry.util.DateTimeUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.Optional;
import javax.inject.Inject;
import javax.mail.internet.AddressException;
@@ -84,7 +84,7 @@ public class RelockDomainAction implements Runnable {
private final InternetAddress alertRecipientAddress;
private final InternetAddress gSuiteOutgoingEmailAddress;
private final String supportEmail;
private final SendEmailService sendEmailService;
private final GmailClient gmailClient;
private final DomainLockUtils domainLockUtils;
private final Response response;
@@ -92,10 +92,10 @@ public class RelockDomainAction implements Runnable {
public RelockDomainAction(
@Parameter(OLD_UNLOCK_REVISION_ID_PARAM) long oldUnlockRevisionId,
@Parameter(PREVIOUS_ATTEMPTS_PARAM) int previousAttempts,
@Config("alertRecipientEmailAddress") InternetAddress alertRecipientAddress,
@Config("newAlertRecipientEmailAddress") InternetAddress alertRecipientAddress,
@Config("gSuiteOutgoingEmailAddress") InternetAddress gSuiteOutgoingEmailAddress,
@Config("supportEmail") String supportEmail,
SendEmailService sendEmailService,
GmailClient gmailClient,
DomainLockUtils domainLockUtils,
Response response) {
this.oldUnlockRevisionId = oldUnlockRevisionId;
@@ -103,7 +103,7 @@ public class RelockDomainAction implements Runnable {
this.alertRecipientAddress = alertRecipientAddress;
this.gSuiteOutgoingEmailAddress = gSuiteOutgoingEmailAddress;
this.supportEmail = supportEmail;
this.sendEmailService = sendEmailService;
this.gmailClient = gmailClient;
this.domainLockUtils = domainLockUtils;
this.response = response;
}
@@ -215,7 +215,7 @@ public class RelockDomainAction implements Runnable {
oldLock.getDomainName(),
t.getMessage(),
supportEmail);
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setFrom(gSuiteOutgoingEmailAddress)
.setBody(body)
@@ -245,7 +245,7 @@ public class RelockDomainAction implements Runnable {
String body =
String.format(RELOCK_SUCCESS_EMAIL_TEMPLATE, oldLock.getDomainName(), supportEmail);
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setFrom(gSuiteOutgoingEmailAddress)
.setBody(body)
@@ -264,7 +264,7 @@ public class RelockDomainAction implements Runnable {
.addAll(getEmailRecipients(oldLock.getRegistrarId()))
.add(alertRecipientAddress)
.build();
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setFrom(gSuiteOutgoingEmailAddress)
.setBody(body)
@@ -274,7 +274,7 @@ public class RelockDomainAction implements Runnable {
}
private void sendUnknownRevisionIdAlertEmail() {
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setFrom(gSuiteOutgoingEmailAddress)
.setBody(String.format(RELOCK_UNKNOWN_ID_FAILURE_EMAIL_TEMPLATE, oldUnlockRevisionId))
@@ -31,6 +31,7 @@ import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.flows.certs.CertificateChecker;
import google.registry.groups.GmailClient;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPoc.Type;
@@ -38,7 +39,6 @@ import google.registry.request.Action;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.Date;
import java.util.Optional;
import javax.inject.Inject;
@@ -72,7 +72,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
private final CertificateChecker certificateChecker;
private final String expirationWarningEmailBodyText;
private final SendEmailService sendEmailService;
private final GmailClient gmailClient;
private final String expirationWarningEmailSubjectText;
private final InternetAddress gSuiteOutgoingEmailAddress;
private final Response response;
@@ -82,12 +82,12 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
@Config("expirationWarningEmailBodyText") String expirationWarningEmailBodyText,
@Config("expirationWarningEmailSubjectText") String expirationWarningEmailSubjectText,
@Config("gSuiteOutgoingEmailAddress") InternetAddress gSuiteOutgoingEmailAddress,
SendEmailService sendEmailService,
GmailClient gmailClient,
CertificateChecker certificateChecker,
Response response) {
this.certificateChecker = certificateChecker;
this.expirationWarningEmailSubjectText = expirationWarningEmailSubjectText;
this.sendEmailService = sendEmailService;
this.gmailClient = gmailClient;
this.gSuiteOutgoingEmailAddress = gSuiteOutgoingEmailAddress;
this.expirationWarningEmailBodyText = expirationWarningEmailBodyText;
this.response = response;
@@ -173,7 +173,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
registrar.getRegistrarName());
return false;
}
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setFrom(gSuiteOutgoingEmailAddress)
.setSubject(expirationWarningEmailSubjectText)
@@ -274,10 +274,7 @@ public class RdeIO {
PendingDeposit key = input.getKey();
Tld tld = Tld.get(key.tld());
Optional<Cursor> cursor =
tm().transact(
() ->
tm().loadByKeyIfPresent(
Cursor.createScopedVKey(key.cursor(), tld)));
tm().loadByKeyIfPresent(Cursor.createScopedVKey(key.cursor(), tld));
DateTime position = getCursorTimeOrStartOfTime(cursor);
checkState(key.interval() != null, "Interval must be present");
DateTime newPosition = key.watermark().plus(key.interval());
@@ -723,6 +723,18 @@ public final class RegistryConfig {
.collect(toImmutableList());
}
/**
* Returns an optional return email address that overrides the default {@code reply-to} address
* in outgoing invoicing email messages.
*/
@Provides
@Config("invoiceReplyToEmailAddress")
public static Optional<InternetAddress> provideInvoiceReplyToEmailAddress(
RegistryConfigSettings config) {
return Optional.ofNullable(config.billing.invoiceReplyToEmailAddress)
.map(RegistryConfig::parseEmailAddress);
}
/**
* Returns the file prefix for the invoice CSV file.
*
@@ -170,6 +170,7 @@ public class RegistryConfigSettings {
/** Configuration for monthly invoices. */
public static class Billing {
public List<String> invoiceEmailRecipients;
public String invoiceReplyToEmailAddress;
public String invoiceFilePrefix;
}
@@ -382,6 +382,8 @@ icannReporting:
billing:
invoiceEmailRecipients: []
# Optional return address that overrides the default.
invoiceReplyToEmailAddress: null
invoiceFilePrefix: REG-INV
rde:
@@ -28,4 +28,4 @@ misc:
transientFailureRetries: 3
hibernate:
perTransactionIsolation: false
perTransactionIsolation: true
@@ -45,6 +45,7 @@ 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.groups.GmailClient;
import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
@@ -61,7 +62,6 @@ import google.registry.request.lock.LockHandler;
import google.registry.util.Clock;
import google.registry.util.DomainNameUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
@@ -112,7 +112,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
private final Clock clock;
private final CloudTasksUtils cloudTasksUtils;
private final Response response;
private final SendEmailService sendEmailService;
private final GmailClient gmailClient;
private final String dnsUpdateFailEmailSubjectText;
private final String dnsUpdateFailEmailBodyText;
private final String dnsUpdateFailRegistryName;
@@ -143,12 +143,12 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
LockHandler lockHandler,
Clock clock,
CloudTasksUtils cloudTasksUtils,
SendEmailService sendEmailService,
GmailClient gmailClient,
Response response) {
this.dnsWriterProxy = dnsWriterProxy;
this.dnsMetrics = dnsMetrics;
this.timeout = timeout;
this.sendEmailService = sendEmailService;
this.gmailClient = gmailClient;
this.retryCount = retryCount;
this.dnsWriter = dnsWriter;
this.enqueuedTime = enqueuedTime;
@@ -303,7 +303,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
.map(PublishDnsUpdatesAction::emailToInternetAddress)
.collect(toImmutableList());
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setBody(body)
.setSubject(dnsUpdateFailEmailSubjectText)
@@ -60,18 +60,21 @@ public final class RefreshDnsAction implements Runnable {
if (!domainOrHostName.contains(".")) {
throw new BadRequestException("URL parameter 'name' must be fully qualified");
}
switch (type) {
case DOMAIN:
loadAndVerifyExistence(Domain.class, domainOrHostName);
tm().transact(() -> requestDomainDnsRefresh(domainOrHostName));
break;
case HOST:
verifyHostIsSubordinate(loadAndVerifyExistence(Host.class, domainOrHostName));
tm().transact(() -> requestHostDnsRefresh(domainOrHostName));
break;
default:
throw new BadRequestException("Unsupported type: " + type);
}
tm().transact(
() -> {
switch (type) {
case DOMAIN:
loadAndVerifyExistence(Domain.class, domainOrHostName);
requestDomainDnsRefresh(domainOrHostName);
break;
case HOST:
verifyHostIsSubordinate(loadAndVerifyExistence(Host.class, domainOrHostName));
requestHostDnsRefresh(domainOrHostName);
break;
default:
throw new BadRequestException("Unsupported type: " + type);
}
});
}
private <T extends EppResource & ForeignKeyedEppResource>
@@ -165,6 +165,9 @@ public class EppXmlSanitizer {
xmlInputFactory.setProperty(XMLInputFactory.IS_COALESCING, true);
// Preserve Name Space information.
xmlInputFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
// Prevent XXE attacks.
xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
return xmlInputFactory;
}
}
@@ -78,6 +78,8 @@ public class FlowRunner {
return EppOutput.create(flowProvider.get().run());
}
try {
// TODO(mcilwain/weiminyu): Use transactReadOnly() here for TransactionalFlow and transact()
// for MutatingFlow.
return tm().transact(
() -> {
try {
@@ -0,0 +1,23 @@
// Copyright 2023 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.flows;
/**
* Interface for a {@link TransactionalFlow} that mutates the database (i.e. is not read-only).
*
* <p>Any flow that mutates the DB should implement this so that {@link FlowRunner} will know how to
* run it.
*/
public interface MutatingFlow extends TransactionalFlow {}
@@ -72,17 +72,12 @@ public final class ResourceFlowUtils {
*/
public static <R extends EppResource> void checkLinkedDomains(
final String targetId, final DateTime now, final Class<R> resourceClass) throws EppException {
EppException failfastException =
tm().transact(
() -> {
VKey<R> key = ForeignKeyUtils.load(resourceClass, targetId, now);
if (key == null) {
return new ResourceDoesNotExistException(resourceClass, targetId);
}
return isLinked(key, now) ? new ResourceToDeleteIsReferencedException() : null;
});
if (failfastException != null) {
throw failfastException;
VKey<R> key = ForeignKeyUtils.load(resourceClass, targetId, now);
if (key == null) {
throw new ResourceDoesNotExistException(resourceClass, targetId);
}
if (isLinked(key, now)) {
throw new ResourceToDeleteIsReferencedException();
}
}
@@ -169,7 +164,7 @@ public final class ResourceFlowUtils {
throw new BadAuthInfoForResourceException();
}
// Check the authInfo against the contact.
verifyAuthInfo(authInfo, tm().transact(() -> tm().loadByKey(foundContact.get())));
verifyAuthInfo(authInfo, tm().loadByKey(foundContact.get()));
}
/** Check that the given {@link AuthInfo} is valid for the given contact. */
@@ -23,8 +23,8 @@ import com.google.common.collect.ImmutableSet;
import google.registry.config.RegistryConfig.Config;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactCommand.Check;
@@ -45,7 +45,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
*/
@ReportingSpec(ActivityReportField.CONTACT_CHECK)
public final class ContactCheckFlow implements Flow {
public final class ContactCheckFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject @RegistrarId String registrarId;
@@ -28,7 +28,7 @@ import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException;
import google.registry.flows.exceptions.ResourceCreateContentionException;
@@ -54,7 +54,7 @@ import org.joda.time.DateTime;
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
@ReportingSpec(ActivityReportField.CONTACT_CREATE)
public final class ContactCreateFlow implements TransactionalFlow {
public final class ContactCreateFlow implements MutatingFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -32,7 +32,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactHistory;
@@ -63,7 +63,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.ResourceToDeleteIsReferencedException}
*/
@ReportingSpec(ActivityReportField.CONTACT_DELETE)
public final class ContactDeleteFlow implements TransactionalFlow {
public final class ContactDeleteFlow implements MutatingFlow {
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES =
ImmutableSet.of(
@@ -22,10 +22,10 @@ import static google.registry.model.EppResourceUtils.isLinked;
import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactInfoData;
@@ -51,7 +51,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
*/
@ReportingSpec(ActivityReportField.CONTACT_INFO)
public final class ContactInfoFlow implements Flow {
public final class ContactInfoFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Clock clock;
@@ -30,7 +30,7 @@ import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactHistory;
@@ -60,7 +60,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
*/
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_APPROVE)
public final class ContactTransferApproveFlow implements TransactionalFlow {
public final class ContactTransferApproveFlow implements MutatingFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -30,7 +30,7 @@ import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactHistory;
@@ -60,7 +60,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NotTransferInitiatorException}
*/
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_CANCEL)
public final class ContactTransferCancelFlow implements TransactionalFlow {
public final class ContactTransferCancelFlow implements MutatingFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -21,9 +21,9 @@ import static google.registry.flows.contact.ContactFlowUtils.createTransferRespo
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
@@ -52,7 +52,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotAuthorizedToViewTransferException}
*/
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_QUERY)
public final class ContactTransferQueryFlow implements Flow {
public final class ContactTransferQueryFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional<AuthInfo> authInfo;
@@ -30,7 +30,7 @@ import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactHistory;
@@ -59,7 +59,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
*/
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_REJECT)
public final class ContactTransferRejectFlow implements TransactionalFlow {
public final class ContactTransferRejectFlow implements MutatingFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional<AuthInfo> authInfo;
@@ -33,7 +33,7 @@ import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.AlreadyPendingTransferException;
import google.registry.flows.exceptions.ObjectAlreadySponsoredException;
@@ -72,7 +72,7 @@ import org.joda.time.Duration;
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
*/
@ReportingSpec(ActivityReportField.CONTACT_TRANSFER_REQUEST)
public final class ContactTransferRequestFlow implements TransactionalFlow {
public final class ContactTransferRequestFlow implements MutatingFlow {
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES =
ImmutableSet.of(
@@ -33,7 +33,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.model.contact.Contact;
@@ -66,7 +66,7 @@ import org.joda.time.DateTime;
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
@ReportingSpec(ActivityReportField.CONTACT_UPDATE)
public final class ContactUpdateFlow implements TransactionalFlow {
public final class ContactUpdateFlow implements MutatingFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -43,9 +43,9 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainCheckFlowCustomLogic;
import google.registry.flows.custom.DomainCheckFlowCustomLogic.BeforeResponseParameters;
@@ -121,7 +121,7 @@ import org.joda.time.DateTime;
* @error {@link OnlyCheckedNamesCanBeFeeCheckedException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_CHECK)
public final class DomainCheckFlow implements Flow {
public final class DomainCheckFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -382,17 +382,13 @@ public final class DomainCheckFlow implements Flow {
private ImmutableMap<String, BillingRecurrence> loadRecurrencesForDomains(
ImmutableMap<String, Domain> domainObjs) {
return tm().transact(
() -> {
ImmutableMap<VKey<? extends BillingRecurrence>, BillingRecurrence> recurrences =
tm().loadByKeys(
domainObjs.values().stream()
.map(Domain::getAutorenewBillingEvent)
.collect(toImmutableSet()));
return ImmutableMap.copyOf(
Maps.transformValues(
domainObjs, d -> recurrences.get(d.getAutorenewBillingEvent())));
});
ImmutableMap<VKey<? extends BillingRecurrence>, BillingRecurrence> recurrences =
tm().loadByKeys(
domainObjs.values().stream()
.map(Domain::getAutorenewBillingEvent)
.collect(toImmutableSet()));
return ImmutableMap.copyOf(
Maps.transformValues(domainObjs, d -> recurrences.get(d.getAutorenewBillingEvent())));
}
/**
@@ -31,9 +31,9 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.domain.DomainCommand.Check;
import google.registry.model.domain.launch.LaunchCheckExtension;
@@ -67,7 +67,7 @@ import org.joda.time.DateTime;
* @error {@link DomainClaimsCheckNotAllowedWithAllocationTokens}
*/
@ReportingSpec(ActivityReportField.DOMAIN_CHECK) // Claims check is a special domain check.
public final class DomainClaimsCheckFlow implements Flow {
public final class DomainClaimsCheckFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject EppInput eppInput;
@@ -67,7 +67,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainCreateFlowCustomLogic;
import google.registry.flows.custom.DomainCreateFlowCustomLogic.BeforeResponseParameters;
@@ -210,7 +210,7 @@ import org.joda.time.Duration;
* @error {@link DomainPricingLogic.AllocationTokenInvalidForPremiumNameException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_CREATE)
public final class DomainCreateFlow implements TransactionalFlow {
public final class DomainCreateFlow implements MutatingFlow {
/** Anchor tenant creates should always be for 2 years, since they get 2 years free. */
private static final int ANCHOR_TENANT_CREATE_VALID_YEARS = 2;
@@ -51,8 +51,8 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.MutatingFlow;
import google.registry.flows.SessionMetadata;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainDeleteFlowCustomLogic;
import google.registry.flows.custom.DomainDeleteFlowCustomLogic.AfterValidationParameters;
@@ -115,7 +115,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_DELETE)
public final class DomainDeleteFlow implements TransactionalFlow {
public final class DomainDeleteFlow implements MutatingFlow {
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_DELETE_PROHIBITED,
@@ -28,10 +28,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainInfoFlowCustomLogic;
import google.registry.flows.custom.DomainInfoFlowCustomLogic.AfterValidationParameters;
@@ -76,7 +76,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.TransfersAreAlwaysForOneYearException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_INFO)
public final class DomainInfoFlow implements Flow {
public final class DomainInfoFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject ResourceCommand resourceCommand;
@@ -120,14 +120,12 @@ public final class DomainInfoFlow implements Flow {
.setLastEppUpdateTime(domain.getLastEppUpdateTime())
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime())
.setLastTransferTime(domain.getLastTransferTime())
.setRegistrant(
tm().transact(() -> tm().loadByKey(domain.getRegistrant())).getContactId());
.setRegistrant(tm().loadByKey(domain.getRegistrant()).getContactId());
// If authInfo is non-null, then the caller is authorized to see the full information since we
// will have already verified the authInfo is valid.
if (registrarId.equals(domain.getCurrentSponsorRegistrarId()) || authInfo.isPresent()) {
infoBuilder
.setContacts(
tm().transact(() -> loadForeignKeyedDesignatedContacts(domain.getContacts())))
.setContacts(loadForeignKeyedDesignatedContacts(domain.getContacts()))
.setSubordinateHosts(
hostsRequest.requestSubordinate() ? domain.getSubordinateHosts() : null)
.setCreationRegistrarId(domain.getCreationRegistrarId())
@@ -178,7 +176,7 @@ public final class DomainInfoFlow implements Flow {
pricingLogic,
Optional.empty(),
false,
tm().transact(() -> tm().loadByKey(domain.getAutorenewBillingEvent())));
tm().loadByKey(domain.getAutorenewBillingEvent()));
extensions.add(builder.build());
}
return extensions.build();
@@ -44,7 +44,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainRenewFlowCustomLogic;
import google.registry.flows.custom.DomainRenewFlowCustomLogic.AfterValidationParameters;
@@ -137,7 +137,7 @@ import org.joda.time.Duration;
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_RENEW)
public final class DomainRenewFlow implements TransactionalFlow {
public final class DomainRenewFlow implements MutatingFlow {
private static final ImmutableSet<StatusValue> RENEW_DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_RENEW_PROHIBITED,
@@ -328,7 +328,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
checkHasBillingAccount(registrarId, existingDomain.getTld());
}
verifyUnitIsYears(command.getPeriod());
// We only allow __REMOVE_PACKAGE__ token on bulk pricing domains for now
// We only allow __REMOVEDOMAIN__ token on bulk pricing domains for now
verifyTokenAllowedOnDomain(existingDomain, allocationToken);
// If the date they specify doesn't match the expiration, fail. (This is an idempotence check).
if (!command.getCurrentExpirationDate().equals(
@@ -42,7 +42,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingBase.Reason;
@@ -112,7 +112,7 @@ import org.joda.time.DateTime;
* @error {@link DomainRestoreRequestFlow.RestoreCommandIncludesChangesException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_RGP_RESTORE_REQUEST)
public final class DomainRestoreRequestFlow implements TransactionalFlow {
public final class DomainRestoreRequestFlow implements MutatingFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -41,7 +41,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
import google.registry.model.ImmutableObject;
@@ -106,7 +106,7 @@ import org.joda.time.DateTime;
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_APPROVE)
public final class DomainTransferApproveFlow implements TransactionalFlow {
public final class DomainTransferApproveFlow implements MutatingFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional<AuthInfo> authInfo;
@@ -37,7 +37,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.domain.Domain;
@@ -74,7 +74,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_CANCEL)
public final class DomainTransferCancelFlow implements TransactionalFlow {
public final class DomainTransferCancelFlow implements MutatingFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional<AuthInfo> authInfo;
@@ -21,10 +21,10 @@ import static google.registry.flows.domain.DomainTransferUtils.createTransferRes
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.ResourceFlowUtils;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
@@ -56,7 +56,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NotAuthorizedToViewTransferException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_QUERY)
public final class DomainTransferQueryFlow implements Flow {
public final class DomainTransferQueryFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional<AuthInfo> authInfo;
@@ -39,7 +39,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.domain.Domain;
@@ -76,7 +76,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_REJECT)
public final class DomainTransferRejectFlow implements TransactionalFlow {
public final class DomainTransferRejectFlow implements MutatingFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional<AuthInfo> authInfo;
@@ -45,7 +45,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
import google.registry.flows.exceptions.AlreadyPendingTransferException;
@@ -135,7 +135,7 @@ import org.joda.time.DateTime;
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_REQUEST)
public final class DomainTransferRequestFlow implements TransactionalFlow {
public final class DomainTransferRequestFlow implements MutatingFlow {
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_TRANSFER_PROHIBITED,
@@ -55,7 +55,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainUpdateFlowCustomLogic;
import google.registry.flows.custom.DomainUpdateFlowCustomLogic.AfterValidationParameters;
@@ -133,7 +133,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.UrgentAttributeNotSupportedException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_UPDATE)
public final class DomainUpdateFlow implements TransactionalFlow {
public final class DomainUpdateFlow implements MutatingFlow {
/**
* A list of {@link StatusValue}s that prohibit updates.
@@ -23,8 +23,8 @@ import com.google.common.collect.ImmutableSet;
import google.registry.config.RegistryConfig.Config;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CheckData.HostCheck;
@@ -45,7 +45,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
*/
@ReportingSpec(ActivityReportField.HOST_CHECK)
public final class HostCheckFlow implements Flow {
public final class HostCheckFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject @RegistrarId String registrarId;
@@ -35,7 +35,7 @@ import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException;
import google.registry.flows.exceptions.ResourceCreateContentionException;
@@ -78,7 +78,7 @@ import org.joda.time.DateTime;
* @error {@link UnexpectedExternalHostIpException}
*/
@ReportingSpec(ActivityReportField.HOST_CREATE)
public final class HostCreateFlow implements TransactionalFlow {
public final class HostCreateFlow implements MutatingFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -30,7 +30,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.EppResource;
import google.registry.model.domain.metadata.MetadataExtension;
@@ -63,7 +63,7 @@ import org.joda.time.DateTime;
* @error {@link HostFlowUtils.HostNameNotPunyCodedException}
*/
@ReportingSpec(ActivityReportField.HOST_DELETE)
public final class HostDeleteFlow implements TransactionalFlow {
public final class HostDeleteFlow implements MutatingFlow {
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES =
ImmutableSet.of(
@@ -23,9 +23,9 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
@@ -50,7 +50,7 @@ import org.joda.time.DateTime;
* @error {@link HostFlowUtils.HostNameNotPunyCodedException}
*/
@ReportingSpec(ActivityReportField.HOST_INFO)
public final class HostInfoFlow implements Flow {
public final class HostInfoFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject @RegistrarId String registrarId;
@@ -77,8 +77,7 @@ public final class HostInfoFlow implements Flow {
// there is no superordinate domain, the host's own values for these fields will be correct.
if (host.isSubordinate()) {
Domain superordinateDomain =
tm().transact(
() -> tm().loadByKey(host.getSuperordinateDomain()).cloneProjectedAtTime(now));
tm().loadByKey(host.getSuperordinateDomain()).cloneProjectedAtTime(now);
hostInfoDataBuilder
.setCurrentSponsorRegistrarId(superordinateDomain.getCurrentSponsorRegistrarId())
.setLastTransferTime(host.computeLastTransferTime(superordinateDomain));
@@ -47,7 +47,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.model.EppResource;
@@ -107,7 +107,7 @@ import org.joda.time.DateTime;
* @error {@link RenameHostToExternalRemoveIpException}
*/
@ReportingSpec(ActivityReportField.HOST_UPDATE)
public final class HostUpdateFlow implements TransactionalFlow {
public final class HostUpdateFlow implements MutatingFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -31,7 +31,7 @@ import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.PollMessageId;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.MutatingFlow;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.MessageQueueInfo;
import google.registry.model.poll.PollMessage;
@@ -55,7 +55,7 @@ import org.joda.time.DateTime;
* @error {@link PollAckFlow.MissingMessageIdException}
* @error {@link PollAckFlow.NotAuthorizedToAckMessageException}
*/
public final class PollAckFlow implements TransactionalFlow {
public final class PollAckFlow implements MutatingFlow {
@Inject ExtensionManager extensionManager;
@Inject @RegistrarId String registrarId;
@@ -108,7 +108,7 @@ public final class PollAckFlow implements TransactionalFlow {
// acked, then we return a special status code indicating that. Note that the query will
// include the message being acked.
int messageCount = tm().transact(() -> getPollMessageCount(registrarId, now));
int messageCount = getPollMessageCount(registrarId, now);
if (messageCount <= 0) {
return responseBuilder.setResultFromCode(SUCCESS_WITH_NO_MESSAGES).build();
}
@@ -30,13 +30,12 @@ public final class PollFlowUtils {
/** Returns the number of poll messages for the given registrar that are not in the future. */
public static int getPollMessageCount(String registrarId, DateTime now) {
return tm().transact(() -> createPollMessageQuery(registrarId, now).count()).intValue();
return (int) createPollMessageQuery(registrarId, now).count();
}
/** Returns the first (by event time) poll message not in the future for this registrar. */
public static Optional<PollMessage> getFirstPollMessage(String registrarId, DateTime now) {
return tm().transact(
() -> createPollMessageQuery(registrarId, now).orderBy("eventTime").first());
return createPollMessageQuery(registrarId, now).orderBy("eventTime").first();
}
/**
@@ -20,18 +20,18 @@ import static google.registry.flows.poll.PollFlowUtils.getPollMessageCount;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACK_MESSAGE;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_NO_MESSAGES;
import static google.registry.model.poll.PollMessageExternalKeyConverter.makePollMessageExternalId;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.PollMessageId;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.TransactionalFlow;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.MessageQueueInfo;
import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessageExternalKeyConverter;
import google.registry.util.Clock;
import java.util.Optional;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -47,12 +47,11 @@ import org.joda.time.DateTime;
*
* @error {@link PollRequestFlow.UnexpectedMessageIdException}
*/
public final class PollRequestFlow implements Flow {
public final class PollRequestFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject @RegistrarId String registrarId;
@Inject @PollMessageId String messageId;
@Inject Clock clock;
@Inject EppResponse.Builder responseBuilder;
@Inject PollRequestFlow() {}
@@ -63,8 +62,9 @@ public final class PollRequestFlow implements Flow {
if (!messageId.isEmpty()) {
throw new UnexpectedMessageIdException();
}
// Return the oldest message from the queue.
DateTime now = clock.nowUtc();
DateTime now = tm().getTransactionTime();
Optional<PollMessage> maybePollMessage = getFirstPollMessage(registrarId, now);
if (!maybePollMessage.isPresent()) {
return responseBuilder.setResultFromCode(SUCCESS_WITH_NO_MESSAGES).build();
@@ -30,8 +30,8 @@ import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.EppException.UnimplementedObjectServiceException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.MutatingFlow;
import google.registry.flows.SessionMetadata;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.TransportCredentials;
import google.registry.model.eppcommon.ProtocolDefinition;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
@@ -62,7 +62,7 @@ import javax.inject.Inject;
* @error {@link LoginFlow.RegistrarAccountNotActiveException}
* @error {@link LoginFlow.UnsupportedLanguageException}
*/
public class LoginFlow implements TransactionalFlow {
public class LoginFlow implements MutatingFlow {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -23,6 +23,7 @@ import com.google.api.services.gmail.model.Message;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import dagger.Lazy;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.EmailMessage;
import google.registry.util.EmailMessage.Attachment;
@@ -49,7 +50,7 @@ public final class GmailClient {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final Gmail gmail;
private final Lazy<Gmail> gmail;
private final Retrier retrier;
private final boolean isEmailSendingEnabled;
private final InternetAddress outgoingEmailAddressWithUsername;
@@ -57,7 +58,7 @@ public final class GmailClient {
@Inject
GmailClient(
Gmail gmail,
Lazy<Gmail> gmail,
Retrier retrier,
@Config("isEmailSendingEnabled") boolean isEmailSendingEnabled,
@Config("gSuiteNewOutgoingEmailAddress") String gSuiteOutgoingEmailAddress,
@@ -99,7 +100,7 @@ public final class GmailClient {
// Unlike other Cloud APIs such as GCS and SecretManager, Gmail does not retry on errors.
retrier.callWithRetry(
// "me" is reserved word for the authorized user of the Gmail API.
() -> this.gmail.users().messages().send("me", message).execute(),
() -> this.gmail.get().users().messages().send("me", message).execute(),
RetriableGmailExceptionPredicate.INSTANCE);
}
@@ -119,7 +120,8 @@ public final class GmailClient {
MimeMessage msg =
new MimeMessage(Session.getDefaultInstance(new Properties(), /* authenticator= */ null));
msg.setFrom(this.outgoingEmailAddressWithUsername);
msg.setReplyTo(new InternetAddress[] {replyToEmailAddress});
msg.setReplyTo(
new InternetAddress[] {emailMessage.replyToEmailAddress().orElse(replyToEmailAddress)});
msg.addRecipients(
RecipientType.TO, toArray(emailMessage.recipients(), InternetAddress.class));
msg.setSubject(emailMessage.subject());
@@ -19,10 +19,12 @@ import static com.google.common.collect.Ordering.natural;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
@@ -54,8 +56,10 @@ public class EntityYamlUtils {
module.addSerializer(Money.class, new MoneySerializer());
module.addDeserializer(Money.class, new MoneyDeserializer());
ObjectMapper mapper =
new ObjectMapper(new YAMLFactory().disable(Feature.WRITE_DOC_START_MARKER))
JsonMapper.builder(new YAMLFactory().disable(Feature.WRITE_DOC_START_MARKER))
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
.build()
.registerModule(module);
mapper.findAndRegisterModules();
return mapper;
@@ -20,7 +20,6 @@ import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.union;
import static google.registry.config.RegistryConfig.getEppResourceCachingDuration;
import static google.registry.config.RegistryConfig.getEppResourceMaxCachedEntries;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
@@ -358,13 +357,13 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
@Override
public EppResource load(VKey<? extends EppResource> key) {
return replicaTm().transact(() -> replicaTm().loadByKey(key));
return tm().reTransact(() -> tm().loadByKey(key));
}
@Override
public Map<VKey<? extends EppResource>, EppResource> loadAll(
Iterable<? extends VKey<? extends EppResource>> keys) {
return replicaTm().transact(() -> replicaTm().loadByKeys(keys));
return tm().reTransact(() -> tm().loadByKeys(keys));
}
};
@@ -403,7 +402,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
public static ImmutableMap<VKey<? extends EppResource>, EppResource> loadCached(
Iterable<VKey<? extends EppResource>> keys) {
if (!RegistryConfig.isEppResourceCachingEnabled()) {
return tm().transact(() -> tm().loadByKeys(keys));
return tm().reTransact(() -> tm().loadByKeys(keys));
}
return ImmutableMap.copyOf(cacheEppResources.getAll(keys));
}
@@ -416,7 +415,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
*/
public static <T extends EppResource> T loadCached(VKey<T> key) {
if (!RegistryConfig.isEppResourceCachingEnabled()) {
return tm().transact(() -> tm().loadByKey(key));
return tm().reTransact(() -> tm().loadByKey(key));
}
// Safe to cast because loading a Key<T> returns an entity of type T.
@SuppressWarnings("unchecked")
@@ -156,7 +156,9 @@ public final class EppResourceUtils {
T resource =
useCache
? EppResource.loadCached(key)
: tm().transact(() -> tm().loadByKeyIfPresent(key).orElse(null));
// This transaction is buried very deeply inside many outer nested calls, hence merits
// the use of reTransact() for now pending a substantial refactoring.
: tm().reTransact(() -> tm().loadByKeyIfPresent(key).orElse(null));
if (resource == null || isAtOrAfter(now, resource.getDeletionTime())) {
return Optional.empty();
}
@@ -109,7 +109,7 @@ public final class ForeignKeyUtils {
Class<E> clazz, Collection<String> foreignKeys, boolean useReplicaTm) {
String fkProperty = RESOURCE_TYPE_TO_FK_PROPERTY.get(clazz);
JpaTransactionManager tmToUse = useReplicaTm ? replicaTm() : tm();
return tmToUse.transact(
return tmToUse.reTransact(
() ->
tmToUse
.query(
@@ -352,6 +352,10 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
!getInstance().tokenType.equals(TokenType.BULK_PRICING)
|| getInstance().renewalPriceBehavior.equals(RenewalPriceBehavior.SPECIFIED),
"Bulk tokens must have renewalPriceBehavior set to SPECIFIED");
checkArgument(
!getInstance().tokenType.equals(TokenType.BULK_PRICING)
|| ImmutableSet.of(CommandName.CREATE).equals(getInstance().allowedEppActions),
"Bulk tokens may only be valid for CREATE actions");
checkArgument(
!getInstance().tokenType.equals(TokenType.BULK_PRICING)
|| !getInstance().discountPremiums,
@@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.common.collect.Sets.immutableEnumSet;
@@ -49,7 +48,6 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.gson.annotations.Expose;
import com.google.re2j.Pattern;
import google.registry.model.Buildable;
@@ -556,7 +554,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
* address.
*/
public ImmutableSortedSet<RegistrarPoc> getContacts() {
return Streams.stream(getContactsIterable())
return getContactPocs().stream()
.filter(Objects::nonNull)
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
}
@@ -566,7 +564,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
* their email address.
*/
public ImmutableSortedSet<RegistrarPoc> getContactsOfType(final RegistrarPoc.Type type) {
return Streams.stream(getContactsIterable())
return getContactPocs().stream()
.filter(Objects::nonNull)
.filter((@Nullable RegistrarPoc contact) -> contact.getTypes().contains(type))
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
@@ -580,13 +578,13 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
return getContacts().stream().filter(RegistrarPoc::getVisibleInDomainWhoisAsAbuse).findFirst();
}
private Iterable<RegistrarPoc> getContactsIterable() {
private ImmutableSet<RegistrarPoc> getContactPocs() {
return tm().transact(
() ->
tm().query("FROM RegistrarPoc WHERE registrarId = :registrarId", RegistrarPoc.class)
.setParameter("registrarId", registrarId)
.getResultStream()
.collect(toImmutableList()));
.collect(toImmutableSet()));
}
@Override
@@ -732,8 +730,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
.map(Tld::createVKey)
.collect(toImmutableSet());
Set<VKey<Tld>> missingTldKeys =
Sets.difference(
newTldKeys, tm().transact(() -> tm().loadByKeysIfPresent(newTldKeys)).keySet());
Sets.difference(newTldKeys, tm().loadByKeysIfPresent(newTldKeys).keySet());
checkArgument(missingTldKeys.isEmpty(), "Trying to set nonexistent TLDs: %s", missingTldKeys);
getInstance().allowedTlds = ImmutableSortedSet.copyOf(allowedTlds);
return this;
@@ -206,13 +206,11 @@ public class ClaimsList extends ImmutableObject {
if (labelsToKeys != null) {
return Optional.ofNullable(labelsToKeys.get(label));
}
return tm().transact(
() ->
tm().createQueryComposer(ClaimsEntry.class)
.where("revisionId", EQ, revisionId)
.where("domainLabel", EQ, label)
.first()
.map(ClaimsEntry::getClaimKey));
return tm().createQueryComposer(ClaimsEntry.class)
.where("revisionId", EQ, revisionId)
.where("domainLabel", EQ, label)
.first()
.map(ClaimsEntry::getClaimKey);
}
public static ClaimsList create(
@@ -23,6 +23,7 @@ import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.flows.ServerTridProviderModule;
import google.registry.flows.custom.CustomLogicFactoryModule;
import google.registry.groups.DirectoryModule;
import google.registry.groups.GmailModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
@@ -54,6 +55,7 @@ import javax.inject.Singleton;
DirectoryModule.class,
DummyKeyringModule.class,
FrontendRequestComponentModule.class,
GmailModule.class,
GroupsModule.class,
GroupssettingsModule.class,
GsonModule.class,
@@ -158,6 +158,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
() -> transactNoRetry(work, isolationLevel), JpaRetries::isFailedTxnRetriable);
}
@Override
public <T> T reTransact(Supplier<T> work) {
return transact(work);
}
@Override
public <T> T transact(Supplier<T> work) {
return transact(work, null);
@@ -167,12 +172,17 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
public <T> T transactNoRetry(
Supplier<T> work, @Nullable TransactionIsolationLevel isolationLevel) {
if (inTransaction()) {
if (getHibernatePerTransactionIsolationEnabled()) {
throw new IllegalStateException("Nested transaction detected");
} else {
logger.atWarning().log("Nested transaction detected");
return work.get();
if (isolationLevel != null && getHibernatePerTransactionIsolationEnabled()) {
TransactionIsolationLevel enclosingLevel = getCurrentTransactionIsolationLevel();
if (isolationLevel != enclosingLevel) {
throw new IllegalStateException(
String.format(
"Isolation level conflict detected in nested transactions.\n"
+ "Enclosing transaction: %s\nCurrent transaction: %s",
enclosingLevel, isolationLevel));
}
}
return work.get();
}
TransactionInfo txnInfo = transactionInfo.get();
txnInfo.entityManager = emf.createEntityManager();
@@ -224,6 +234,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
isolationLevel);
}
@Override
public void reTransact(Runnable work) {
transact(work);
}
@Override
public void transact(Runnable work) {
transact(work, null);
@@ -56,12 +56,44 @@ public interface TransactionManager {
*/
<T> T transact(Supplier<T> work, TransactionIsolationLevel isolationLevel);
/**
* Executes the work in a (potentially wrapped) transaction and returns the result.
*
* <p>Calls to this method are typically going to be in inner functions, that are called either as
* top-level transactions themselves or are nested inside of larger transactions (e.g. a
* transactional flow). Invocations of reTransact must be vetted to occur in both situations and
* with such complexity that it is not trivial to refactor out the nested transaction calls. New
* code should be written in such a way as to avoid requiring reTransact in the first place.
*
* <p>In the future we will be enforcing that {@link #transact(Supplier)} calls be top-level only,
* with reTransact calls being the only ones that can potentially be an inner nested transaction
* (which is a noop). Note that, as this can be a nested inner exception, there is no overload
* provided to specify a (potentially conflicting) transaction isolation level.
*/
<T> T reTransact(Supplier<T> work);
/** Executes the work in a transaction. */
void transact(Runnable work);
/** Executes the work in a transaction at the given {@link TransactionIsolationLevel}. */
void transact(Runnable work, TransactionIsolationLevel isolationLevel);
/**
* Executes the work in a (potentially wrapped) transaction and returns the result.
*
* <p>Calls to this method are typically going to be in inner functions, that are called either as
* top-level transactions themselves or are nested inside of larger transactions (e.g. a
* transactional flow). Invocations of reTransact must be vetted to occur in both situations and
* with such complexity that it is not trivial to refactor out the nested transaction calls. New
* code should be written in such a way as to avoid requiring reTransact in the first place.
*
* <p>In the future we will be enforcing that {@link #transact(Runnable)} calls be top-level only,
* with reTransact calls being the only ones that can potentially be an inner nested transaction
* (which is a noop). Note that, as this can be a nested inner exception, there is no overload *
* provided to specify a (potentially conflicting) transaction isolation level.
*/
void reTransact(Runnable work);
/** Returns the time associated with the start of this particular transaction attempt. */
DateTime getTransactionTime();
@@ -23,12 +23,13 @@ import com.google.common.io.CharStreams;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.gcs.GcsUtils;
import google.registry.groups.GmailClient;
import google.registry.reporting.billing.BillingModule.InvoiceDirectoryPrefix;
import google.registry.util.EmailMessage;
import google.registry.util.EmailMessage.Attachment;
import google.registry.util.SendEmailService;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Optional;
import javax.inject.Inject;
import javax.mail.internet.InternetAddress;
import org.joda.time.YearMonth;
@@ -36,11 +37,12 @@ import org.joda.time.YearMonth;
/** Utility functions for sending emails involving monthly invoices. */
public class BillingEmailUtils {
private final SendEmailService emailService;
private final GmailClient gmailClient;
private final YearMonth yearMonth;
private final InternetAddress outgoingEmailAddress;
private final InternetAddress alertRecipientAddress;
private final ImmutableList<InternetAddress> invoiceEmailRecipients;
private final Optional<InternetAddress> replyToEmailAddress;
private final String billingBucket;
private final String invoiceFilePrefix;
private final String invoiceDirectoryPrefix;
@@ -48,20 +50,22 @@ public class BillingEmailUtils {
@Inject
BillingEmailUtils(
SendEmailService emailService,
GmailClient gmailClient,
YearMonth yearMonth,
@Config("gSuiteOutgoingEmailAddress") InternetAddress outgoingEmailAddress,
@Config("alertRecipientEmailAddress") InternetAddress alertRecipientAddress,
@Config("invoiceEmailRecipients") ImmutableList<InternetAddress> invoiceEmailRecipients,
@Config("invoiceReplyToEmailAddress") Optional<InternetAddress> replyToEmailAddress,
@Config("billingBucket") String billingBucket,
@Config("invoiceFilePrefix") String invoiceFilePrefix,
@InvoiceDirectoryPrefix String invoiceDirectoryPrefix,
GcsUtils gcsUtils) {
this.emailService = emailService;
this.gmailClient = gmailClient;
this.yearMonth = yearMonth;
this.outgoingEmailAddress = outgoingEmailAddress;
this.alertRecipientAddress = alertRecipientAddress;
this.invoiceEmailRecipients = invoiceEmailRecipients;
this.replyToEmailAddress = replyToEmailAddress;
this.billingBucket = billingBucket;
this.invoiceFilePrefix = invoiceFilePrefix;
this.invoiceDirectoryPrefix = invoiceDirectoryPrefix;
@@ -74,13 +78,14 @@ public class BillingEmailUtils {
String invoiceFile = String.format("%s-%s.csv", invoiceFilePrefix, yearMonth);
BlobId invoiceFilename = BlobId.of(billingBucket, invoiceDirectoryPrefix + invoiceFile);
try (InputStream in = gcsUtils.openInputStream(invoiceFilename)) {
emailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setSubject(String.format("Domain Registry invoice data %s", yearMonth))
.setBody(
String.format("Attached is the %s invoice for the domain registry.", yearMonth))
.setFrom(outgoingEmailAddress)
.setRecipients(invoiceEmailRecipients)
.setReplyToEmailAddress(replyToEmailAddress)
.setAttachment(
Attachment.newBuilder()
.setContent(CharStreams.toString(new InputStreamReader(in, UTF_8)))
@@ -100,7 +105,7 @@ public class BillingEmailUtils {
/** Sends an e-mail to the provided alert e-mail address indicating a billing failure. */
void sendAlertEmail(String body) {
try {
emailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setSubject(String.format("Billing Pipeline Alert: %s", yearMonth))
.setBody(body)
@@ -111,6 +111,10 @@ public class TmchXmlSignature {
dbf.setSchema(SCHEMA);
dbf.setAttribute("http://apache.org/xml/features/validation/schema/normalized-value", false);
dbf.setNamespaceAware(true);
// Disable DTDs
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setXIncludeAware(false); // disable XML Inclusions
dbf.setExpandEntityReferences(false); // disable expand entity reference nodes
return dbf.newDocumentBuilder().parse(input);
}
@@ -114,18 +114,19 @@ interface RegistryToolComponent {
void inject(GenerateEscrowDepositCommand command);
void inject(GetBulkPricingPackageCommand command);
void inject(GetContactCommand command);
void inject(GetDomainCommand command);
void inject(GetHostCommand command);
void inject(GetBulkPricingPackageCommand command);
void inject(GetKeyringSecretCommand command);
void inject(GetSqlCredentialCommand command);
void inject(GetTldCommand command);
void inject(GhostrydeCommand command);
void inject(ListCursorsCommand command);
@@ -20,8 +20,8 @@ import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig.Config;
import google.registry.groups.GmailClient;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
@@ -38,7 +38,7 @@ public class SendEmailUtils {
private final InternetAddress gSuiteOutgoingEmailAddress;
private final String gSuiteOutgoingEmailDisplayName;
private final SendEmailService emailService;
private final GmailClient gmailClient;
private final ImmutableList<String> registrarChangesNotificationEmailAddresses;
@Inject
@@ -47,10 +47,10 @@ public class SendEmailUtils {
@Config("gSuiteOutgoingEmailDisplayName") String gSuiteOutgoingEmailDisplayName,
@Config("registrarChangesNotificationEmailAddresses")
ImmutableList<String> registrarChangesNotificationEmailAddresses,
SendEmailService emailService) {
GmailClient gmailClient) {
this.gSuiteOutgoingEmailAddress = gSuiteOutgoingEmailAddress;
this.gSuiteOutgoingEmailDisplayName = gSuiteOutgoingEmailDisplayName;
this.emailService = emailService;
this.gmailClient = gmailClient;
this.registrarChangesNotificationEmailAddresses = registrarChangesNotificationEmailAddresses;
}
@@ -109,7 +109,7 @@ public class SendEmailUtils {
"Could not send email to %s with subject '%s'.", bcc, subject);
}
}
emailService.sendEmail(emailMessage.build());
gmailClient.sendEmail(emailMessage.build());
return true;
} catch (Throwable t) {
logger.atSevere().withCause(t).log(
@@ -31,6 +31,7 @@ import com.google.common.flogger.FluentLogger;
import com.google.gson.Gson;
import google.registry.config.RegistryConfig.Config;
import google.registry.flows.domain.DomainFlowUtils;
import google.registry.groups.GmailClient;
import google.registry.model.domain.RegistryLock;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
@@ -46,7 +47,6 @@ import google.registry.request.auth.UserAuthInfo;
import google.registry.security.JsonResponseHelper;
import google.registry.tools.DomainLockUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
@@ -83,7 +83,7 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
private final JsonActionRunner jsonActionRunner;
private final AuthResult authResult;
private final AuthenticatedRegistrarAccessor registrarAccessor;
private final SendEmailService sendEmailService;
private final GmailClient gmailClient;
private final DomainLockUtils domainLockUtils;
private final InternetAddress gSuiteOutgoingEmailAddress;
@@ -93,14 +93,14 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
JsonActionRunner jsonActionRunner,
AuthResult authResult,
AuthenticatedRegistrarAccessor registrarAccessor,
SendEmailService sendEmailService,
GmailClient gmailClient,
DomainLockUtils domainLockUtils,
@Config("gSuiteOutgoingEmailAddress") InternetAddress gSuiteOutgoingEmailAddress) {
this.req = req;
this.jsonActionRunner = jsonActionRunner;
this.authResult = authResult;
this.registrarAccessor = registrarAccessor;
this.sendEmailService = sendEmailService;
this.gmailClient = gmailClient;
this.domainLockUtils = domainLockUtils;
this.gSuiteOutgoingEmailAddress = gSuiteOutgoingEmailAddress;
}
@@ -168,7 +168,7 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
ImmutableList<InternetAddress> recipients =
ImmutableList.of(new InternetAddress(userEmail, true));
String action = isLock ? "lock" : "unlock";
sendEmailService.sendEmail(
gmailClient.sendEmail(
EmailMessage.newBuilder()
.setBody(body)
.setSubject(String.format("Registry %s verification", action))
@@ -28,8 +28,10 @@ import static org.mockito.Mockito.verifyNoInteractions;
import com.google.common.collect.ImmutableList;
import com.google.common.testing.TestLogHandler;
import google.registry.groups.GmailClient;
import google.registry.model.billing.BillingBase.RenewalPriceBehavior;
import google.registry.model.contact.Contact;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenType;
import google.registry.model.domain.token.BulkPricingPackage;
@@ -39,7 +41,6 @@ import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.ui.server.SendEmailUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.internet.InternetAddress;
@@ -77,7 +78,7 @@ public class CheckBulkComplianceActionTest {
private final TestLogHandler logHandler = new TestLogHandler();
private final Logger loggerToIntercept =
Logger.getLogger(CheckBulkComplianceAction.class.getCanonicalName());
private final SendEmailService emailService = mock(SendEmailService.class);
private final GmailClient gmailClient = mock(GmailClient.class);
private Contact contact;
private BulkPricingPackage bulkPricingPackage;
private SendEmailUtils sendEmailUtils;
@@ -91,7 +92,7 @@ public class CheckBulkComplianceActionTest {
new InternetAddress("outgoing@registry.example"),
"UnitTest Registry",
ImmutableList.of("notification@test.example", "notification2@test.example"),
emailService);
gmailClient);
createTld("tld");
action =
new CheckBulkComplianceAction(
@@ -113,6 +114,7 @@ public class CheckBulkComplianceActionTest {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
bulkPricingPackage =
@@ -143,7 +145,7 @@ public class CheckBulkComplianceActionTest {
.build());
action.run();
verifyNoInteractions(emailService);
verifyNoInteractions(gmailClient);
assertAboutLogs()
.that(logHandler)
.hasLogAtLevelWithMessage(
@@ -176,7 +178,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token abc123 has exceeded their max domain creation"
+ " limit by 1 name(s).");
verify(emailService).sendEmail(emailCaptor.capture());
verify(gmailClient).sendEmail(emailCaptor.capture());
EmailMessage emailMessage = emailCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo(CREATE_LIMIT_EMAIL_SUBJECT);
assertThat(emailMessage.body())
@@ -207,6 +209,7 @@ public class CheckBulkComplianceActionTest {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
BulkPricingPackage bulkPricingPackage2 =
@@ -248,7 +251,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token token has exceeded their max domain creation"
+ " limit by 1 name(s).");
verify(emailService, times(2)).sendEmail(any(EmailMessage.class));
verify(gmailClient, times(2)).sendEmail(any(EmailMessage.class));
}
@Test
@@ -263,6 +266,7 @@ public class CheckBulkComplianceActionTest {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
BulkPricingPackage packagePromotion2 =
@@ -292,7 +296,7 @@ public class CheckBulkComplianceActionTest {
.that(logHandler)
.hasLogAtLevelWithMessage(
Level.INFO, "Found no bulk pricing packages over their create limit.");
verifyNoInteractions(emailService);
verifyNoInteractions(gmailClient);
}
@Test
@@ -305,7 +309,7 @@ public class CheckBulkComplianceActionTest {
.build());
action.run();
verifyNoInteractions(emailService);
verifyNoInteractions(gmailClient);
assertAboutLogs()
.that(logHandler)
.hasLogAtLevelWithMessage(
@@ -337,6 +341,7 @@ public class CheckBulkComplianceActionTest {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
BulkPricingPackage bulkPricingPackage2 =
@@ -365,7 +370,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token abc123 has exceed their max active domains limit"
+ " by 1 name(s).");
verify(emailService).sendEmail(emailCaptor.capture());
verify(gmailClient).sendEmail(emailCaptor.capture());
EmailMessage emailMessage = emailCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT);
assertThat(emailMessage.body())
@@ -402,6 +407,7 @@ public class CheckBulkComplianceActionTest {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
BulkPricingPackage bulkPricingPackage2 =
@@ -442,7 +448,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token token has exceed their max active domains limit"
+ " by 1 name(s).");
verify(emailService, times(2)).sendEmail(any(EmailMessage.class));
verify(gmailClient, times(2)).sendEmail(any(EmailMessage.class));
}
@Test
@@ -479,7 +485,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token abc123 has exceed their max active domains limit"
+ " by 1 name(s).");
verifyNoInteractions(emailService);
verifyNoInteractions(gmailClient);
BulkPricingPackage packageAfterCheck =
tm().transact(() -> BulkPricingPackage.loadByTokenString(token.getToken()).get());
assertThat(packageAfterCheck.getLastNotificationSent().get())
@@ -520,7 +526,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token abc123 has exceed their max active domains limit"
+ " by 1 name(s).");
verify(emailService).sendEmail(emailCaptor.capture());
verify(gmailClient).sendEmail(emailCaptor.capture());
EmailMessage emailMessage = emailCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT);
assertThat(emailMessage.body())
@@ -565,7 +571,7 @@ public class CheckBulkComplianceActionTest {
Level.INFO,
"Bulk pricing package with bulk token abc123 has exceed their max active domains limit"
+ " by 1 name(s).");
verify(emailService).sendEmail(emailCaptor.capture());
verify(gmailClient).sendEmail(emailCaptor.capture());
EmailMessage emailMessage = emailCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_UPGRADE_EMAIL_SUBJECT);
assertThat(emailMessage.body())
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.cloud.tasks.v2.HttpMethod;
import com.google.common.collect.ImmutableSet;
import google.registry.groups.GmailClient;
import google.registry.model.domain.Domain;
import google.registry.model.domain.RegistryLock;
import google.registry.model.host.Host;
@@ -48,7 +49,6 @@ import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.tools.DomainLockUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import google.registry.util.StringGenerator.Alphabets;
import java.util.Optional;
import javax.mail.internet.InternetAddress;
@@ -85,7 +85,7 @@ public class RelockDomainActionTest {
private Domain domain;
private RegistryLock oldLock;
@Mock private SendEmailService sendEmailService;
@Mock private GmailClient gmailClient;
private RelockDomainAction action;
@BeforeEach
@@ -107,7 +107,7 @@ public class RelockDomainActionTest {
@AfterEach
void afterEach() {
verifyNoMoreInteractions(sendEmailService);
verifyNoMoreInteractions(gmailClient);
}
@Test
@@ -260,7 +260,7 @@ public class RelockDomainActionTest {
ImmutableSet.of(new InternetAddress("Marla.Singer.RegistryLock@crr.com")))
.setFrom(new InternetAddress("outgoing@example.com"))
.build();
verify(sendEmailService).sendEmail(expectedEmail);
verify(gmailClient).sendEmail(expectedEmail);
}
private void assertNonTransientFailureEmail(String exceptionMessage) throws Exception {
@@ -294,7 +294,7 @@ public class RelockDomainActionTest {
.setRecipients(recipients)
.setFrom(new InternetAddress("outgoing@example.com"))
.build();
verify(sendEmailService).sendEmail(expectedEmail);
verify(gmailClient).sendEmail(expectedEmail);
}
private void assertTaskEnqueued(int numAttempts) {
@@ -328,7 +328,7 @@ public class RelockDomainActionTest {
alertRecipientAddress,
gSuiteOutgoingAddress,
"support@example.com",
sendEmailService,
gmailClient,
domainLockUtils,
response);
}
@@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableSortedMap;
import google.registry.batch.SendExpiringCertificateNotificationEmailAction.CertificateType;
import google.registry.batch.SendExpiringCertificateNotificationEmailAction.RegistrarInfo;
import google.registry.flows.certs.CertificateChecker;
import google.registry.groups.GmailClient;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
@@ -41,7 +42,6 @@ import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationT
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.util.SelfSignedCaCertificate;
import google.registry.util.SendEmailService;
import java.security.cert.X509Certificate;
import java.util.Optional;
import javax.annotation.Nullable;
@@ -75,7 +75,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("2021-05-24T20:21:22Z"));
private final SendEmailService sendEmailService = mock(SendEmailService.class);
private final GmailClient sendEmailService = mock(GmailClient.class);
private CertificateChecker certificateChecker;
private SendExpiringCertificateNotificationEmailAction action;
private Registrar sampleRegistrar;
@@ -50,6 +50,7 @@ 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.groups.GmailClient;
import google.registry.model.domain.Domain;
import google.registry.model.tld.Tld;
import google.registry.persistence.transaction.JpaTestExtensions;
@@ -63,7 +64,6 @@ import google.registry.testing.FakeLockHandler;
import google.registry.testing.FakeResponse;
import google.registry.testing.Lazies;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.util.Set;
import javax.mail.internet.InternetAddress;
import org.joda.time.DateTime;
@@ -90,7 +90,7 @@ public class PublishDnsUpdatesActionTest {
private InternetAddress outgoingRegistry;
private Lazy<InternetAddress> registrySupportEmail;
private Lazy<InternetAddress> registryCcEmail;
private final SendEmailService emailService = mock(SendEmailService.class);
private final GmailClient emailService = mock(GmailClient.class);
@BeforeEach
void beforeEach() throws Exception {
@@ -145,14 +145,14 @@ public abstract class FlowTestCase<F extends Flow> {
sessionMetadata.setRegistrarId(registrarId);
}
public void assertTransactionalFlow(boolean isTransactional) throws Exception {
public void assertMutatingFlow(boolean isMutating) throws Exception {
Class<? extends Flow> flowClass = FlowPicker.getFlowClass(eppLoader.getEpp());
if (isTransactional) {
assertThat(flowClass).isAssignableTo(TransactionalFlow.class);
if (isMutating) {
assertThat(flowClass).isAssignableTo(MutatingFlow.class);
} else {
// There's no "isNotAssignableTo" in Truth.
assertWithMessage(flowClass.getSimpleName() + " implements TransactionalFlow")
.that(TransactionalFlow.class.isAssignableFrom(flowClass))
assertWithMessage(flowClass.getSimpleName() + " implements MutatingFlow")
.that(MutatingFlow.class.isAssignableFrom(flowClass))
.isFalse();
}
}
@@ -30,7 +30,7 @@ public abstract class ResourceCheckFlowTestCase<F extends Flow, R extends EppRes
extends ResourceFlowTestCase<F, R> {
protected void doCheckTest(CheckData.Check... expected) throws Exception {
assertTransactionalFlow(false);
assertMutatingFlow(false);
assertThat(((CheckData) runFlow().getResponse().getResponseData().get(0)).getChecks())
.containsExactlyElementsIn(expected);
assertNoHistory(); // Checks don't create a history event.
@@ -44,7 +44,7 @@ class ContactCreateFlowTest extends ResourceFlowTestCase<ContactCreateFlow, Cont
}
private void doSuccessfulTest() throws Exception {
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("contact_create_response.xml"));
// Check that the contact was created and persisted with a history entry.
Contact contact = reloadResourceByForeignKey();
@@ -78,7 +78,7 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
void testSuccess() throws Exception {
persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response.xml"));
assertSqlDeleteSuccess();
}
@@ -94,7 +94,7 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
clock.nowUtc())
.getTransferData();
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response.xml"));
assertSqlDeleteSuccess(Type.CONTACT_DELETE, Type.CONTACT_TRANSFER_REQUEST);
Contact softDeletedContact = reloadResourceByForeignKey(clock.nowUtc().minusMillis(1));
@@ -130,7 +130,7 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
setEppInput("contact_delete_no_cltrid.xml");
persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response_no_cltrid.xml"));
assertSqlDeleteSuccess();
}
@@ -109,7 +109,7 @@ class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, Contact>
void testSuccess() throws Exception {
persistContact(true);
// Check that the persisted contact info was returned.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
loadFile("contact_info_response.xml"),
// We use a different roid scheme than the samples so ignore it.
@@ -123,7 +123,7 @@ class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, Contact>
createTld("foobar");
persistResource(DatabaseHelper.newDomain("example.foobar", persistContact(true)));
// Check that the persisted contact info was returned.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
loadFile("contact_info_response_linked.xml"),
// We use a different roid scheme than the samples so ignore it.
@@ -137,7 +137,7 @@ class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, Contact>
setEppInput("contact_info_no_authinfo.xml");
persistContact(true);
// Check that the persisted contact info was returned.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
loadFile("contact_info_response.xml"),
// We use a different roid scheme than the samples so ignore it.
@@ -151,7 +151,7 @@ class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, Contact>
setRegistrarIdForFlow("NewRegistrar");
persistContact(true);
// Check that the persisted contact info was returned.
assertTransactionalFlow(false);
assertMutatingFlow(false);
ResourceNotOwnedException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@@ -162,7 +162,7 @@ class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, Contact>
setEppInput("contact_info_no_authinfo.xml");
persistContact(true);
// Check that the persisted contact info was returned.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
CommitMode.LIVE,
UserPrivileges.SUPERUSER,
@@ -178,7 +178,7 @@ class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, Contact>
setRegistrarIdForFlow("NewRegistrar");
persistContact(true);
// Check that the persisted contact info was returned.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
CommitMode.LIVE,
UserPrivileges.SUPERUSER,
@@ -69,7 +69,7 @@ class ContactTransferApproveFlowTest
// Setup done; run the test.
contact = reloadResourceByForeignKey();
TransferData originalTransferData = contact.getTransferData();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename));
// Transfer should have succeeded. Verify correct fields were set.
@@ -120,7 +120,7 @@ class ContactTransferApproveFlowTest
private void doFailingTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -63,7 +63,7 @@ class ContactTransferCancelFlowTest
// Setup done; run the test.
contact = reloadResourceByForeignKey();
TransferData originalTransferData = contact.getTransferData();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename));
// Transfer should have been cancelled. Verify correct fields were set.
@@ -104,7 +104,7 @@ class ContactTransferCancelFlowTest
private void doFailingTest(String commandFilename) throws Exception {
this.setEppInput(commandFilename);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -53,7 +53,7 @@ class ContactTransferQueryFlowTest
setEppInput(commandFilename);
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile(expectedXmlFilename));
assertAboutContacts().that(reloadResourceByForeignKey(clock.nowUtc().minusDays(1)))
.hasOneHistoryEntryEachOfTypes(HistoryEntry.Type.CONTACT_TRANSFER_REQUEST);
@@ -64,7 +64,7 @@ class ContactTransferQueryFlowTest
setEppInput(commandFilename);
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlow();
}
@@ -67,7 +67,7 @@ class ContactTransferRejectFlowTest
// Setup done; run the test.
contact = reloadResourceByForeignKey();
TransferData originalTransferData = contact.getTransferData();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename));
// Transfer should have failed. Verify correct fields were set.
@@ -119,7 +119,7 @@ class ContactTransferRejectFlowTest
private void doFailingTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -78,7 +78,7 @@ class ContactTransferRequestFlowTest
DateTime afterTransfer = clock.nowUtc().plus(getContactAutomaticTransferLength());
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename));
// Transfer should have been requested. Verify correct fields were set.
@@ -140,7 +140,7 @@ class ContactTransferRequestFlowTest
private void doFailingTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -53,7 +53,7 @@ class ContactUpdateFlowTest extends ResourceFlowTestCase<ContactUpdateFlow, Cont
private void doSuccessfulTest() throws Exception {
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
Contact contact = reloadResourceByForeignKey();
// Check that the contact was updated. This value came from the xml.
@@ -58,7 +58,7 @@ public class DomainClaimsCheckFlowTest extends ResourceFlowTestCase<DomainClaims
}
protected void doSuccessfulTest(String expectedXmlFilename) throws Exception {
assertTransactionalFlow(false);
assertMutatingFlow(false);
assertNoHistory(); // Checks don't create a history event.
assertNoBillingEvents(); // Checks are always free.
runFlowAssertResponse(loadFile(expectedXmlFilename));
@@ -152,7 +152,7 @@ public class DomainClaimsCheckFlowTest extends ResourceFlowTestCase<DomainClaims
ImmutableMap.of("example2", "2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001"));
persistResource(
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
assertNoHistory(); // Checks don't create a history event.
assertNoBillingEvents(); // Checks are always free.
runFlowAssertResponse(
@@ -158,6 +158,7 @@ import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.fee.BaseFee.FeeType;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DomainDsData;
@@ -428,7 +429,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
UserPrivileges userPrivileges,
Map<String, String> substitutions)
throws Exception {
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(
CommitMode.LIVE, userPrivileges, loadFile(responseXmlFile, substitutions));
assertSuccessfulCreate(domainTld, ImmutableSet.of());
@@ -613,7 +614,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
createTld("foo.tld");
setEppInput("domain_create_with_tld.xml", ImmutableMap.of("TLD", "foo.tld"));
persistContactsAndHosts("foo.tld");
assertTransactionalFlow(true);
assertMutatingFlow(true);
String expectedResponseXml =
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.foo.tld"));
runFlowAssertResponse(CommitMode.LIVE, UserPrivileges.NORMAL, expectedResponseXml);
@@ -3681,6 +3682,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.setTokenType(BULK_PRICING)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setRenewalPriceBehavior(SPECIFIED)
.build());
persistContactsAndHosts();
@@ -3707,6 +3709,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedTlds(ImmutableSet.of("tld"))
.setRenewalPriceBehavior(SPECIFIED)
.build());
@@ -152,7 +152,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.setAutorenewPollMessage(autorenewPollMessage.createVKey())
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
}
private void createReferencedEntities(DateTime expirationTime) throws Exception {
@@ -217,7 +217,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.setAutorenewBillingEvent(autorenewBillingEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey())
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
}
private void assertAutorenewClosedAndCancellationCreatedFor(
@@ -63,6 +63,7 @@ import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DomainDsData;
import google.registry.model.domain.token.AllocationToken;
@@ -177,7 +178,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
ImmutableMap<String, String> substitutions,
boolean expectHistoryAndBilling)
throws Exception {
assertTransactionalFlow(false);
assertMutatingFlow(false);
String expected =
loadFile(expectedXmlFilename, updateSubstitutions(substitutions, "ROID", "2FF-TLD"));
if (inactive) {
@@ -1096,6 +1097,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("NewRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
domain = domain.asBuilder().setCurrentBulkToken(token.createVKey()).build();
@@ -1116,6 +1118,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("NewRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
domain = domain.asBuilder().setCurrentBulkToken(token.createVKey()).build();
@@ -1148,6 +1151,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
.setAllowedTlds(ImmutableSet.of("foo"))
.setAllowedRegistrarIds(ImmutableSet.of("NewRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(1)
.build());
domain = domain.asBuilder().setCurrentBulkToken(token.createVKey()).build();
@@ -250,7 +250,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
RenewalPriceBehavior renewalPriceBehavior,
@Nullable Money renewalPrice)
throws Exception {
assertTransactionalFlow(true);
assertMutatingFlow(true);
DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime();
DateTime newExpiration = currentExpiration.plusYears(renewalYears);
runFlowAssertResponse(
@@ -1258,14 +1258,22 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.build());
persistDomain();
persistResource(
reloadResourceByForeignKey().asBuilder().setCurrentBulkToken(token.createVKey()).build());
persistResource(
new AllocationToken.Builder()
.setToken("token")
.setTokenType(SINGLE_USE)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
setEppInput(
"domain_renew_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "token"));
EppException thrown =
assertThrows(MissingRemoveDomainTokenOnBulkPricingDomainException.class, this::runFlow);
@@ -1282,6 +1290,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.build());
persistDomain();
persistResource(
@@ -1317,6 +1326,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.build());
persistDomain(SPECIFIED, Money.of(USD, 2));
persistResource(
@@ -1346,6 +1356,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.build());
persistDomain(SPECIFIED, Money.of(USD, 2));
persistResource(
@@ -163,7 +163,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
setEppInput("domain_update_restore_request.xml", ImmutableMap.of("DOMAIN", "example.tld"));
DateTime expirationTime = clock.nowUtc().plusYears(5).plusDays(45);
persistPendingDeleteDomain(expirationTime);
assertTransactionalFlow(true);
assertMutatingFlow(true);
// Double check that we see a poll message in the future for when the delete happens.
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
@@ -231,7 +231,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
DateTime expirationTime = clock.nowUtc().minusDays(20);
DateTime newExpirationTime = expirationTime.plusYears(1);
persistPendingDeleteDomain(expirationTime);
assertTransactionalFlow(true);
assertMutatingFlow(true);
// Double check that we see a poll message in the future for when the delete happens.
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
@@ -73,6 +73,7 @@ import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
@@ -200,7 +201,7 @@ class DomainTransferApproveFlowTest
assertThat(getPollMessages(domain, "TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
// Setup done; run the test.
DomainTransferData originalTransferData = domain.getTransferData();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename));
// Transfer should have succeeded. Verify correct fields were set.
domain = reloadResourceByForeignKey();
@@ -364,7 +365,7 @@ class DomainTransferApproveFlowTest
private void doFailingTest(String commandFilename) throws Exception {
setEppLoader(commandFilename);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -390,6 +391,7 @@ class DomainTransferApproveFlowTest
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.build());
domain = reloadResourceByForeignKey();
persistResource(
@@ -417,6 +419,7 @@ class DomainTransferApproveFlowTest
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain = reloadResourceByForeignKey();
@@ -116,7 +116,7 @@ class DomainTransferCancelFlowTest
clock.advanceOneMilli();
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
DateTime originalExpirationTime = domain.getRegistrationExpirationTime();
ImmutableSet<GracePeriod> originalGracePeriods = domain.getGracePeriods();
DomainTransferData originalTransferData = domain.getTransferData();
@@ -190,7 +190,7 @@ class DomainTransferCancelFlowTest
// Replace the ROID in the xml file with the one generated in our test.
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -55,7 +55,7 @@ class DomainTransferQueryFlowTest
// Replace the ROID in the xml file with the one generated in our test.
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile(expectedXmlFilename));
assertAboutDomains()
.that(domain)
@@ -76,7 +76,7 @@ class DomainTransferQueryFlowTest
// Replace the ROID in the xml file with the one generated in our test.
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlow();
}
@@ -89,7 +89,7 @@ class DomainTransferRejectFlowTest
assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
DateTime originalExpirationTime = domain.getRegistrationExpirationTime();
ImmutableSet<GracePeriod> originalGracePeriods = domain.getGracePeriods();
TransferData originalTransferData = domain.getTransferData();
@@ -152,7 +152,7 @@ class DomainTransferRejectFlowTest
// Replace the ROID in the xml file with the one generated in our test.
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow();
}
@@ -105,6 +105,7 @@ import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
@@ -483,7 +484,7 @@ class DomainTransferRequestFlowTest
Tld registry = Tld.get(domain.getTld());
DateTime implicitTransferTime = clock.nowUtc().plus(registry.getAutomaticTransferLength());
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename, substitutions));
// Transfer should have been requested.
domain = reloadResourceByForeignKey();
@@ -583,7 +584,7 @@ class DomainTransferRequestFlowTest
// the transfer timeline 3 days later by adjusting the implicit transfer time here.
DateTime implicitTransferTime = clock.nowUtc().plus(expectedAutomaticTransferLength);
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile(expectedXmlFilename, substitutions));
@@ -634,7 +635,7 @@ class DomainTransferRequestFlowTest
// Replace the ROID in the xml file with the one generated in our test.
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlow(CommitMode.LIVE, userPrivileges);
}
@@ -1345,6 +1346,7 @@ class DomainTransferRequestFlowTest
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain =
@@ -1403,6 +1405,7 @@ class DomainTransferRequestFlowTest
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain =
@@ -1460,6 +1463,7 @@ class DomainTransferRequestFlowTest
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain =
@@ -1741,7 +1745,7 @@ class DomainTransferRequestFlowTest
"domain_transfer_request_wildcard.xml",
ImmutableMap.of("YEARS", "1", "DOMAIN", "--invalid", "EXDATE", "2002-09-08T22:00:00.0Z"));
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
assertTransactionalFlow(true);
assertMutatingFlow(true);
ResourceDoesNotExistException thrown =
assertThrows(
ResourceDoesNotExistException.class,
@@ -203,7 +203,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
}
private void doSuccessfulTest(String expectedXmlFilename) throws Exception {
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile(expectedXmlFilename));
Domain domain = reloadResourceByForeignKey();
// Check that the domain was updated. These values came from the xml.
@@ -341,7 +341,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.setRegistrant(contacts.get(3).getContactKey())
.build());
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
Domain domain = reloadResourceByForeignKey();
assertAboutDomains().that(domain).hasOneHistoryEntryEachOfTypes(DOMAIN_CREATE, DOMAIN_UPDATE);
@@ -407,7 +407,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.createVKey()))
.build());
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
domain = reloadResourceByForeignKey();
assertThat(domain.getNameservers()).containsExactly(addedHost.createVKey());
@@ -490,7 +490,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.asBuilder()
.setDsData(originalDsData)
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
clock.advanceOneMilli();
runFlowAssertResponse(loadFile("generic_success_response.xml"));
Domain resource = reloadResourceByForeignKey();
@@ -81,7 +81,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
private void doSuccessfulTest() throws Exception {
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("host_create_response.xml"));
Host host = reloadResourceByForeignKey();
// Check that the host was created and persisted with a history entry.
@@ -77,7 +77,7 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Host> {
void testSuccess() throws Exception {
persistActiveHost("ns1.example.tld");
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("host_delete_response.xml"));
assertSqlDeleteSuccess();
}
@@ -87,7 +87,7 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Host> {
setEppInput("host_delete_no_cltrid.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld"));
persistActiveHost("ns1.example.tld");
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("host_delete_response_no_cltrid.xml"));
assertSqlDeleteSuccess();
}
@@ -82,7 +82,7 @@ class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, Host> {
@Test
void testSuccess() throws Exception {
persistHost();
assertTransactionalFlow(false);
assertMutatingFlow(false);
// Check that the persisted host info was returned.
runFlowAssertResponse(
loadFile("host_info_response.xml"),
@@ -100,7 +100,7 @@ class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, Host> {
.asBuilder()
.addNameserver(persistHost().createVKey())
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
// Check that the persisted host info was returned.
runFlowAssertResponse(
loadFile("host_info_response_linked.xml"),
@@ -131,7 +131,7 @@ class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, Host> {
.build());
// we shouldn't have two active hosts with the same hostname
deleteResource(firstHost);
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
loadFile("host_info_response_superordinate_clientid.xml"),
// We use a different roid scheme than the samples so ignore it.
@@ -160,7 +160,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
private Host doSuccessfulTest(boolean isSuperuser) throws Exception {
clock.advanceOneMilli();
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(
CommitMode.LIVE,
isSuperuser ? UserPrivileges.SUPERUSER : UserPrivileges.NORMAL,
@@ -96,7 +96,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setMsg("Some poll message.")
.setHistoryEntry(createHistoryEntryForEppResource(contact))
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
}
@@ -111,14 +111,14 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setMsg("Some poll message.")
.setHistoryEntry(createHistoryEntryForEppResource(contact))
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(MessageDoesNotExistException.class, this::runFlow);
}
@Test
void testSuccess_messageOnContact() throws Exception {
persistOneTimePollMessage(MESSAGE_ID);
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
}
@@ -126,7 +126,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
void testSuccess_recentActiveAutorenew() throws Exception {
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "3-2010"));
persistAutorenewPollMessage(clock.nowUtc().minusMonths(6), END_OF_TIME);
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
}
@@ -139,7 +139,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
for (int i = 1; i < 4; i++) {
persistOneTimePollMessage(MESSAGE_ID + i);
}
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(
loadFile("poll_ack_response.xml", ImmutableMap.of("MSGID", "3-2009", "COUNT", "4")));
}
@@ -148,7 +148,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
void testSuccess_oldInactiveAutorenew() throws Exception {
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "3-2010"));
persistAutorenewPollMessage(clock.nowUtc().minusMonths(6), clock.nowUtc());
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
}
@@ -158,14 +158,14 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
for (int i = 0; i < 5; i++) {
persistOneTimePollMessage(MESSAGE_ID + i);
}
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(
loadFile("poll_ack_response.xml", ImmutableMap.of("MSGID", "3-2011", "COUNT", "4")));
}
@Test
void testFailure_noSuchMessage() throws Exception {
assertTransactionalFlow(true);
assertMutatingFlow(true);
Exception e = assertThrows(MessageDoesNotExistException.class, this::runFlow);
assertThat(e).hasMessageThat().contains(String.format("(%d-2011)", MESSAGE_ID));
}
@@ -173,14 +173,14 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
@Test
void testFailure_invalidId_tooFewComponents() throws Exception {
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "1"));
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(InvalidMessageIdException.class, this::runFlow);
}
@Test
void testFailure_invalidId_tooManyComponents() throws Exception {
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "2-2-1999-2007"));
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(InvalidMessageIdException.class, this::runFlow);
}
@@ -195,21 +195,21 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setMsg("Some poll message.")
.setHistoryEntry(createHistoryEntryForEppResource(contact))
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(InvalidMessageIdException.class, this::runFlow);
}
@Test
void testFailure_invalidId_stringInsteadOfNumeric() throws Exception {
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "ABC-12345"));
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(InvalidMessageIdException.class, this::runFlow);
}
@Test
void testFailure_missingId() throws Exception {
setEppInput("poll_ack_missing_id.xml");
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(MissingMessageIdException.class, this::runFlow);
}
@@ -223,7 +223,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setMsg("Some poll message.")
.setHistoryEntry(createHistoryEntryForEppResource(domain))
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
assertThrows(NotAuthorizedToAckMessageException.class, this::runFlow);
}
@@ -237,7 +237,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setMsg("Some poll message.")
.setHistoryEntry(createHistoryEntryForEppResource(domain))
.build());
assertTransactionalFlow(true);
assertMutatingFlow(true);
Exception e = assertThrows(MessageDoesNotExistException.class, this::runFlow);
assertThat(e).hasMessageThat().contains(String.format("(%d-2011)", MESSAGE_ID));
}
@@ -87,7 +87,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
@Test
void testSuccess_domainTransferApproved() throws Exception {
persistPendingTransferPollMessage();
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_domain_transfer.xml"));
}
@@ -95,7 +95,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
void testSuccess_clTridNotSpecified() throws Exception {
setEppInput("poll_no_cltrid.xml");
persistPendingTransferPollMessage();
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_domain_transfer_no_cltrid.xml"));
}
@@ -120,7 +120,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.build()))
.setHistoryEntry(createHistoryEntryForEppResource(contact))
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_contact_transfer.xml"));
}
@@ -140,7 +140,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
clock.nowUtc())))
.setHistoryEntry(createHistoryEntryForEppResource(domain))
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_domain_pending_notification.xml"));
}
@@ -164,7 +164,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
clock.nowUtc())))
.setHistoryEntry(createHistoryEntryForEppResource(domain))
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_message_domain_pending_action_immediate_delete.xml"));
}
@@ -178,7 +178,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setTargetId("test.example")
.setHistoryEntry(createHistoryEntryForEppResource(domain))
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_autorenew.xml"));
}
@@ -221,7 +221,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setTargetId("target.example")
.setHistoryEntry(createHistoryEntryForEppResource(domain))
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_empty.xml"));
}
@@ -244,7 +244,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setHistoryEntry(historyEntry)
.setEventTime(clock.nowUtc().minusDays(1))
.build());
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_contact_delete.xml"));
}
@@ -268,14 +268,14 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setEventTime(clock.nowUtc().minusDays(1))
.build());
clock.advanceOneMilli();
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(loadFile("poll_response_host_delete.xml"));
}
@Test
void testFailure_messageIdProvided() throws Exception {
setEppInput("poll_with_id.xml");
assertTransactionalFlow(false);
assertMutatingFlow(false);
EppException thrown = assertThrows(UnexpectedMessageIdException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@@ -30,7 +30,7 @@ class HelloFlowTest extends FlowTestCase<HelloFlow> {
@Test
void testHello() throws Exception {
setEppInput("hello.xml");
assertTransactionalFlow(false);
assertMutatingFlow(false);
runFlowAssertResponse(
loadFile(
"greeting.xml", ImmutableMap.of("DATE", clock.nowUtc().toString(dateTimeNoMillis()))));
@@ -62,7 +62,7 @@ public abstract class LoginFlowTestCase extends FlowTestCase<LoginFlow> {
// Also called in subclasses.
void doSuccessfulTest(String xmlFilename) throws Exception {
setEppInput(xmlFilename);
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
}
@@ -81,7 +81,7 @@ public abstract class LoginFlowTestCase extends FlowTestCase<LoginFlow> {
@Test
void testSuccess_setsIsLoginResponse() throws Exception {
setEppInput("login_valid.xml");
assertTransactionalFlow(true);
assertMutatingFlow(true);
EppOutput output = runFlow();
assertThat(output.getResponse().isLoginResponse()).isTrue();
}
@@ -125,7 +125,7 @@ public abstract class LoginFlowTestCase extends FlowTestCase<LoginFlow> {
assertThat(registrar.verifyPassword("randomstring")).isFalse();
setEppInput("login_set_new_password.xml", ImmutableMap.of("NEWPW", "ANewPassword"));
assertTransactionalFlow(true);
assertMutatingFlow(true);
runFlowAssertResponse(loadFile("generic_success_response.xml"));
Registrar newRegistrar = loadRegistrar("NewRegistrar");
@@ -38,7 +38,7 @@ class LogoutFlowTest extends FlowTestCase<LogoutFlow> {
@Test
void testSuccess() throws Exception {
assertTransactionalFlow(false);
assertMutatingFlow(false);
// All flow tests are implicitly logged in, so logout should work.
runFlowAssertResponse(loadFile("logout_response.xml"));
}
@@ -61,7 +61,7 @@ public class GmailClientTest {
private GmailClient getGmailClient(boolean isExternalEmailAllowed) throws Exception {
return new GmailClient(
gmail,
() -> gmail,
new Retrier(new SystemSleeper(), 3),
isExternalEmailAllowed,
"from@example.com",
@@ -125,6 +125,9 @@ public class GmailClientTest {
assertThat(mimeMessage.getRecipients(RecipientType.TO)).asList().containsExactly(toAddr);
assertThat(mimeMessage.getRecipients(RecipientType.CC)).asList().containsExactly(ccAddr);
assertThat(mimeMessage.getRecipients(RecipientType.BCC)).asList().containsExactly(bccAddr);
assertThat(mimeMessage.getReplyTo())
.asList()
.containsExactly(new InternetAddress("replyTo@example.com"));
assertThat(mimeMessage.getSubject()).isEqualTo("My subject");
assertThat(mimeMessage.getContent()).isInstanceOf(MimeMultipart.class);
MimeMultipart parts = (MimeMultipart) mimeMessage.getContent();
@@ -137,6 +140,23 @@ public class GmailClientTest {
assertThat(attachment.getContent()).isEqualTo("foo,bar\nbaz,qux");
}
@Test
public void toMimeMessage_overrideReplyToAddr() throws Exception {
InternetAddress fromAddr = new InternetAddress("from@example.com", "My sender");
InternetAddress toAddr = new InternetAddress("to@example.com");
InternetAddress replyToAddr = new InternetAddress("some-addr@another.com");
EmailMessage emailMessage =
EmailMessage.newBuilder()
.setFrom(fromAddr)
.setRecipients(ImmutableList.of(toAddr))
.setReplyToEmailAddress(replyToAddr)
.setSubject("My subject")
.setBody("My body")
.build();
MimeMessage mimeMessage = getGmailClient(true).toMimeMessage(emailMessage);
assertThat(mimeMessage.getReplyTo()).asList().containsExactly(replyToAddr);
}
@Test
public void toGmailMessage() throws Exception {
MimeMessage mimeMessage = mock(MimeMessage.class);
@@ -37,6 +37,7 @@ import com.google.common.collect.Sets;
import google.registry.model.billing.BillingBase.RenewalPriceBehavior;
import google.registry.model.contact.Contact;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DomainDsData;
@@ -136,6 +137,7 @@ public class DomainSqlTest {
.setAllowedTlds(ImmutableSet.of("dev", "app"))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setTokenStatusTransitions(
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
.put(START_OF_TIME, NOT_STARTED)
@@ -52,6 +52,7 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.contact.Contact;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DomainDsData;
@@ -833,6 +834,7 @@ public class DomainTest {
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain =
@@ -894,6 +896,7 @@ public class DomainTest {
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain =
@@ -1063,6 +1066,7 @@ public class DomainTest {
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build();
IllegalArgumentException thrown =
@@ -1080,6 +1084,7 @@ public class DomainTest {
.setToken("abc123")
.setTokenType(BULK_PRICING)
.setRenewalPriceBehavior(SPECIFIED)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.build());
domain = domain.asBuilder().setCurrentBulkToken(allocationToken.createVKey()).build();

Some files were not shown because too many files have changed in this diff Show More