Provide useful error messages on flows run during read-only mode (#1425)

We want to keep the read-only-mode-exception as an unchecked exception,
so we introduce a temporary check in the EppController that provides a
specific error message for this situation (rather than letting it fall
through to the generic "command failed" messaging
This commit is contained in:
gbrodman 2021-11-24 14:57:44 -05:00 committed by GitHub
parent 25d5d3d25e
commit 52ef8592fc
43 changed files with 319 additions and 15 deletions

View file

@ -143,9 +143,6 @@ public final class EppController {
/** Creates a response indicating an EPP failure. */ /** Creates a response indicating an EPP failure. */
@VisibleForTesting @VisibleForTesting
static EppOutput getErrorResponse(Result result, Trid trid) { static EppOutput getErrorResponse(Result result, Trid trid) {
return EppOutput.create(new EppResponse.Builder() return EppOutput.create(new EppResponse.Builder().setResult(result).setTrid(trid).build());
.setResult(result)
.setTrid(trid)
.build());
} }
} }

View file

@ -25,10 +25,12 @@ import google.registry.model.eppinput.EppInput.InnerCommand;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper; import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.eppoutput.Result; import google.registry.model.eppoutput.Result;
import google.registry.model.eppoutput.Result.Code; import google.registry.model.eppoutput.Result.Code;
import google.registry.persistence.transaction.TransactionManagerFactory.ReadOnlyModeException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Inherited; import java.lang.annotation.Inherited;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import javax.annotation.Nullable;
/** Exception used to propagate all failures containing one or more EPP responses. */ /** Exception used to propagate all failures containing one or more EPP responses. */
public abstract class EppException extends Exception { public abstract class EppException extends Exception {
@ -37,7 +39,12 @@ public abstract class EppException extends Exception {
/** Create an EppException with a custom message. */ /** Create an EppException with a custom message. */
private EppException(String message) { private EppException(String message) {
super(message); this(message, null);
}
/** Create an EppException with a custom message and cause. */
private EppException(String message, @Nullable Throwable cause) {
super(message, cause);
Code code = getClass().getAnnotation(EppResultCode.class).value(); Code code = getClass().getAnnotation(EppResultCode.class).value();
Preconditions.checkState(!code.isSuccess()); Preconditions.checkState(!code.isSuccess());
this.result = Result.create(code, message); this.result = Result.create(code, message);
@ -255,4 +262,12 @@ public abstract class EppException extends Exception {
super("Specified protocol version is not implemented"); super("Specified protocol version is not implemented");
} }
} }
/** Registry is currently undergoing maintenance and is in read-only mode. */
@EppResultCode(Code.COMMAND_FAILED)
public static class ReadOnlyModeEppException extends EppException {
ReadOnlyModeEppException(ReadOnlyModeException cause) {
super("Registry is currently undergoing maintenance and is in read-only mode", cause);
}
}
} }

View file

@ -19,6 +19,7 @@ import static google.registry.xml.XmlTransformer.prettyPrint;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger; import com.google.common.flogger.FluentLogger;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.FlowModule.DryRun; import google.registry.flows.FlowModule.DryRun;
import google.registry.flows.FlowModule.InputXml; import google.registry.flows.FlowModule.InputXml;
import google.registry.flows.FlowModule.RegistrarId; import google.registry.flows.FlowModule.RegistrarId;
@ -28,6 +29,7 @@ import google.registry.flows.session.LoginFlow;
import google.registry.model.eppcommon.Trid; import google.registry.model.eppcommon.Trid;
import google.registry.model.eppoutput.EppOutput; import google.registry.model.eppoutput.EppOutput;
import google.registry.monitoring.whitebox.EppMetric; import google.registry.monitoring.whitebox.EppMetric;
import google.registry.persistence.transaction.TransactionManagerFactory.ReadOnlyModeException;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider; import javax.inject.Provider;
@ -97,6 +99,8 @@ public class FlowRunner {
return e.output; return e.output;
} catch (EppRuntimeException e) { } catch (EppRuntimeException e) {
throw e.getCause(); throw e.getCause();
} catch (ReadOnlyModeException e) {
throw new ReadOnlyModeEppException(e);
} }
} }

View file

@ -50,6 +50,7 @@ import org.joda.time.DateTime;
/** /**
* An EPP flow that creates a new contact. * An EPP flow that creates a new contact.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link ResourceAlreadyExistsForThisClientException} * @error {@link ResourceAlreadyExistsForThisClientException}
* @error {@link ResourceCreateContentionException} * @error {@link ResourceCreateContentionException}
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException} * @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}

View file

@ -60,6 +60,7 @@ import org.joda.time.DateTime;
* references to the host before the deletion is allowed to proceed. A poll message will be written * references to the host before the deletion is allowed to proceed. A poll message will be written
* with the success or failure message when the process is complete. * with the success or failure message when the process is complete.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException} * @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}

View file

@ -54,6 +54,7 @@ import org.joda.time.DateTime;
* transfer is automatically approved. Within that window, this flow allows the losing client to * transfer is automatically approved. Within that window, this flow allows the losing client to
* explicitly approve the transfer request, which then becomes effective immediately. * explicitly approve the transfer request, which then becomes effective immediately.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}

View file

@ -54,6 +54,7 @@ import org.joda.time.DateTime;
* transfer is automatically approved. Within that window, this flow allows the gaining client to * transfer is automatically approved. Within that window, this flow allows the gaining client to
* withdraw the transfer request. * withdraw the transfer request.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.exceptions.NotPendingTransferException} * @error {@link google.registry.flows.exceptions.NotPendingTransferException}

View file

@ -53,6 +53,7 @@ import org.joda.time.DateTime;
* transfer is automatically approved. Within that window, this flow allows the losing client to * transfer is automatically approved. Within that window, this flow allows the losing client to
* reject the transfer request. * reject the transfer request.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -63,6 +63,7 @@ import org.joda.time.Duration;
* by the losing registrar or rejected, and the gaining registrar can also cancel the transfer * by the losing registrar or rejected, and the gaining registrar can also cancel the transfer
* request. * request.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.exceptions.AlreadyPendingTransferException} * @error {@link google.registry.flows.exceptions.AlreadyPendingTransferException}

View file

@ -55,6 +55,7 @@ import org.joda.time.DateTime;
/** /**
* An EPP flow that updates a contact. * An EPP flow that updates a contact.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException} * @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -133,6 +133,7 @@ import org.joda.time.Duration;
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException} * google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
* @error {@link * @error {@link
* google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException} * google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException}
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException} * @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
* @error {@link ResourceAlreadyExistsForThisClientException} * @error {@link ResourceAlreadyExistsForThisClientException}
* @error {@link ResourceCreateContentionException} * @error {@link ResourceCreateContentionException}

View file

@ -103,6 +103,7 @@ import org.joda.time.Duration;
/** /**
* An EPP flow that deletes a domain. * An EPP flow that deletes a domain.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException} * @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -94,6 +94,7 @@ import org.joda.time.Duration;
* longer than 10 years unless it comes in at the exact millisecond that the domain would have * longer than 10 years unless it comes in at the exact millisecond that the domain would have
* expired. * expired.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException} * @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -93,6 +93,7 @@ import org.joda.time.DateTime;
* restored to a single year expiration starting at the restore time, regardless of what the * restored to a single year expiration starting at the restore time, regardless of what the
* original expiration time was. * original expiration time was.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException} * @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException} * @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}

View file

@ -78,6 +78,7 @@ import org.joda.time.DateTime;
* timestamps such that they only would become active when the transfer period passed. In this flow, * timestamps such that they only would become active when the transfer period passed. In this flow,
* those speculative objects are deleted and replaced with new ones with the correct approval time. * those speculative objects are deleted and replaced with new ones with the correct approval time.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -65,6 +65,7 @@ import org.joda.time.DateTime;
* timestamps such that they only would become active when the transfer period passed. In this flow, * timestamps such that they only would become active when the transfer period passed. In this flow,
* those speculative objects are deleted. * those speculative objects are deleted.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.exceptions.NotPendingTransferException} * @error {@link google.registry.flows.exceptions.NotPendingTransferException}

View file

@ -67,6 +67,7 @@ import org.joda.time.DateTime;
* timestamps such that they only would become active when the transfer period passed. In this flow, * timestamps such that they only would become active when the transfer period passed. In this flow,
* those speculative objects are deleted. * those speculative objects are deleted.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -93,6 +93,7 @@ import org.joda.time.DateTime;
* rejection or cancellation of the request, they will be deleted (and in the approval case, * rejection or cancellation of the request, they will be deleted (and in the approval case,
* replaced with new ones with the correct approval time). * replaced with new ones with the correct approval time).
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException} * @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException} * @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
@ -102,7 +103,8 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException} * @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.TransferPeriodMustBeOneYearException} * @error {@link google.registry.flows.exceptions.TransferPeriodMustBeOneYearException}
* @error {@link InvalidTransferPeriodValueException} * @error {@link InvalidTransferPeriodValueException}
* @error {@link google.registry.flows.exceptions.TransferPeriodZeroAndFeeTransferExtensionException} * @error {@link
* google.registry.flows.exceptions.TransferPeriodZeroAndFeeTransferExtensionException}
* @error {@link DomainFlowUtils.BadPeriodUnitException} * @error {@link DomainFlowUtils.BadPeriodUnitException}
* @error {@link DomainFlowUtils.CurrencyUnitMismatchException} * @error {@link DomainFlowUtils.CurrencyUnitMismatchException}
* @error {@link DomainFlowUtils.CurrencyValueScaleException} * @error {@link DomainFlowUtils.CurrencyValueScaleException}

View file

@ -97,6 +97,7 @@ import org.joda.time.DateTime;
* superuser. As such, adding or removing these statuses incurs a billing event. There will be only * superuser. As such, adding or removing these statuses incurs a billing event. There will be only
* one charge per update, even if several such statuses are updated at once. * one charge per update, even if several such statuses are updated at once.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException} * @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException} * @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}

View file

@ -65,6 +65,7 @@ import org.joda.time.DateTime;
* hosts cannot have any. This flow allows creating a host name, and if necessary enqueues tasks to * hosts cannot have any. This flow allows creating a host name, and if necessary enqueues tasks to
* update DNS. * update DNS.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.FlowUtils.IpAddressVersionMismatchException} * @error {@link google.registry.flows.FlowUtils.IpAddressVersionMismatchException}
* @error {@link ResourceAlreadyExistsForThisClientException} * @error {@link ResourceAlreadyExistsForThisClientException}
* @error {@link ResourceCreateContentionException} * @error {@link ResourceCreateContentionException}

View file

@ -58,6 +58,7 @@ import org.joda.time.DateTime;
* references to the host before the deletion is allowed to proceed. A poll message will be written * references to the host before the deletion is allowed to proceed. A poll message will be written
* with the success or failure message when the process is complete. * with the success or failure message when the process is complete.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException} * @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}

View file

@ -73,11 +73,12 @@ import org.joda.time.DateTime;
* hosts. Internal hosts must have at least one IP address associated with them, whereas external * hosts. Internal hosts must have at least one IP address associated with them, whereas external
* hosts cannot have any. * hosts cannot have any.
* *
* <p>This flow allows changing a host name, and adding or removing IP addresses to hosts. When * <p>This flow allows changing a host name, and adding or removing IP addresses to hosts. When a
* a host is renamed from internal to external all IP addresses must be simultaneously removed, and * host is renamed from internal to external all IP addresses must be simultaneously removed, and
* when it is renamed from external to internal at least one must be added. If the host is renamed * when it is renamed from external to internal at least one must be added. If the host is renamed
* or IP addresses are added, tasks are enqueued to update DNS accordingly. * or IP addresses are added, tasks are enqueued to update DNS accordingly.
* *
* @error {@link google.registry.flows.EppException.ReadOnlyModeEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException} * @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException} * @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}

View file

@ -157,7 +157,7 @@ public class TransactionManagerFactory {
/** Registry is currently undergoing maintenance and is in read-only mode. */ /** Registry is currently undergoing maintenance and is in read-only mode. */
public static class ReadOnlyModeException extends IllegalStateException { public static class ReadOnlyModeException extends IllegalStateException {
ReadOnlyModeException() { public ReadOnlyModeException() {
super("Registry is currently undergoing maintenance and is in read-only mode"); super("Registry is currently undergoing maintenance and is in read-only mode");
} }
} }

View file

@ -26,15 +26,18 @@ import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptio
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.contact.ContactFlowUtils.BadInternationalizedPostalInfoException; import google.registry.flows.contact.ContactFlowUtils.BadInternationalizedPostalInfoException;
import google.registry.flows.contact.ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException; import google.registry.flows.contact.ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException;
import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException; import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException;
import google.registry.flows.exceptions.ResourceCreateContentionException; import google.registry.flows.exceptions.ResourceCreateContentionException;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -137,4 +140,12 @@ class ContactCreateFlowTest extends ResourceFlowTestCase<ContactCreateFlow, Cont
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-create"); assertIcannReportingActivityFieldLogged("srs-cont-create");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -35,6 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
@ -51,9 +52,11 @@ import google.registry.model.tld.Registry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import google.registry.testing.TestSqlOnly; import google.registry.testing.TestSqlOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -243,6 +246,15 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
assertIcannReportingActivityFieldLogged("srs-cont-delete"); assertIcannReportingActivityFieldLogged("srs-cont-delete");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
persistActiveContact(getUniqueIdFromCommand());
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
private void assertOfyDeleteSuccess(String registrarId, String clientTrid, boolean isSuperuser) private void assertOfyDeleteSuccess(String registrarId, String clientTrid, boolean isSuperuser)
throws Exception { throws Exception {
ContactResource deletedContact = reloadResourceByForeignKey(); ContactResource deletedContact = reloadResourceByForeignKey();

View file

@ -26,6 +26,7 @@ import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptio
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
@ -40,9 +41,11 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -265,4 +268,12 @@ class ContactTransferApproveFlowTest
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-transfer-approve"); assertIcannReportingActivityFieldLogged("srs-cont-transfer-approve");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -25,6 +25,7 @@ import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptio
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.exceptions.NotPendingTransferException; import google.registry.flows.exceptions.NotPendingTransferException;
@ -37,9 +38,11 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -251,4 +254,12 @@ class ContactTransferCancelFlowTest
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-transfer-cancel"); assertIcannReportingActivityFieldLogged("srs-cont-transfer-cancel");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -25,6 +25,7 @@ import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptio
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
@ -39,9 +40,11 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -264,4 +267,12 @@ class ContactTransferRejectFlowTest
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-transfer-reject"); assertIcannReportingActivityFieldLogged("srs-cont-transfer-reject");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -35,6 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.exceptions.AlreadyPendingTransferException; import google.registry.flows.exceptions.AlreadyPendingTransferException;
@ -50,9 +51,11 @@ import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.ContactTransferData; import google.registry.model.transfer.ContactTransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
@ -313,4 +316,12 @@ class ContactTransferRequestFlowTest
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-transfer-request"); assertIcannReportingActivityFieldLogged("srs-cont-transfer-request");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException; import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
@ -41,9 +42,11 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.contact.PostalInfo; import google.registry.model.contact.PostalInfo;
import google.registry.model.contact.PostalInfo.Type; import google.registry.model.contact.PostalInfo.Type;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -426,4 +429,13 @@ class ContactUpdateFlowTest extends ResourceFlowTestCase<ContactUpdateFlow, Cont
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-update"); assertIcannReportingActivityFieldLogged("srs-cont-update");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
persistActiveContact(getUniqueIdFromCommand());
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -72,6 +72,7 @@ import com.google.common.collect.Ordering;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig; import google.registry.config.RegistryConfig;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.ExtensionManager.UndeclaredServiceExtensionException; import google.registry.flows.ExtensionManager.UndeclaredServiceExtensionException;
@ -164,10 +165,12 @@ import google.registry.model.tld.Registry.TldState;
import google.registry.model.tld.Registry.TldType; import google.registry.model.tld.Registry.TldType;
import google.registry.monitoring.whitebox.EppMetric; import google.registry.monitoring.whitebox.EppMetric;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher; import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -2517,4 +2520,13 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
EppMetric eppMetric = getEppMetric(); EppMetric eppMetric = getEppMetric();
assertThat(eppMetric.getCommandName()).hasValue("DomainCreate"); assertThat(eppMetric.getCommandName()).hasValue("DomainCreate");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
persistContactsAndHosts();
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -68,6 +68,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import google.registry.batch.ResaveEntityAction; import google.registry.batch.ResaveEntityAction;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
@ -100,10 +101,12 @@ import google.registry.model.tld.Registry.TldType;
import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher; import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.util.Map; import java.util.Map;
import org.joda.money.Money; import org.joda.money.Money;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -1248,4 +1251,13 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
EppException thrown = assertThrows(UnimplementedExtensionException.class, this::runFlow); EppException thrown = assertThrows(UnimplementedExtensionException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
setUpSuccessfulTest();
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.FlowUtils.UnknownCurrencyEppException; import google.registry.flows.FlowUtils.UnknownCurrencyEppException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
@ -73,10 +74,12 @@ import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField; import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.tld.Registry; import google.registry.model.tld.Registry;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.SetClockExtension; import google.registry.testing.SetClockExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.util.Map; import java.util.Map;
import org.joda.money.Money; import org.joda.money.Money;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -870,4 +873,20 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
TransactionReportField.netRenewsFieldFromYears(5), TransactionReportField.netRenewsFieldFromYears(5),
1)); 1));
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
persistDomain();
DomainBase domain = reloadResourceByForeignKey();
persistResource(
domain
.asBuilder()
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime().minusYears(1))
.build());
clock.setTo(clock.nowUtc().minusSeconds(2));
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -41,6 +41,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.FlowUtils.UnknownCurrencyEppException; import google.registry.flows.FlowUtils.UnknownCurrencyEppException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
@ -72,9 +73,11 @@ import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField; import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.tld.Registry; import google.registry.model.tld.Registry;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.joda.money.Money; import org.joda.money.Money;
@ -771,4 +774,13 @@ class DomainRestoreRequestFlowTest
assertThat(thrown).hasMessageThat().contains("domain restore reports are not supported"); assertThat(thrown).hasMessageThat().contains("domain restore reports are not supported");
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
persistPendingDeleteDomain();
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -43,6 +43,7 @@ import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
@ -72,9 +73,11 @@ import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.joda.money.Money; import org.joda.money.Money;
@ -94,7 +97,7 @@ class DomainTransferApproveFlowTest
final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock); final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock);
@BeforeEach @BeforeEach
void setUp() { void beforeEach() {
setEppInput("domain_transfer_approve.xml"); setEppInput("domain_transfer_approve.xml");
// Change the registry so that the renew price changes a day minus 1 millisecond before the // Change the registry so that the renew price changes a day minus 1 millisecond before the
// transfer (right after there will be an autorenew in the test case that has one) and then // transfer (right after there will be an autorenew in the test case that has one) and then
@ -674,4 +677,12 @@ class DomainTransferApproveFlowTest
domain.getRegistrationExpirationTime()); domain.getRegistrationExpirationTime());
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods(); assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -37,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
@ -55,9 +56,11 @@ import google.registry.model.tld.Registry;
import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -74,7 +77,7 @@ class DomainTransferCancelFlowTest
final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock); final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock);
@BeforeEach @BeforeEach
void setUp() { void beforeEach() {
setEppInput("domain_transfer_cancel.xml"); setEppInput("domain_transfer_cancel.xml");
setRegistrarIdForFlow("NewRegistrar"); setRegistrarIdForFlow("NewRegistrar");
setupDomainWithPendingTransfer("example", "tld"); setupDomainWithPendingTransfer("example", "tld");
@ -416,4 +419,12 @@ class DomainTransferCancelFlowTest
assertThat(persistedEntry.getDomainTransactionRecords()) assertThat(persistedEntry.getDomainTransactionRecords())
.containsExactly(previousSuccessRecord.asBuilder().setReportAmount(-1).build()); .containsExactly(previousSuccessRecord.asBuilder().setReportAmount(-1).build());
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -37,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
@ -57,9 +58,11 @@ import google.registry.model.tld.Registry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -76,7 +79,7 @@ class DomainTransferRejectFlowTest
final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock); final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock);
@BeforeEach @BeforeEach
void setUp() { void beforeEach() {
setEppInput("domain_transfer_reject.xml"); setEppInput("domain_transfer_reject.xml");
setRegistrarIdForFlow("TheRegistrar"); setRegistrarIdForFlow("TheRegistrar");
setupDomainWithPendingTransfer("example", "tld"); setupDomainWithPendingTransfer("example", "tld");
@ -384,4 +387,12 @@ class DomainTransferRejectFlowTest
previousSuccessRecord.asBuilder().setReportAmount(-1).build(), previousSuccessRecord.asBuilder().setReportAmount(-1).build(),
DomainTransactionRecord.create("tld", clock.nowUtc(), TRANSFER_NACKED, 1)); DomainTransactionRecord.create("tld", clock.nowUtc(), TRANSFER_NACKED, 1));
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -60,6 +60,7 @@ import com.google.common.collect.Sets;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import google.registry.batch.ResaveEntityAction; import google.registry.batch.ResaveEntityAction;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.FlowUtils.UnknownCurrencyEppException; import google.registry.flows.FlowUtils.UnknownCurrencyEppException;
import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
@ -104,10 +105,12 @@ import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher; import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -163,7 +166,7 @@ class DomainTransferRequestFlowTest
.build(); .build();
@BeforeEach @BeforeEach
void setUp() { void beforeEach() {
setEppInput("domain_transfer_request.xml"); setEppInput("domain_transfer_request.xml");
setRegistrarIdForFlow("NewRegistrar"); setRegistrarIdForFlow("NewRegistrar");
} }
@ -1540,4 +1543,15 @@ class DomainTransferRequestFlowTest
DomainTransactionRecord.create( DomainTransactionRecord.create(
"tld", clock.nowUtc().plusDays(5), TRANSFER_SUCCESSFUL, 1)); "tld", clock.nowUtc().plusDays(5), TRANSFER_SUCCESSFUL, 1));
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
setupDomain("example", "tld");
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown =
assertThrows(
ReadOnlyModeEppException.class, () -> doFailingTest("domain_transfer_request.xml"));
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -59,6 +59,7 @@ import com.google.common.collect.ImmutableSortedMap;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig; import google.registry.config.RegistryConfig;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
@ -101,9 +102,11 @@ import google.registry.model.host.HostResource;
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.model.tld.Registry; import google.registry.model.tld.Registry;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import java.util.Optional; import java.util.Optional;
import org.joda.money.Money; import org.joda.money.Money;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -133,7 +136,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock); final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock);
@BeforeEach @BeforeEach
void initDomainTest() { void beforeEach() {
createTld("tld"); createTld("tld");
// Note that "domain_update.xml" tests adding and removing the same contact type. // Note that "domain_update.xml" tests adding and removing the same contact type.
setEppInput("domain_update.xml"); setEppInput("domain_update.xml");
@ -1495,4 +1498,14 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
runFlowAsSuperuser(); runFlowAsSuperuser();
assertAboutDomains().that(reloadResourceByForeignKey()).hasNoAutorenewEndTime(); assertAboutDomains().that(reloadResourceByForeignKey()).hasNoAutorenewEndTime();
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
persistReferencedEntities();
persistDomain();
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -36,6 +36,7 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.FlowUtils.IpAddressVersionMismatchException; import google.registry.flows.FlowUtils.IpAddressVersionMismatchException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException; import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException;
@ -54,9 +55,11 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -329,4 +332,12 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, HostResour
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-host-create"); assertIcannReportingActivityFieldLogged("srs-host-create");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -35,6 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
@ -51,9 +52,11 @@ import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.model.tld.Registry; import google.registry.model.tld.Registry;
import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
@ -338,6 +341,15 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
assertIcannReportingActivityFieldLogged("srs-host-delete"); assertIcannReportingActivityFieldLogged("srs-host-delete");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() {
persistActiveHost("ns1.example.tld");
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
private void assertOfyDeleteSuccess(String registrarId, String clientTrid, boolean isSuperuser) private void assertOfyDeleteSuccess(String registrarId, String clientTrid, boolean isSuperuser)
throws Exception { throws Exception {
HostResource deletedHost = reloadResourceByForeignKey(); HostResource deletedHost = reloadResourceByForeignKey();

View file

@ -47,6 +47,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ReadOnlyModeEppException;
import google.registry.flows.EppRequestSource; import google.registry.flows.EppRequestSource;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException; import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
@ -77,10 +78,12 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.tld.Registry; import google.registry.model.tld.Registry;
import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher; import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
@ -1341,4 +1344,14 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResour
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-host-update"); assertIcannReportingActivityFieldLogged("srs-host-update");
} }
@TestOfyOnly
void testModification_duringReadOnlyPhase() throws Exception {
createTld("tld");
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
DatabaseHelper.setMigrationScheduleToDatastorePrimaryReadOnly(clock);
EppException thrown = assertThrows(ReadOnlyModeEppException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
DatabaseHelper.removeDatabaseMigrationSchedule();
}
} }

View file

@ -27,6 +27,8 @@ An EPP flow that creates a new contact.
* Resource with this id already exists. * Resource with this id already exists.
* 2306 * 2306
* Declining contact disclosure is disallowed by server policy. * Declining contact disclosure is disallowed by server policy.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## ContactDeleteFlow ## ContactDeleteFlow
@ -51,6 +53,8 @@ or failure message when the process is complete.
* Resource status prohibits this operation. * Resource status prohibits this operation.
* 2305 * 2305
* Resource to be deleted has active incoming references. * Resource to be deleted has active incoming references.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## ContactInfoFlow ## ContactInfoFlow
@ -93,6 +97,8 @@ transfer request, which then becomes effective immediately.
* The resource does not have a pending transfer. * The resource does not have a pending transfer.
* 2303 * 2303
* Resource with this id does not exist. * Resource with this id does not exist.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## ContactTransferCancelFlow ## ContactTransferCancelFlow
@ -116,6 +122,8 @@ request.
* The resource does not have a pending transfer. * The resource does not have a pending transfer.
* 2303 * 2303
* Resource with this id does not exist. * Resource with this id does not exist.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## ContactTransferQueryFlow ## ContactTransferQueryFlow
@ -163,6 +171,8 @@ that window, this flow allows the losing client to reject the transfer request.
* The resource does not have a pending transfer. * The resource does not have a pending transfer.
* 2303 * 2303
* Resource with this id does not exist. * Resource with this id does not exist.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## ContactTransferRequestFlow ## ContactTransferRequestFlow
@ -190,6 +200,8 @@ or rejected, and the gaining registrar can also cancel the transfer request.
* Resource with this id does not exist. * Resource with this id does not exist.
* 2304 * 2304
* Resource status prohibits this operation. * Resource status prohibits this operation.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## ContactUpdateFlow ## ContactUpdateFlow
@ -214,6 +226,8 @@ An EPP flow that updates a contact.
* 2306 * 2306
* Cannot add and remove the same value. * Cannot add and remove the same value.
* Declining contact disclosure is disallowed by server policy. * Declining contact disclosure is disallowed by server policy.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainCheckFlow ## DomainCheckFlow
@ -371,6 +385,8 @@ An EPP flow that creates a new domain resource.
* Too many nameservers set on this domain. * Too many nameservers set on this domain.
* Domain labels cannot end with a dash. * Domain labels cannot end with a dash.
* Only encoded signed marks are supported. * Only encoded signed marks are supported.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainDeleteFlow ## DomainDeleteFlow
@ -394,6 +410,8 @@ An EPP flow that deletes a domain.
* Resource status prohibits this operation. * Resource status prohibits this operation.
* 2305 * 2305
* Domain to be deleted has subordinate hosts. * Domain to be deleted has subordinate hosts.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainInfoFlow ## DomainInfoFlow
@ -465,6 +483,8 @@ comes in at the exact millisecond that the domain would have expired.
* 2306 * 2306
* Periods for domain registrations must be specified in years. * Periods for domain registrations must be specified in years.
* The requested fees cannot be provided in the requested currency. * The requested fees cannot be provided in the requested currency.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainRestoreRequestFlow ## DomainRestoreRequestFlow
@ -524,6 +544,8 @@ regardless of what the original expiration time was.
* Domain is not eligible for restore. * Domain is not eligible for restore.
* 2306 * 2306
* The requested fees cannot be provided in the requested currency. * The requested fees cannot be provided in the requested currency.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainTransferApproveFlow ## DomainTransferApproveFlow
@ -553,6 +575,8 @@ replaced with new ones with the correct approval time.
* The resource does not have a pending transfer. * The resource does not have a pending transfer.
* 2303 * 2303
* Resource with this id does not exist. * Resource with this id does not exist.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainTransferCancelFlow ## DomainTransferCancelFlow
@ -581,6 +605,8 @@ transfer period passed. In this flow, those speculative objects are deleted.
* The resource does not have a pending transfer. * The resource does not have a pending transfer.
* 2303 * 2303
* Resource with this id does not exist. * Resource with this id does not exist.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainTransferQueryFlow ## DomainTransferQueryFlow
@ -633,6 +659,8 @@ transfer period passed. In this flow, those speculative objects are deleted.
* The resource does not have a pending transfer. * The resource does not have a pending transfer.
* 2303 * 2303
* Resource with this id does not exist. * Resource with this id does not exist.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainTransferRequestFlow ## DomainTransferRequestFlow
@ -692,6 +720,8 @@ new ones with the correct approval time).
EPP extension. EPP extension.
* Periods for domain registrations must be specified in years. * Periods for domain registrations must be specified in years.
* The requested fees cannot be provided in the requested currency. * The requested fees cannot be provided in the requested currency.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## DomainUpdateFlow ## DomainUpdateFlow
@ -747,6 +777,8 @@ statuses are updated at once.
* The secDNS:all element must have value 'true' if present. * The secDNS:all element must have value 'true' if present.
* Too many DS records set on a domain. * Too many DS records set on a domain.
* Too many nameservers set on this domain. * Too many nameservers set on this domain.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## HelloFlow ## HelloFlow
@ -805,6 +837,8 @@ allows creating a host name, and if necessary enqueues tasks to update DNS.
* Superordinate domain for this hostname is in pending delete. * Superordinate domain for this hostname is in pending delete.
* 2306 * 2306
* Host names must be at least two levels below the registry suffix. * Host names must be at least two levels below the registry suffix.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## HostDeleteFlow ## HostDeleteFlow
@ -833,6 +867,8 @@ or failure message when the process is complete.
* Resource status prohibits this operation. * Resource status prohibits this operation.
* 2305 * 2305
* Resource to be deleted has active incoming references. * Resource to be deleted has active incoming references.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## HostInfoFlow ## HostInfoFlow
@ -901,6 +937,8 @@ are enqueued to update DNS accordingly.
* 2306 * 2306
* Cannot add and remove the same value. * Cannot add and remove the same value.
* Host names must be at least two levels below the registry suffix. * Host names must be at least two levels below the registry suffix.
* 2400
* Registry is currently undergoing maintenance and is in read-only mode.
## LoginFlow ## LoginFlow