diff --git a/java/google/registry/flows/EppController.java b/java/google/registry/flows/EppController.java index 5a308adba..d9c4d981e 100644 --- a/java/google/registry/flows/EppController.java +++ b/java/google/registry/flows/EppController.java @@ -15,12 +15,11 @@ package google.registry.flows; import static google.registry.flows.EppXmlTransformer.unmarshal; -import static google.registry.flows.picker.FlowPicker.getFlowClass; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; +import google.registry.flows.FlowModule.EppExceptionInProviderException; import google.registry.model.eppcommon.Trid; import google.registry.model.eppinput.EppInput; import google.registry.model.eppoutput.EppOutput; @@ -43,6 +42,7 @@ public final class EppController { private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); @Inject Clock clock; + @Inject FlowComponent.Builder flowComponentBuilder; @Inject EppMetrics metrics; @Inject EppController() {} @@ -54,57 +54,62 @@ public final class EppController { boolean isDryRun, boolean isSuperuser, byte[] inputXmlBytes) { - Trid trid = null; + metrics.setClientId(sessionMetadata.getClientId()); + metrics.setPrivilegeLevel(isSuperuser ? "SUPERUSER" : "NORMAL"); try { - EppInput eppInput = unmarshal(EppInput.class, inputXmlBytes); - trid = Trid.create(eppInput.getCommandWrapper().getClTrid()); - ImmutableList targetIds = eppInput.getTargetIds(); + EppInput eppInput; + try { + eppInput = unmarshal(EppInput.class, inputXmlBytes); + } catch (EppException e) { + // Send the client an error message, with no clTRID since we couldn't unmarshal it. + metrics.setEppStatus(e.getResult().getCode()); + return getErrorResponse(clock, e.getResult(), Trid.create(null)); + } metrics.setCommandName(eppInput.getCommandName()); - metrics.setClientId(sessionMetadata.getClientId()); - metrics.setPrivilegeLevel(isSuperuser ? "SUPERUSER" : "NORMAL"); - if (!targetIds.isEmpty()) { - metrics.setEppTarget(Joiner.on(",").join(targetIds)); + if (!eppInput.getTargetIds().isEmpty()) { + metrics.setEppTarget(Joiner.on(',').join(eppInput.getTargetIds())); } - FlowRunner flowRunner = new FlowRunner( - getFlowClass(eppInput), - eppInput, - trid, - sessionMetadata, - credentials, - eppRequestSource, - isDryRun, - isSuperuser, - inputXmlBytes, - metrics, - clock); - EppOutput eppOutput = flowRunner.run(); - if (eppOutput.isResponse()) { - metrics.setEppStatus(eppOutput.getResponse().getResult().getCode()); + EppOutput output = runFlowConvertEppErrors(flowComponentBuilder + .flowModule(new FlowModule.Builder() + .setSessionMetadata(sessionMetadata) + .setCredentials(credentials) + .setEppRequestSource(eppRequestSource) + .setIsDryRun(isDryRun) + .setIsSuperuser(isSuperuser) + .setInputXmlBytes(inputXmlBytes) + .setEppInput(eppInput) + .build()) + .build()); + if (output.isResponse()) { + metrics.setEppStatus(output.getResponse().getResult().getCode()); } - return eppOutput; - } catch (EppException e) { - // The command failed. Send the client an error message. - metrics.setEppStatus(e.getResult().getCode()); - return getErrorResponse(clock, e.getResult(), trid); - } catch (Throwable e) { - // Something bad and unexpected happened. Send the client a generic error, and log it. - logger.severe(e, "Unexpected failure"); - metrics.setEppStatus(Code.CommandFailed); - return getErrorResponse(clock, Result.create(Code.CommandFailed), trid); + return output; } finally { metrics.export(); } } - /** Create a response indicating an Epp failure. */ + /** Run an EPP flow and convert known exceptions into EPP error responses. */ + private EppOutput runFlowConvertEppErrors(FlowComponent flowComponent) { + try { + return flowComponent.flowRunner().run(); + } catch (EppException | EppExceptionInProviderException e) { + // The command failed. Send the client an error message. + EppException eppEx = (EppException) (e instanceof EppException ? e : e.getCause()); + return getErrorResponse(clock, eppEx.getResult(), flowComponent.trid()); + } catch (Throwable e) { + // Something bad and unexpected happened. Send the client a generic error, and log it. + logger.severe(e, "Unexpected failure"); + return getErrorResponse(clock, Result.create(Code.CommandFailed), flowComponent.trid()); + } + } + + /** Create a response indicating an EPP failure. */ @VisibleForTesting static EppOutput getErrorResponse(Clock clock, Result result, Trid trid) { - // Create TRID (without a clTRID) if one hasn't been created yet, as it's necessary to construct - // a valid response. This can happen if the error occurred before we could even parse out the - // clTRID (e.g. if a syntax error occurred parsing the supplied XML). return EppOutput.create(new EppResponse.Builder() - .setTrid(trid == null ? Trid.create(null) : trid) .setResult(result) + .setTrid(trid) .setExecutionTime(clock.nowUtc()) .build()); } diff --git a/java/google/registry/flows/FlowComponent.java b/java/google/registry/flows/FlowComponent.java new file mode 100644 index 000000000..0f1545f32 --- /dev/null +++ b/java/google/registry/flows/FlowComponent.java @@ -0,0 +1,35 @@ +// Copyright 2016 The Domain Registry 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; + +import dagger.Subcomponent; + +import google.registry.model.eppcommon.Trid; + +/** Dagger component for flow classes. */ +@FlowScope +@Subcomponent(modules = FlowModule.class) +public interface FlowComponent { + + Trid trid(); + FlowRunner flowRunner(); + + /** Dagger-implemented builder for this subcomponent. */ + @Subcomponent.Builder + interface Builder { + Builder flowModule(FlowModule flowModule); + FlowComponent build(); + } +} diff --git a/java/google/registry/flows/FlowModule.java b/java/google/registry/flows/FlowModule.java new file mode 100644 index 000000000..fdc6fa7b0 --- /dev/null +++ b/java/google/registry/flows/FlowModule.java @@ -0,0 +1,335 @@ +// Copyright 2016 The Domain Registry 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; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.collect.ImmutableMap; + +import dagger.Module; +import dagger.Provides; + +import google.registry.flows.contact.ContactCheckFlow; +import google.registry.flows.contact.ContactCreateFlow; +import google.registry.flows.contact.ContactDeleteFlow; +import google.registry.flows.contact.ContactInfoFlow; +import google.registry.flows.contact.ContactTransferApproveFlow; +import google.registry.flows.contact.ContactTransferCancelFlow; +import google.registry.flows.contact.ContactTransferQueryFlow; +import google.registry.flows.contact.ContactTransferRejectFlow; +import google.registry.flows.contact.ContactTransferRequestFlow; +import google.registry.flows.contact.ContactUpdateFlow; +import google.registry.flows.domain.ClaimsCheckFlow; +import google.registry.flows.domain.DomainAllocateFlow; +import google.registry.flows.domain.DomainApplicationCreateFlow; +import google.registry.flows.domain.DomainApplicationDeleteFlow; +import google.registry.flows.domain.DomainApplicationInfoFlow; +import google.registry.flows.domain.DomainApplicationUpdateFlow; +import google.registry.flows.domain.DomainCheckFlow; +import google.registry.flows.domain.DomainCreateFlow; +import google.registry.flows.domain.DomainDeleteFlow; +import google.registry.flows.domain.DomainInfoFlow; +import google.registry.flows.domain.DomainRenewFlow; +import google.registry.flows.domain.DomainRestoreRequestFlow; +import google.registry.flows.domain.DomainTransferApproveFlow; +import google.registry.flows.domain.DomainTransferCancelFlow; +import google.registry.flows.domain.DomainTransferQueryFlow; +import google.registry.flows.domain.DomainTransferRejectFlow; +import google.registry.flows.domain.DomainTransferRequestFlow; +import google.registry.flows.domain.DomainUpdateFlow; +import google.registry.flows.host.HostCheckFlow; +import google.registry.flows.host.HostCreateFlow; +import google.registry.flows.host.HostDeleteFlow; +import google.registry.flows.host.HostInfoFlow; +import google.registry.flows.host.HostUpdateFlow; +import google.registry.flows.picker.FlowPicker; +import google.registry.flows.poll.PollAckFlow; +import google.registry.flows.poll.PollRequestFlow; +import google.registry.flows.session.HelloFlow; +import google.registry.flows.session.LoginFlow; +import google.registry.flows.session.LogoutFlow; +import google.registry.model.eppcommon.Trid; +import google.registry.model.eppinput.EppInput; + +import java.lang.annotation.Documented; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.inject.Provider; +import javax.inject.Qualifier; + +/** Module to choose and instantiate an EPP flow. */ +@Module +public class FlowModule { + + private EppInput eppInput; + private byte[] inputXmlBytes; + private SessionMetadata sessionMetadata; + private TransportCredentials credentials; + private boolean isDryRun; + private EppRequestSource eppRequestSource; + private boolean isSuperuser; + + private FlowModule() {} + + /** Builder for {@link FlowModule}. */ + static class Builder { + FlowModule module = new FlowModule(); + + Builder setEppInput(EppInput eppInput) { + module.eppInput = eppInput; + return this; + } + + Builder setInputXmlBytes(byte[] inputXmlBytes) { + module.inputXmlBytes = inputXmlBytes; + return this; + } + + Builder setSessionMetadata(SessionMetadata sessionMetadata) { + module.sessionMetadata = sessionMetadata; + return this; + } + + Builder setIsDryRun(boolean isDryRun) { + module.isDryRun = isDryRun; + return this; + } + + Builder setIsSuperuser(boolean isSuperuser) { + module.isSuperuser = isSuperuser; + return this; + } + + Builder setEppRequestSource(EppRequestSource eppRequestSource) { + module.eppRequestSource = eppRequestSource; + return this; + } + + Builder setCredentials(TransportCredentials credentials) { + module.credentials = credentials; + return this; + } + + FlowModule build() { + try { + checkState(module != null, "Already built"); + return module; + } finally { + module = null; + } + } + } + + @Provides + @FlowScope + @InputXml + byte[] provideInputXml() { + return inputXmlBytes; + } + + @Provides + @FlowScope + EppInput provideEppInput() { + return eppInput; + } + + @Provides + @FlowScope + SessionMetadata provideSessionMetadata() { + return sessionMetadata; + } + + @Provides + @FlowScope + @DryRun + boolean provideIsDryRun() { + return isDryRun; + } + + @Provides + @FlowScope + @Transactional + boolean provideIsTransactional(Class flowClass) { + return TransactionalFlow.class.isAssignableFrom(flowClass); + } + + @Provides + @FlowScope + @Superuser + boolean provideIsSuperuser() { + return isSuperuser; + } + + @Provides + @FlowScope + EppRequestSource provideEppRequestSource() { + return eppRequestSource; + } + + @Provides + @FlowScope + TransportCredentials provideTransportCredentials() { + return credentials; + } + + @Provides + @FlowScope + @Nullable + @ClientId + static String provideClientId(SessionMetadata sessionMetadata) { + return sessionMetadata.getClientId(); + } + + @Provides + @FlowScope + static Trid provideTrid(EppInput eppInput) { + return Trid.create(eppInput.getCommandWrapper().getClTrid()); + } + + /** Provides a mapping between flow classes and injected providers. */ + @Provides + @FlowScope + static Map, Provider> provideFlowClassMap( + Provider contactCheckFlowProvider, + Provider contactCreateFlowProvider, + Provider contactDeleteFlowProvider, + Provider contactInfoFlowProvider, + Provider contactTransferApproveFlowProvider, + Provider contactTransferCancelFlowProvider, + Provider contactTransferQueryFlowProvider, + Provider contactTransferRejectFlowProvider, + Provider contactTransferRequestFlowProvider, + Provider contactUpdateFlowProvider, + Provider claimsCheckFlowProvider, + Provider domainAllocateFlowProvider, + Provider domainApplicationCreateFlowProvider, + Provider domainApplicationDeleteFlowProvider, + Provider domainApplicationInfoFlowProvider, + Provider domainApplicationUpdateFlowProvider, + Provider domainCheckFlowProvider, + Provider domainCreateFlowProvider, + Provider domainDeleteFlowProvider, + Provider domainInfoFlowProvider, + Provider domainRenewFlowProvider, + Provider domainRestoreRequestFlowProvider, + Provider domainTransferApproveFlowProvider, + Provider domainTransferCancelFlowProvider, + Provider domainTransferQueryFlowProvider, + Provider domainTransferRejectFlowProvider, + Provider domainTransferRequestFlowProvider, + Provider domainUpdateFlowProvider, + Provider hostCheckFlowProvider, + Provider hostCreateFlowProvider, + Provider hostDeleteFlowProvider, + Provider hostInfoFlowProvider, + Provider hostUpdateFlowProvider, + Provider pollAckFlowProvider, + Provider pollRequestFlowProvider, + Provider helloFlowProvider, + Provider loginFlowProvider, + Provider logoutFlowProvider) { + return new ImmutableMap.Builder, Provider>() + .put(ContactCheckFlow.class, contactCheckFlowProvider) + .put(ContactCreateFlow.class, contactCreateFlowProvider) + .put(ContactDeleteFlow.class, contactDeleteFlowProvider) + .put(ContactInfoFlow.class, contactInfoFlowProvider) + .put(ContactTransferApproveFlow.class, contactTransferApproveFlowProvider) + .put(ContactTransferCancelFlow.class, contactTransferCancelFlowProvider) + .put(ContactTransferQueryFlow.class, contactTransferQueryFlowProvider) + .put(ContactTransferRejectFlow.class, contactTransferRejectFlowProvider) + .put(ContactTransferRequestFlow.class, contactTransferRequestFlowProvider) + .put(ContactUpdateFlow.class, contactUpdateFlowProvider) + .put(ClaimsCheckFlow.class, claimsCheckFlowProvider) + .put(DomainAllocateFlow.class, domainAllocateFlowProvider) + .put(DomainApplicationCreateFlow.class, domainApplicationCreateFlowProvider) + .put(DomainApplicationDeleteFlow.class, domainApplicationDeleteFlowProvider) + .put(DomainApplicationInfoFlow.class, domainApplicationInfoFlowProvider) + .put(DomainApplicationUpdateFlow.class, domainApplicationUpdateFlowProvider) + .put(DomainCheckFlow.class, domainCheckFlowProvider) + .put(DomainCreateFlow.class, domainCreateFlowProvider) + .put(DomainDeleteFlow.class, domainDeleteFlowProvider) + .put(DomainInfoFlow.class, domainInfoFlowProvider) + .put(DomainRenewFlow.class, domainRenewFlowProvider) + .put(DomainRestoreRequestFlow.class, domainRestoreRequestFlowProvider) + .put(DomainTransferApproveFlow.class, domainTransferApproveFlowProvider) + .put(DomainTransferCancelFlow.class, domainTransferCancelFlowProvider) + .put(DomainTransferQueryFlow.class, domainTransferQueryFlowProvider) + .put(DomainTransferRejectFlow.class, domainTransferRejectFlowProvider) + .put(DomainTransferRequestFlow.class, domainTransferRequestFlowProvider) + .put(DomainUpdateFlow.class, domainUpdateFlowProvider) + .put(HostCheckFlow.class, hostCheckFlowProvider) + .put(HostCreateFlow.class, hostCreateFlowProvider) + .put(HostDeleteFlow.class, hostDeleteFlowProvider) + .put(HostInfoFlow.class, hostInfoFlowProvider) + .put(HostUpdateFlow.class, hostUpdateFlowProvider) + .put(PollAckFlow.class, pollAckFlowProvider) + .put(PollRequestFlow.class, pollRequestFlowProvider) + .put(HelloFlow.class, helloFlowProvider) + .put(LoginFlow.class, loginFlowProvider) + .put(LogoutFlow.class, logoutFlowProvider) + .build(); + } + + @Provides + @FlowScope + static Class provideFlowClass(EppInput eppInput) { + try { + return FlowPicker.getFlowClass(eppInput); + } catch (EppException e) { + throw new EppExceptionInProviderException(e); + } + } + + @Provides + @FlowScope + static Flow provideFlow( + Map, Provider> flowProviders, + Class flowClass) { + return flowProviders.get(flowClass).get(); + } + + /** Wrapper class to carry an {@link EppException} to the calling code. */ + static class EppExceptionInProviderException extends RuntimeException { + EppExceptionInProviderException(EppException exception) { + super(exception); + } + } + + /** Dagger qualifier for inputXml. */ + @Qualifier + @Documented + public @interface InputXml {} + + /** Dagger qualifier for registrar client id. */ + @Qualifier + @Documented + public @interface ClientId {} + + /** Dagger qualifier for whether a flow is in dry run mode. */ + @Qualifier + @Documented + public @interface DryRun {} + + /** Dagger qualifier for whether a flow is in superuser mode. */ + @Qualifier + @Documented + public @interface Superuser {} + + /** Dagger qualifier for whether a flow is transactional. */ + @Qualifier + @Documented + public @interface Transactional {} +} diff --git a/java/google/registry/flows/FlowRunner.java b/java/google/registry/flows/FlowRunner.java index 892b068d1..6d6c8778e 100644 --- a/java/google/registry/flows/FlowRunner.java +++ b/java/google/registry/flows/FlowRunner.java @@ -23,16 +23,24 @@ import com.google.common.base.Strings; import com.googlecode.objectify.Work; +import google.registry.flows.FlowModule.ClientId; +import google.registry.flows.FlowModule.DryRun; +import google.registry.flows.FlowModule.InputXml; +import google.registry.flows.FlowModule.Superuser; +import google.registry.flows.FlowModule.Transactional; import google.registry.model.eppcommon.Trid; import google.registry.model.eppinput.EppInput; import google.registry.model.eppoutput.EppOutput; import google.registry.monitoring.whitebox.EppMetrics; import google.registry.util.Clock; import google.registry.util.FormattingLogger; -import google.registry.util.TypeUtils; import org.joda.time.DateTime; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Provider; + /** Run a flow, either transactionally or not, with logging and retrying as needed. */ public class FlowRunner { @@ -40,43 +48,20 @@ public class FlowRunner { private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); - private final Class flowClass; - private final EppInput eppInput; - private final Trid trid; - private final SessionMetadata sessionMetadata; - private final TransportCredentials credentials; - private final EppRequestSource eppRequestSource; - private final boolean isDryRun; - private final boolean isSuperuser; - private final byte[] inputXmlBytes; - private final EppMetrics metrics; - private final Clock clock; - - - public FlowRunner( - Class flowClass, - EppInput eppInput, - Trid trid, - SessionMetadata sessionMetadata, - TransportCredentials credentials, - EppRequestSource eppRequestSource, - boolean isDryRun, - boolean isSuperuser, - byte[] inputXmlBytes, - final EppMetrics metrics, - Clock clock) { - this.flowClass = flowClass; - this.eppInput = eppInput; - this.trid = trid; - this.sessionMetadata = sessionMetadata; - this.credentials = credentials; - this.eppRequestSource = eppRequestSource; - this.isDryRun = isDryRun; - this.isSuperuser = isSuperuser; - this.inputXmlBytes = inputXmlBytes; - this.metrics = metrics; - this.clock = clock; - } + @Inject @Nullable @ClientId String clientId; + @Inject Clock clock; + @Inject TransportCredentials credentials; + @Inject EppInput eppInput; + @Inject EppRequestSource eppRequestSource; + @Inject Provider flowProvider; + @Inject @InputXml byte[] inputXmlBytes; + @Inject @DryRun boolean isDryRun; + @Inject @Superuser boolean isSuperuser; + @Inject @Transactional boolean isTransactional; + @Inject EppMetrics metrics; + @Inject SessionMetadata sessionMetadata; + @Inject Trid trid; + @Inject FlowRunner() {} public EppOutput run() throws EppException { String clientId = sessionMetadata.getClientId(); @@ -90,10 +75,8 @@ public class FlowRunner { eppRequestSource, isDryRun ? "DRY_RUN" : "LIVE", isSuperuser ? "SUPERUSER" : "NORMAL"); - if (!isTransactional()) { - if (metrics != null) { - metrics.incrementAttempts(); - } + if (!isTransactional) { + metrics.incrementAttempts(); return createAndInitFlow(clock.nowUtc()).run(); } // We log the command in a structured format. Note that we do this before the transaction; @@ -107,9 +90,7 @@ public class FlowRunner { EppOutput flowResult = ofy().transact(new Work() { @Override public EppOutput run() { - if (metrics != null) { - metrics.incrementAttempts(); - } + metrics.incrementAttempts(); try { EppOutput output = createAndInitFlow(ofy().getTransactionTime()).run(); if (isDryRun) { @@ -137,7 +118,7 @@ public class FlowRunner { } private Flow createAndInitFlow(DateTime now) throws EppException { - return TypeUtils.instantiate(flowClass).init( + return flowProvider.get().init( eppInput, trid, sessionMetadata, @@ -148,10 +129,6 @@ public class FlowRunner { inputXmlBytes); } - public boolean isTransactional() { - return TransactionalFlow.class.isAssignableFrom(flowClass); - } - /** * Helper for logging in json format. * diff --git a/java/google/registry/flows/FlowScope.java b/java/google/registry/flows/FlowScope.java new file mode 100644 index 000000000..59b5cc2d8 --- /dev/null +++ b/java/google/registry/flows/FlowScope.java @@ -0,0 +1,35 @@ +// Copyright 2016 The Domain Registry 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Scope; + +/** + * Dagger annotation for flow-scoped components. + * + *

Note that this scope survives across transactional retries of a flow. That is, it is scoped to + * the overall execution of a flow, and not to a specific attempt. + */ +@Scope +@Documented +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface FlowScope {} diff --git a/java/google/registry/flows/contact/ContactCheckFlow.java b/java/google/registry/flows/contact/ContactCheckFlow.java index 6e03e2825..d4ca978cd 100644 --- a/java/google/registry/flows/contact/ContactCheckFlow.java +++ b/java/google/registry/flows/contact/ContactCheckFlow.java @@ -27,12 +27,17 @@ import google.registry.model.eppoutput.CheckData.ContactCheckData; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that checks whether a contact can be provisioned. * * @error {@link google.registry.flows.ResourceCheckFlow.TooManyResourceChecksException} */ public class ContactCheckFlow extends ResourceCheckFlow { + + @Inject ContactCheckFlow() {} + @Override protected CheckData getCheckData() { Set existingIds = checkResourcesExist(resourceClass, targetIds, now); diff --git a/java/google/registry/flows/contact/ContactCreateFlow.java b/java/google/registry/flows/contact/ContactCreateFlow.java index 7aaf9eebe..b3818e458 100644 --- a/java/google/registry/flows/contact/ContactCreateFlow.java +++ b/java/google/registry/flows/contact/ContactCreateFlow.java @@ -29,6 +29,8 @@ import google.registry.model.eppoutput.EppOutput; import google.registry.model.ofy.ObjectifyService; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that creates a new contact resource. * @@ -37,6 +39,9 @@ import google.registry.model.reporting.HistoryEntry; * @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException} */ public class ContactCreateFlow extends ResourceCreateFlow { + + @Inject ContactCreateFlow() {} + @Override protected EppOutput getOutput() { return createOutput(Success, ContactCreateData.create(newResource.getContactId(), now)); diff --git a/java/google/registry/flows/contact/ContactDeleteFlow.java b/java/google/registry/flows/contact/ContactDeleteFlow.java index 6651409ff..20378b9cf 100644 --- a/java/google/registry/flows/contact/ContactDeleteFlow.java +++ b/java/google/registry/flows/contact/ContactDeleteFlow.java @@ -36,6 +36,8 @@ import google.registry.model.contact.ContactResource.Builder; import google.registry.model.domain.DomainBase; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that deletes a contact resource. * @@ -49,6 +51,8 @@ public class ContactDeleteFlow extends ResourceAsyncDeleteFlow ref) { // Query for the first few linked domains, and if found, actually load them. The query is diff --git a/java/google/registry/flows/contact/ContactInfoFlow.java b/java/google/registry/flows/contact/ContactInfoFlow.java index 94aceb116..648718391 100644 --- a/java/google/registry/flows/contact/ContactInfoFlow.java +++ b/java/google/registry/flows/contact/ContactInfoFlow.java @@ -18,10 +18,14 @@ import google.registry.flows.ResourceInfoFlow; import google.registry.model.contact.ContactCommand.Info; import google.registry.model.contact.ContactResource; +import javax.inject.Inject; + /** * An EPP flow that reads a contact. * * @error {@link google.registry.flows.ResourceQueryFlow.ResourceToQueryDoesNotExistException} */ -public class ContactInfoFlow extends ResourceInfoFlow {} +public class ContactInfoFlow extends ResourceInfoFlow { + @Inject ContactInfoFlow() {} +} diff --git a/java/google/registry/flows/contact/ContactTransferApproveFlow.java b/java/google/registry/flows/contact/ContactTransferApproveFlow.java index 64bca5897..5d955bba5 100644 --- a/java/google/registry/flows/contact/ContactTransferApproveFlow.java +++ b/java/google/registry/flows/contact/ContactTransferApproveFlow.java @@ -20,6 +20,8 @@ import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that approves a pending transfer on a {@link ContactResource}. * @@ -30,6 +32,9 @@ import google.registry.model.reporting.HistoryEntry; */ public class ContactTransferApproveFlow extends ResourceTransferApproveFlow { + + @Inject ContactTransferApproveFlow() {} + @Override protected final HistoryEntry.Type getHistoryEntryType() { return HistoryEntry.Type.CONTACT_TRANSFER_APPROVE; diff --git a/java/google/registry/flows/contact/ContactTransferCancelFlow.java b/java/google/registry/flows/contact/ContactTransferCancelFlow.java index 766c953ea..d70691a54 100644 --- a/java/google/registry/flows/contact/ContactTransferCancelFlow.java +++ b/java/google/registry/flows/contact/ContactTransferCancelFlow.java @@ -20,6 +20,8 @@ import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that cancels a pending transfer on a {@link ContactResource}. * @@ -30,6 +32,9 @@ import google.registry.model.reporting.HistoryEntry; */ public class ContactTransferCancelFlow extends ResourceTransferCancelFlow { + + @Inject ContactTransferCancelFlow() {} + @Override protected final HistoryEntry.Type getHistoryEntryType() { return HistoryEntry.Type.CONTACT_TRANSFER_CANCEL; diff --git a/java/google/registry/flows/contact/ContactTransferQueryFlow.java b/java/google/registry/flows/contact/ContactTransferQueryFlow.java index e48b8b53f..e6450abb6 100644 --- a/java/google/registry/flows/contact/ContactTransferQueryFlow.java +++ b/java/google/registry/flows/contact/ContactTransferQueryFlow.java @@ -18,6 +18,8 @@ import google.registry.flows.ResourceTransferQueryFlow; import google.registry.model.contact.ContactCommand.Transfer; import google.registry.model.contact.ContactResource; +import javax.inject.Inject; + /** * An EPP flow that queries a pending transfer on a {@link ContactResource}. * @@ -27,4 +29,5 @@ import google.registry.model.contact.ContactResource; * @error {@link google.registry.flows.ResourceTransferQueryFlow.NotAuthorizedToViewTransferException} */ public class ContactTransferQueryFlow extends ResourceTransferQueryFlow { + @Inject ContactTransferQueryFlow() {} } diff --git a/java/google/registry/flows/contact/ContactTransferRejectFlow.java b/java/google/registry/flows/contact/ContactTransferRejectFlow.java index 02fa7be2f..ad0f31f13 100644 --- a/java/google/registry/flows/contact/ContactTransferRejectFlow.java +++ b/java/google/registry/flows/contact/ContactTransferRejectFlow.java @@ -20,6 +20,8 @@ import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that rejects a pending transfer on a {@link ContactResource}. * @@ -30,6 +32,9 @@ import google.registry.model.reporting.HistoryEntry; */ public class ContactTransferRejectFlow extends ResourceTransferRejectFlow { + + @Inject ContactTransferRejectFlow() {} + @Override protected final HistoryEntry.Type getHistoryEntryType() { return HistoryEntry.Type.CONTACT_TRANSFER_REJECT; diff --git a/java/google/registry/flows/contact/ContactTransferRequestFlow.java b/java/google/registry/flows/contact/ContactTransferRequestFlow.java index 658960fe3..d867efeb7 100644 --- a/java/google/registry/flows/contact/ContactTransferRequestFlow.java +++ b/java/google/registry/flows/contact/ContactTransferRequestFlow.java @@ -22,6 +22,8 @@ import google.registry.model.reporting.HistoryEntry; import org.joda.time.Duration; +import javax.inject.Inject; + /** * An EPP flow that requests a transfer on a {@link ContactResource}. * @@ -34,6 +36,8 @@ import org.joda.time.Duration; public class ContactTransferRequestFlow extends ResourceTransferRequestFlow { + @Inject ContactTransferRequestFlow() {} + @Override protected final HistoryEntry.Type getHistoryEntryType() { return HistoryEntry.Type.CONTACT_TRANSFER_REQUEST; diff --git a/java/google/registry/flows/contact/ContactUpdateFlow.java b/java/google/registry/flows/contact/ContactUpdateFlow.java index b867088b0..d0821b490 100644 --- a/java/google/registry/flows/contact/ContactUpdateFlow.java +++ b/java/google/registry/flows/contact/ContactUpdateFlow.java @@ -24,6 +24,8 @@ import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that updates a contact resource. * @@ -36,6 +38,9 @@ import google.registry.model.reporting.HistoryEntry; * @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException} */ public class ContactUpdateFlow extends ResourceUpdateFlow { + + @Inject ContactUpdateFlow() {} + @Override protected void verifyNewUpdatedStateIsAllowed() throws EppException { validateAsciiPostalInfo(newResource.getInternationalizedPostalInfo()); diff --git a/java/google/registry/flows/domain/ClaimsCheckFlow.java b/java/google/registry/flows/domain/ClaimsCheckFlow.java index 4dbe91770..e3f594b70 100644 --- a/java/google/registry/flows/domain/ClaimsCheckFlow.java +++ b/java/google/registry/flows/domain/ClaimsCheckFlow.java @@ -35,6 +35,8 @@ import google.registry.model.tmch.ClaimsListShard; import java.util.Map.Entry; +import javax.inject.Inject; + /** * An EPP flow that checks whether strings are trademarked. * @@ -48,6 +50,8 @@ public class ClaimsCheckFlow extends BaseDomainCheckFlow { public static final ImmutableSet DISALLOWED_TLD_STATES = Sets.immutableEnumSet( TldState.PREDELEGATION, TldState.SUNRISE); + @Inject ClaimsCheckFlow() {} + @Override protected void initDomainCheckFlow() throws EppException { registerExtensions(LaunchCheckExtension.class); diff --git a/java/google/registry/flows/domain/DomainAllocateFlow.java b/java/google/registry/flows/domain/DomainAllocateFlow.java index 452d310de..98fc5d9f7 100644 --- a/java/google/registry/flows/domain/DomainAllocateFlow.java +++ b/java/google/registry/flows/domain/DomainAllocateFlow.java @@ -48,6 +48,8 @@ import google.registry.model.registry.label.ReservationType; import google.registry.model.reporting.HistoryEntry; import google.registry.tmch.LordnTask; +import javax.inject.Inject; + /** * An EPP flow that allocates a new domain resource from a domain application. * @@ -62,6 +64,8 @@ public class DomainAllocateFlow extends DomainCreateOrAllocateFlow { protected AllocateCreateExtension allocateCreate; protected DomainApplication application; + @Inject DomainAllocateFlow() {} + @Override protected final void initDomainCreateOrAllocateFlow() { registerExtensions(AllocateCreateExtension.class); diff --git a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java index bfa9b5e68..e996e8a2a 100644 --- a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java +++ b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java @@ -51,6 +51,8 @@ import google.registry.model.smd.EncodedSignedMark; import java.util.List; +import javax.inject.Inject; + /** * An EPP flow that creates a new application for a domain resource. * @@ -114,6 +116,8 @@ import java.util.List; */ public class DomainApplicationCreateFlow extends BaseDomainCreateFlow { + @Inject DomainApplicationCreateFlow() {} + @Override protected void initDomainCreateFlow() { registerExtensions(FeeCreateExtension.class, LaunchCreateExtension.class); diff --git a/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java b/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java index b459a858e..86a30186b 100644 --- a/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java +++ b/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java @@ -36,6 +36,8 @@ import google.registry.model.reporting.HistoryEntry; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that deletes a domain application. * @@ -51,6 +53,8 @@ import java.util.Set; public class DomainApplicationDeleteFlow extends ResourceSyncDeleteFlow { + @Inject DomainApplicationDeleteFlow() {} + @Override protected void initResourceCreateOrMutateFlow() throws EppException { registerExtensions(LaunchDeleteExtension.class); diff --git a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java index e2f7c326e..50264b1e0 100644 --- a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java +++ b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java @@ -32,6 +32,8 @@ import google.registry.model.mark.Mark; import google.registry.model.smd.EncodedSignedMark; import google.registry.model.smd.SignedMark; +import javax.inject.Inject; + /** * An EPP flow that reads a domain application. * @@ -45,6 +47,8 @@ public class DomainApplicationInfoFlow extends BaseDomainInfoFlow { + @Inject DomainApplicationUpdateFlow() {} + @Override protected void initDomainUpdateFlow() throws EppException { registerExtensions(LaunchUpdateExtension.class, SecDnsUpdateExtension.class); diff --git a/java/google/registry/flows/domain/DomainCheckFlow.java b/java/google/registry/flows/domain/DomainCheckFlow.java index 847fa108f..fa34255dc 100644 --- a/java/google/registry/flows/domain/DomainCheckFlow.java +++ b/java/google/registry/flows/domain/DomainCheckFlow.java @@ -48,6 +48,8 @@ import google.registry.model.registry.label.ReservationType; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that checks whether a domain can be provisioned. * @@ -81,6 +83,8 @@ public class DomainCheckFlow extends BaseDomainCheckFlow { protected RegTypeCheckExtension regTypeExtension; + @Inject DomainCheckFlow() {} + @Override protected void initDomainCheckFlow() throws EppException { registerExtensions( diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java index 5c5939531..310e3cbcd 100644 --- a/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/java/google/registry/flows/domain/DomainCreateFlow.java @@ -41,6 +41,8 @@ import google.registry.tmch.LordnTask; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that creates a new domain resource. * @@ -101,6 +103,8 @@ public class DomainCreateFlow extends DomainCreateOrAllocateFlow { protected RegTypeCreateExtension regTypeExtension; + @Inject DomainCreateFlow() {} + private boolean isAnchorTenant() { return isAnchorTenantViaReservation || isAnchorTenantViaExtension; } diff --git a/java/google/registry/flows/domain/DomainDeleteFlow.java b/java/google/registry/flows/domain/DomainDeleteFlow.java index 12ae06861..96e7800ab 100644 --- a/java/google/registry/flows/domain/DomainDeleteFlow.java +++ b/java/google/registry/flows/domain/DomainDeleteFlow.java @@ -55,6 +55,8 @@ import org.joda.money.CurrencyUnit; import org.joda.money.Money; import org.joda.time.DateTime; +import javax.inject.Inject; + /** * An EPP flow that deletes a domain resource. * @@ -73,6 +75,8 @@ public class DomainDeleteFlow extends ResourceSyncDeleteFlow credits; + @Inject DomainDeleteFlow() {} + @Override protected void initResourceCreateOrMutateFlow() throws EppException { registerExtensions(SecDnsUpdateExtension.class); diff --git a/java/google/registry/flows/domain/DomainInfoFlow.java b/java/google/registry/flows/domain/DomainInfoFlow.java index 336e7dad3..c3d7fd820 100644 --- a/java/google/registry/flows/domain/DomainInfoFlow.java +++ b/java/google/registry/flows/domain/DomainInfoFlow.java @@ -31,6 +31,8 @@ import google.registry.model.eppoutput.EppResponse.ResponseExtension; import java.util.List; +import javax.inject.Inject; + /** * An EPP flow that reads a domain. * @@ -45,6 +47,8 @@ public class DomainInfoFlow extends BaseDomainInfoFlow protected List registrationTypes; + @Inject DomainInfoFlow() {} + @Override protected void initSingleResourceFlow() throws EppException { registerExtensions(FeeInfoExtension.class); diff --git a/java/google/registry/flows/domain/DomainRenewFlow.java b/java/google/registry/flows/domain/DomainRenewFlow.java index b8d75e0ba..8e4da5503 100644 --- a/java/google/registry/flows/domain/DomainRenewFlow.java +++ b/java/google/registry/flows/domain/DomainRenewFlow.java @@ -59,6 +59,8 @@ import org.joda.time.DateTime; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that updates a domain resource. * @@ -86,6 +88,8 @@ public class DomainRenewFlow extends OwnedResourceMutateFlow getDisallowedStatuses() { return RENEW_DISALLOWED_STATUSES; diff --git a/java/google/registry/flows/domain/DomainRestoreRequestFlow.java b/java/google/registry/flows/domain/DomainRestoreRequestFlow.java index ffe8e89c5..b3aa457cb 100644 --- a/java/google/registry/flows/domain/DomainRestoreRequestFlow.java +++ b/java/google/registry/flows/domain/DomainRestoreRequestFlow.java @@ -54,6 +54,8 @@ import google.registry.model.reporting.HistoryEntry; import org.joda.money.Money; import org.joda.time.DateTime; +import javax.inject.Inject; + /** * An EPP flow that requests that a deleted domain be restored. * @@ -77,6 +79,8 @@ public class DomainRestoreRequestFlow extends OwnedResourceMutateFlow { + @Inject DomainTransferApproveFlow() {} + @Override protected void verifyOwnedResourcePendingTransferMutationAllowed() throws EppException { checkAllowedAccessToTld(getAllowedTlds(), existingResource.getTld()); diff --git a/java/google/registry/flows/domain/DomainTransferCancelFlow.java b/java/google/registry/flows/domain/DomainTransferCancelFlow.java index 1c1b85684..c5253db0f 100644 --- a/java/google/registry/flows/domain/DomainTransferCancelFlow.java +++ b/java/google/registry/flows/domain/DomainTransferCancelFlow.java @@ -25,6 +25,8 @@ import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that cancels a pending transfer on a {@link DomainResource}. * @@ -37,6 +39,8 @@ import google.registry.model.reporting.HistoryEntry; public class DomainTransferCancelFlow extends ResourceTransferCancelFlow { + @Inject DomainTransferCancelFlow() {} + /** * Reopen the autorenew event and poll message that we closed for the implicit transfer. * This may end up recreating the autorenew poll message if it was deleted when the transfer diff --git a/java/google/registry/flows/domain/DomainTransferQueryFlow.java b/java/google/registry/flows/domain/DomainTransferQueryFlow.java index 4ce787265..209c333ed 100644 --- a/java/google/registry/flows/domain/DomainTransferQueryFlow.java +++ b/java/google/registry/flows/domain/DomainTransferQueryFlow.java @@ -18,6 +18,8 @@ import google.registry.flows.ResourceTransferQueryFlow; import google.registry.model.domain.DomainCommand.Transfer; import google.registry.model.domain.DomainResource; +import javax.inject.Inject; + /** * An EPP flow that queries a pending transfer on a {@link DomainResource}. * @@ -26,4 +28,6 @@ import google.registry.model.domain.DomainResource; * @error {@link google.registry.flows.ResourceTransferQueryFlow.NoTransferHistoryToQueryException} * @error {@link google.registry.flows.ResourceTransferQueryFlow.NotAuthorizedToViewTransferException} */ -public class DomainTransferQueryFlow extends ResourceTransferQueryFlow {} +public class DomainTransferQueryFlow extends ResourceTransferQueryFlow { + @Inject DomainTransferQueryFlow() {} +} diff --git a/java/google/registry/flows/domain/DomainTransferRejectFlow.java b/java/google/registry/flows/domain/DomainTransferRejectFlow.java index fcc660a28..ef90c07ca 100644 --- a/java/google/registry/flows/domain/DomainTransferRejectFlow.java +++ b/java/google/registry/flows/domain/DomainTransferRejectFlow.java @@ -25,6 +25,8 @@ import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that rejects a pending transfer on a {@link DomainResource}. * @@ -37,6 +39,8 @@ import google.registry.model.reporting.HistoryEntry; public class DomainTransferRejectFlow extends ResourceTransferRejectFlow { + @Inject DomainTransferRejectFlow() {} + @Override protected void verifyOwnedResourcePendingTransferMutationAllowed() throws EppException { checkAllowedAccessToTld(getAllowedTlds(), existingResource.getTld()); diff --git a/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/java/google/registry/flows/domain/DomainTransferRequestFlow.java index 7d31b3eae..1538c23b0 100644 --- a/java/google/registry/flows/domain/DomainTransferRequestFlow.java +++ b/java/google/registry/flows/domain/DomainTransferRequestFlow.java @@ -56,6 +56,8 @@ import org.joda.time.Duration; import java.util.HashSet; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that requests a transfer on a {@link DomainResource}. * @@ -97,6 +99,8 @@ public class DomainTransferRequestFlow */ private FeeTransferExtension feeTransfer; + @Inject DomainTransferRequestFlow() {} + @Override protected Duration getAutomaticTransferLength() { return Registry.get(existingResource.getTld()).getAutomaticTransferLength(); diff --git a/java/google/registry/flows/domain/DomainUpdateFlow.java b/java/google/registry/flows/domain/DomainUpdateFlow.java index e9e9df15c..fea0ca152 100644 --- a/java/google/registry/flows/domain/DomainUpdateFlow.java +++ b/java/google/registry/flows/domain/DomainUpdateFlow.java @@ -39,6 +39,8 @@ import org.joda.time.DateTime; import java.util.Set; +import javax.inject.Inject; + /** * An EPP flow that updates a domain resource. * @@ -70,6 +72,8 @@ public class DomainUpdateFlow extends BaseDomainUpdateFlow { + + @Inject HostCheckFlow() {} + @Override protected CheckData getCheckData() { Set existingIds = checkResourcesExist(resourceClass, targetIds, now); diff --git a/java/google/registry/flows/host/HostCreateFlow.java b/java/google/registry/flows/host/HostCreateFlow.java index 6ef87520e..2d0d0d8a0 100644 --- a/java/google/registry/flows/host/HostCreateFlow.java +++ b/java/google/registry/flows/host/HostCreateFlow.java @@ -40,6 +40,8 @@ import google.registry.model.host.HostResource.Builder; import google.registry.model.ofy.ObjectifyService; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that creates a new host resource. * @@ -67,6 +69,8 @@ public class HostCreateFlow extends ResourceCreateFlow> superordinateDomain; + @Inject HostCreateFlow() {} + @Override protected void initResourceCreateOrMutateFlow() throws EppException { superordinateDomain = Optional.fromNullable(lookupSuperordinateDomain( diff --git a/java/google/registry/flows/host/HostDeleteFlow.java b/java/google/registry/flows/host/HostDeleteFlow.java index 526d7876d..138bbc2bc 100644 --- a/java/google/registry/flows/host/HostDeleteFlow.java +++ b/java/google/registry/flows/host/HostDeleteFlow.java @@ -36,6 +36,8 @@ import google.registry.model.host.HostResource; import google.registry.model.host.HostResource.Builder; import google.registry.model.reporting.HistoryEntry; +import javax.inject.Inject; + /** * An EPP flow that deletes a host resource. * @@ -49,6 +51,8 @@ public class HostDeleteFlow extends ResourceAsyncDeleteFlow ref) { // Query for the first few linked domains, and if found, actually load them. The query is diff --git a/java/google/registry/flows/host/HostInfoFlow.java b/java/google/registry/flows/host/HostInfoFlow.java index 7eece7515..67ff20dd8 100644 --- a/java/google/registry/flows/host/HostInfoFlow.java +++ b/java/google/registry/flows/host/HostInfoFlow.java @@ -18,9 +18,13 @@ import google.registry.flows.ResourceInfoFlow; import google.registry.model.host.HostCommand; import google.registry.model.host.HostResource; +import javax.inject.Inject; + /** * An EPP flow that reads a host. * * @error {@link google.registry.flows.ResourceQueryFlow.ResourceToQueryDoesNotExistException} */ -public class HostInfoFlow extends ResourceInfoFlow {} +public class HostInfoFlow extends ResourceInfoFlow { + @Inject HostInfoFlow() {} +} diff --git a/java/google/registry/flows/host/HostUpdateFlow.java b/java/google/registry/flows/host/HostUpdateFlow.java index 4ab9a0984..f10c8a4eb 100644 --- a/java/google/registry/flows/host/HostUpdateFlow.java +++ b/java/google/registry/flows/host/HostUpdateFlow.java @@ -47,6 +47,8 @@ import org.joda.time.Duration; import java.util.Objects; +import javax.inject.Inject; + /** * An EPP flow that updates a host resource. * @@ -72,6 +74,8 @@ public class HostUpdateFlow extends ResourceUpdateFlow) JSONValue.parse(((FakeResponse) action.response).getPayload()); } diff --git a/javatests/google/registry/flows/EppCommitLogsTest.java b/javatests/google/registry/flows/EppCommitLogsTest.java new file mode 100644 index 000000000..a932403e9 --- /dev/null +++ b/javatests/google/registry/flows/EppCommitLogsTest.java @@ -0,0 +1,171 @@ +// Copyright 2016 The Domain Registry 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; + +import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.EppResourceUtils.loadAtPointInTime; +import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.testing.DatastoreHelper.createTld; +import static google.registry.testing.DatastoreHelper.persistActiveContact; +import static google.registry.testing.DatastoreHelper.persistActiveHost; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.joda.time.DateTimeZone.UTC; +import static org.joda.time.Duration.standardDays; + +import com.googlecode.objectify.Key; + +import google.registry.flows.EppTestComponent.FakesAndMocksModule; +import google.registry.model.domain.DomainResource; +import google.registry.model.ofy.Ofy; +import google.registry.testing.AppEngineRule; +import google.registry.testing.EppLoader; +import google.registry.testing.ExceptionRule; +import google.registry.testing.FakeClock; +import google.registry.testing.FakeHttpSession; +import google.registry.testing.InjectRule; +import google.registry.testing.ShardableTestCase; + +import org.joda.time.DateTime; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test that domain flows create the commit logs needed to reload at points in the past. */ +@RunWith(JUnit4.class) +public class EppCommitLogsTest extends ShardableTestCase { + + @Rule + public final AppEngineRule appEngine = AppEngineRule.builder() + .withDatastore() + .withTaskQueue() + .build(); + + @Rule + public final ExceptionRule thrown = new ExceptionRule(); + + @Rule + public final InjectRule inject = new InjectRule(); + + private final FakeClock clock = new FakeClock(DateTime.now(UTC)); + private EppLoader eppLoader; + + @Before + public void init() throws Exception { + createTld("tld"); + inject.setStaticField(Ofy.class, "clock", clock); + } + + private void runFlow() throws Exception { + SessionMetadata sessionMetadata = new HttpSessionMetadata(new FakeHttpSession()); + sessionMetadata.setClientId("TheRegistrar"); + DaggerEppTestComponent.builder() + .fakesAndMocksModule(new FakesAndMocksModule(clock)) + .build() + .startRequest() + .flowComponentBuilder() + .flowModule(new FlowModule.Builder() + .setSessionMetadata(sessionMetadata) + .setCredentials(new PasswordOnlyTransportCredentials()) + .setEppRequestSource(EppRequestSource.UNIT_TEST) + .setIsDryRun(false) + .setIsSuperuser(false) + .setInputXmlBytes(eppLoader.getEppXml().getBytes(UTF_8)) + .setEppInput(eppLoader.getEpp()) + .build()) + .build() + .flowRunner() + .run(); + } + + @Test + public void testLoadAtPointInTime() throws Exception { + clock.setTo(DateTime.parse("1984-12-18T12:30Z")); // not midnight + + persistActiveHost("ns1.example.net"); + persistActiveHost("ns2.example.net"); + persistActiveContact("jd1234"); + persistActiveContact("sh8013"); + + clock.advanceBy(standardDays(1)); + DateTime timeAtCreate = clock.nowUtc(); + clock.setTo(timeAtCreate); + eppLoader = new EppLoader(this, "domain_create.xml"); + runFlow(); + ofy().clearSessionCache(); + Key key = Key.create(ofy().load().type(DomainResource.class).first().now()); + DomainResource domainAfterCreate = ofy().load().key(key).now(); + assertThat(domainAfterCreate.getFullyQualifiedDomainName()).isEqualTo("example.tld"); + + clock.advanceBy(standardDays(2)); + DateTime timeAtFirstUpdate = clock.nowUtc(); + eppLoader = new EppLoader(this, "domain_update_dsdata_add.xml"); + runFlow(); + ofy().clearSessionCache(); + + DomainResource domainAfterFirstUpdate = ofy().load().key(key).now(); + assertThat(domainAfterCreate).isNotEqualTo(domainAfterFirstUpdate); + + clock.advanceOneMilli(); // same day as first update + DateTime timeAtSecondUpdate = clock.nowUtc(); + eppLoader = new EppLoader(this, "domain_update_dsdata_rem.xml"); + runFlow(); + ofy().clearSessionCache(); + DomainResource domainAfterSecondUpdate = ofy().load().key(key).now(); + + clock.advanceBy(standardDays(2)); + DateTime timeAtDelete = clock.nowUtc(); // before 'add' grace period ends + eppLoader = new EppLoader(this, "domain_delete.xml"); + runFlow(); + ofy().clearSessionCache(); + + assertThat(domainAfterFirstUpdate).isNotEqualTo(domainAfterSecondUpdate); + + // Point-in-time can only rewind an object from the current version, not roll forward. + DomainResource latest = ofy().load().key(key).now(); + + // Creation time has millisecond granularity due to isActive() check. + ofy().clearSessionCache(); + assertThat(loadAtPointInTime(latest, timeAtCreate.minusMillis(1)).now()).isNull(); + assertThat(loadAtPointInTime(latest, timeAtCreate).now()).isNotNull(); + assertThat(loadAtPointInTime(latest, timeAtCreate.plusMillis(1)).now()).isNotNull(); + + ofy().clearSessionCache(); + assertThat(loadAtPointInTime(latest, timeAtCreate.plusDays(1)).now()) + .isEqualTo(domainAfterCreate); + + // Both updates happened on the same day. Since the revisions field has day granularity, the + // reference to the first update should have been overwritten by the second, and its timestamp + // rolled forward. So we have to fall back to the last revision before midnight. + ofy().clearSessionCache(); + assertThat(loadAtPointInTime(latest, timeAtFirstUpdate).now()) + .isEqualTo(domainAfterCreate); + + ofy().clearSessionCache(); + assertThat(loadAtPointInTime(latest, timeAtSecondUpdate).now()) + .isEqualTo(domainAfterSecondUpdate); + + ofy().clearSessionCache(); + assertThat(loadAtPointInTime(latest, timeAtSecondUpdate.plusDays(1)).now()) + .isEqualTo(domainAfterSecondUpdate); + + // Deletion time has millisecond granularity due to isActive() check. + ofy().clearSessionCache(); + assertThat(loadAtPointInTime(latest, timeAtDelete.minusMillis(1)).now()).isNotNull(); + assertThat(loadAtPointInTime(latest, timeAtDelete).now()).isNull(); + assertThat(loadAtPointInTime(latest, timeAtDelete.plusMillis(1)).now()).isNull(); + } +} diff --git a/javatests/google/registry/flows/EppLifecycleDomainTest.java b/javatests/google/registry/flows/EppLifecycleDomainTest.java index 3903ec728..a9e0190b9 100644 --- a/javatests/google/registry/flows/EppLifecycleDomainTest.java +++ b/javatests/google/registry/flows/EppLifecycleDomainTest.java @@ -15,6 +15,7 @@ package google.registry.flows; import static google.registry.testing.DatastoreHelper.createTld; +import static google.registry.testing.DatastoreHelper.createTlds; import static google.registry.util.DateTimeUtils.START_OF_TIME; import com.google.common.collect.ImmutableMap; @@ -44,7 +45,7 @@ public class EppLifecycleDomainTest extends EppTestCase { @Before public void initTld() { - createTld("example"); + createTlds("example", "tld"); } /** Create the two administrative contacts and two hosts. */ @@ -129,7 +130,7 @@ public class EppLifecycleDomainTest extends EppTestCase { "domain_create_response.xml", DateTime.parse("2000-06-01T00:02:00Z")); - // Delete domain example.com after its add grace period has expired. + // Delete domain example.tld after its add grace period has expired. assertCommandAndResponse( "domain_delete.xml", "generic_success_action_pending_response.xml", @@ -338,7 +339,7 @@ public class EppLifecycleDomainTest extends EppTestCase { DateTime.parse("2001-01-01T00:01:00Z")); assertCommandAndResponse( "poll_ack.xml", - ImmutableMap.of("ID", "1-A-EXAMPLE-16-20"), + ImmutableMap.of("ID", "1-B-EXAMPLE-17-21"), "poll_ack_response_empty.xml", null, DateTime.parse("2001-01-01T00:01:00Z")); @@ -350,7 +351,7 @@ public class EppLifecycleDomainTest extends EppTestCase { DateTime.parse("2001-01-06T00:01:00Z")); assertCommandAndResponse( "poll_ack.xml", - ImmutableMap.of("ID", "1-A-EXAMPLE-16-22"), + ImmutableMap.of("ID", "1-B-EXAMPLE-17-23"), "poll_ack_response_empty.xml", null, DateTime.parse("2001-01-06T00:01:00Z")); @@ -366,7 +367,7 @@ public class EppLifecycleDomainTest extends EppTestCase { DateTime.parse("2001-01-06T00:02:00Z")); assertCommandAndResponse( "poll_ack.xml", - ImmutableMap.of("ID", "1-A-EXAMPLE-16-21"), + ImmutableMap.of("ID", "1-B-EXAMPLE-17-22"), "poll_ack_response_empty.xml", null, DateTime.parse("2001-01-06T00:02:00Z")); diff --git a/javatests/google/registry/flows/EppTestCase.java b/javatests/google/registry/flows/EppTestCase.java index 2a53eecea..aafa6c902 100644 --- a/javatests/google/registry/flows/EppTestCase.java +++ b/javatests/google/registry/flows/EppTestCase.java @@ -21,12 +21,11 @@ import static google.registry.xml.XmlTestUtils.assertXmlEqualsWithMessage; import static java.nio.charset.StandardCharsets.UTF_8; import static javax.servlet.http.HttpServletResponse.SC_OK; import static org.joda.time.DateTimeZone.UTC; -import static org.mockito.Mockito.mock; import com.google.common.net.MediaType; +import google.registry.flows.EppTestComponent.FakesAndMocksModule; import google.registry.model.ofy.Ofy; -import google.registry.monitoring.whitebox.EppMetrics; import google.registry.testing.FakeClock; import google.registry.testing.FakeHttpSession; import google.registry.testing.FakeResponse; @@ -100,8 +99,7 @@ public class EppTestCase extends ShardableTestCase { // When a session is invalidated, reset the sessionMetadata field. super.invalidate(); EppTestCase.this.sessionMetadata = null; - } - }; + }}; } String actualOutput = executeXmlCommand(input); assertXmlEqualsWithMessage( @@ -118,14 +116,16 @@ public class EppTestCase extends ShardableTestCase { EppRequestHandler handler = new EppRequestHandler(); FakeResponse response = new FakeResponse(); handler.response = response; - handler.eppController = new EppController(); - handler.eppController.clock = clock; - handler.eppController.metrics = mock(EppMetrics.class); + handler.eppController = DaggerEppTestComponent.builder() + .fakesAndMocksModule(new FakesAndMocksModule(clock)) + .build() + .startRequest() + .eppController(); handler.executeEpp( sessionMetadata, credentials, EppRequestSource.UNIT_TEST, - false, + false, // Not dryRun. isSuperuser, inputXml.getBytes(UTF_8)); assertThat(response.getStatus()).isEqualTo(SC_OK); diff --git a/javatests/google/registry/flows/EppTestComponent.java b/javatests/google/registry/flows/EppTestComponent.java new file mode 100644 index 000000000..5d319735f --- /dev/null +++ b/javatests/google/registry/flows/EppTestComponent.java @@ -0,0 +1,70 @@ +// Copyright 2016 The Domain Registry 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; + +import static org.mockito.Mockito.mock; + +import dagger.Component; +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; + +import google.registry.monitoring.whitebox.EppMetrics; +import google.registry.request.RequestScope; +import google.registry.testing.FakeClock; +import google.registry.util.Clock; + +import javax.inject.Singleton; + +/** Dagger component for running EPP tests. */ +@Singleton +@Component( + modules = { + EppTestComponent.FakesAndMocksModule.class + }) +interface EppTestComponent { + + RequestComponent startRequest(); + + /** Module for injecting fakes and mocks. */ + @Module + static class FakesAndMocksModule { + final FakeClock clock; + final EppMetrics metrics; + + FakesAndMocksModule(FakeClock clock) { + this.clock = clock; + this.metrics = mock(EppMetrics.class); + } + + @Provides + Clock provideClock() { + return clock; + } + + @Provides + EppMetrics provideMetrics() { + return metrics; + } + } + + /** Subcomponent for request scoped injections. */ + @RequestScope + @Subcomponent + interface RequestComponent { + EppController eppController(); + FlowComponent.Builder flowComponentBuilder(); + } +} diff --git a/javatests/google/registry/flows/FlowTestCase.java b/javatests/google/registry/flows/FlowTestCase.java index 1bc959a2e..02ad186df 100644 --- a/javatests/google/registry/flows/FlowTestCase.java +++ b/javatests/google/registry/flows/FlowTestCase.java @@ -34,13 +34,12 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import google.registry.flows.EppTestComponent.FakesAndMocksModule; import google.registry.flows.picker.FlowPicker; import google.registry.model.billing.BillingEvent; import google.registry.model.domain.GracePeriod; import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.eppcommon.ProtocolDefinition; -import google.registry.model.eppcommon.Trid; -import google.registry.model.eppinput.EppInput; import google.registry.model.eppoutput.EppOutput; import google.registry.model.ofy.Ofy; import google.registry.model.poll.PollMessage; @@ -86,8 +85,6 @@ public abstract class FlowTestCase { @Rule public final InjectRule inject = new InjectRule(); - private Class flowClass; - protected EppLoader eppLoader; protected SessionMetadata sessionMetadata; protected FakeClock clock = new FakeClock(DateTime.now(UTC)); @@ -120,29 +117,8 @@ public abstract class FlowTestCase { return readResourceUtf8(getClass(), "testdata/" + filename); } - /** Load a flow from an epp object. */ - private FlowRunner getFlowRunner(CommitMode commitMode, UserPrivileges userPrivileges) - throws Exception { - EppInput eppInput = eppLoader.getEpp(); - flowClass = firstNonNull(flowClass, FlowPicker.getFlowClass(eppInput)); - Class expectedFlowClass = new TypeInstantiator(getClass()){}.getExactType(); - assertThat(flowClass).isEqualTo(expectedFlowClass); - return new FlowRunner( - flowClass, - eppInput, - getTrid(), - sessionMetadata, - credentials, - eppRequestSource, - commitMode.equals(CommitMode.DRY_RUN), - userPrivileges.equals(UserPrivileges.SUPERUSER), - "".getBytes(), - null, - clock); - } - - protected Trid getTrid() throws Exception { - return Trid.create(eppLoader.getEpp().getCommandWrapper().getClTrid(), "server-trid"); + protected String getClientTrid() throws Exception { + return eppLoader.getEpp().getCommandWrapper().getClTrid(); } /** Gets the client ID that the flow will run as. */ @@ -156,8 +132,15 @@ public abstract class FlowTestCase { } public void assertTransactionalFlow(boolean isTransactional) throws Exception { - assertThat(getFlowRunner(CommitMode.LIVE, UserPrivileges.NORMAL).isTransactional()) - .isEqualTo(isTransactional); + Class flowClass = FlowPicker.getFlowClass(eppLoader.getEpp()); + if (isTransactional) { + assertThat(flowClass).isAssignableTo(TransactionalFlow.class); + } else { + // There's no "isNotAssignableTo" in Truth. + assertThat(TransactionalFlow.class.isAssignableFrom(flowClass)) + .named(flowClass.getSimpleName() + " implements TransactionalFlow") + .isFalse(); + } } public void assertNoHistory() throws Exception { @@ -273,36 +256,67 @@ public abstract class FlowTestCase { .containsExactlyElementsIn(FluentIterable.from(asList(expected)).transform(idStripper)); } - /** Run a flow, and attempt to marshal the result to EPP or throw if it doesn't validate. */ + private EppOutput runFlowInternal(CommitMode commitMode, UserPrivileges userPrivileges) + throws Exception { + // Assert that the xml triggers the flow we expect. + assertThat(FlowPicker.getFlowClass(eppLoader.getEpp())) + .isEqualTo(new TypeInstantiator(getClass()){}.getExactType()); + // Run the flow. + return DaggerEppTestComponent.builder() + .fakesAndMocksModule(new FakesAndMocksModule(clock)) + .build() + .startRequest() + .flowComponentBuilder() + .flowModule(new FlowModule.Builder() + .setSessionMetadata(sessionMetadata) + .setCredentials(credentials) + .setEppRequestSource(eppRequestSource) + .setIsDryRun(commitMode.equals(CommitMode.DRY_RUN)) + .setIsSuperuser(userPrivileges.equals(UserPrivileges.SUPERUSER)) + .setInputXmlBytes(eppLoader.getEppXml().getBytes(UTF_8)) + .setEppInput(eppLoader.getEpp()) + .build()) + .build() + .flowRunner() + .run(); + } + + /** Run a flow and marshal the result to EPP, or throw if it doesn't validate. */ public EppOutput runFlow(CommitMode commitMode, UserPrivileges userPrivileges) throws Exception { - EppOutput output = getFlowRunner(commitMode, userPrivileges).run(); + EppOutput output = runFlowInternal(commitMode, userPrivileges); marshal(output, ValidationMode.STRICT); return output; } + /** Shortcut to call {@link #runFlow(CommitMode, UserPrivileges)} as normal user and live run. */ public EppOutput runFlow() throws Exception { return runFlow(CommitMode.LIVE, UserPrivileges.NORMAL); } + /** Run a flow, marshal the result to EPP, and assert that the output is as expected. */ public void runFlowAssertResponse( CommitMode commitMode, UserPrivileges userPrivileges, String xml, String... ignoredPaths) throws Exception { - EppOutput eppOutput = getFlowRunner(commitMode, userPrivileges).run(); - if (eppOutput.isResponse()) { - assertThat(eppOutput.isSuccess()).isTrue(); + // Always ignore the server trid, since it's generated and meaningless to flow correctness. + String[] ignoredPathsPlusTrid = FluentIterable.from(ignoredPaths) + .append("epp.response.trID.svTRID") + .toArray(String.class); + EppOutput output = runFlowInternal(commitMode, userPrivileges); + if (output.isResponse()) { + assertThat(output.isSuccess()).isTrue(); } try { assertXmlEquals( - xml, new String(marshal(eppOutput, ValidationMode.STRICT), UTF_8), ignoredPaths); + xml, new String(marshal(output, ValidationMode.STRICT), UTF_8), ignoredPathsPlusTrid); } catch (Throwable e) { assertXmlEquals( - xml, new String(marshal(eppOutput, ValidationMode.LENIENT), UTF_8), ignoredPaths); + xml, new String(marshal(output, ValidationMode.LENIENT), UTF_8), ignoredPathsPlusTrid); // If it was a marshaling error, augment the output. throw new Exception( String.format( "Invalid xml.\nExpected:\n%s\n\nActual:\n%s\n", xml, - marshal(eppOutput, ValidationMode.LENIENT)), + marshal(output, ValidationMode.LENIENT)), e); } // Clear the cache so that we don't see stale results in tests. diff --git a/javatests/google/registry/flows/contact/ContactTransferRequestFlowTest.java b/javatests/google/registry/flows/contact/ContactTransferRequestFlowTest.java index 3f0e511b1..3f2418878 100644 --- a/javatests/google/registry/flows/contact/ContactTransferRequestFlowTest.java +++ b/javatests/google/registry/flows/contact/ContactTransferRequestFlowTest.java @@ -71,7 +71,7 @@ public class ContactTransferRequestFlowTest .hasTransferStatus(TransferStatus.PENDING).and() .hasTransferGainingClientId("NewRegistrar").and() .hasTransferLosingClientId("TheRegistrar").and() - .hasTransferRequestTrid(getTrid()).and() + .hasTransferRequestClientTrid(getClientTrid()).and() .hasCurrentSponsorClientId("TheRegistrar").and() .hasPendingTransferExpirationTime(afterTransfer).and() .hasOnlyOneHistoryEntryWhich() diff --git a/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java index b0935a846..14584b8f7 100644 --- a/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -64,7 +64,6 @@ import google.registry.model.domain.GracePeriod; import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.eppcommon.AuthInfo.PasswordAuth; import google.registry.model.eppcommon.StatusValue; -import google.registry.model.eppcommon.Trid; import google.registry.model.poll.PendingActionNotificationResponse; import google.registry.model.poll.PollMessage; import google.registry.model.registrar.Registrar; @@ -95,7 +94,7 @@ public class DomainTransferRequestFlowTest .hasTransferStatus(TransferStatus.PENDING).and() .hasTransferGainingClientId("NewRegistrar").and() .hasTransferLosingClientId("TheRegistrar").and() - .hasTransferRequestTrid(getTrid()).and() + .hasTransferRequestClientTrid(getClientTrid()).and() .hasCurrentSponsorClientId("TheRegistrar").and() .hasPendingTransferExpirationTime( clock.nowUtc().plus(Registry.get("tld").getAutomaticTransferLength())).and() @@ -228,8 +227,7 @@ public class DomainTransferRequestFlowTest PendingActionNotificationResponse panData = Iterables.getOnlyElement(FluentIterable .from(transferApprovedPollMessage.getResponseData()) .filter(PendingActionNotificationResponse.class)); - assertThat(panData.getTrid()) - .isEqualTo(Trid.create("ABC-12345", "server-trid")); + assertThat(panData.getTrid().getClientTransactionId()).isEqualTo("ABC-12345"); assertThat(panData.getActionResult()).isTrue(); // Two poll messages on the losing registrar's side at the implicit transfer time: a diff --git a/javatests/google/registry/model/testdata/domain_create.xml b/javatests/google/registry/flows/testdata/domain_create.xml similarity index 100% rename from javatests/google/registry/model/testdata/domain_create.xml rename to javatests/google/registry/flows/testdata/domain_create.xml diff --git a/javatests/google/registry/flows/testdata/domain_create_no_hosts_or_dsdata.xml b/javatests/google/registry/flows/testdata/domain_create_no_hosts_or_dsdata.xml index 88c822e7e..41c6a586e 100644 --- a/javatests/google/registry/flows/testdata/domain_create_no_hosts_or_dsdata.xml +++ b/javatests/google/registry/flows/testdata/domain_create_no_hosts_or_dsdata.xml @@ -3,7 +3,7 @@ - example.example + example.tld 2 jd1234 sh8013 diff --git a/javatests/google/registry/flows/testdata/domain_create_response.xml b/javatests/google/registry/flows/testdata/domain_create_response.xml index 35c386ba7..6df6fd6ab 100644 --- a/javatests/google/registry/flows/testdata/domain_create_response.xml +++ b/javatests/google/registry/flows/testdata/domain_create_response.xml @@ -6,7 +6,7 @@ - example.example + example.tld 2000-06-01T00:02:00.0Z 2002-06-01T00:02:00.0Z diff --git a/javatests/google/registry/flows/testdata/domain_delete.xml b/javatests/google/registry/flows/testdata/domain_delete.xml index 0ef1a47d1..a0f5cc345 100644 --- a/javatests/google/registry/flows/testdata/domain_delete.xml +++ b/javatests/google/registry/flows/testdata/domain_delete.xml @@ -3,7 +3,7 @@ - example.example + example.tld ABC-12345 diff --git a/javatests/google/registry/flows/testdata/domain_info.xml b/javatests/google/registry/flows/testdata/domain_info.xml index e32700d25..15a31a9d1 100644 --- a/javatests/google/registry/flows/testdata/domain_info.xml +++ b/javatests/google/registry/flows/testdata/domain_info.xml @@ -3,7 +3,7 @@ - example.example + example.tld ABC-12345 diff --git a/javatests/google/registry/flows/testdata/domain_info_response_pendingdelete.xml b/javatests/google/registry/flows/testdata/domain_info_response_pendingdelete.xml index 46b2737a8..8471fda0b 100644 --- a/javatests/google/registry/flows/testdata/domain_info_response_pendingdelete.xml +++ b/javatests/google/registry/flows/testdata/domain_info_response_pendingdelete.xml @@ -7,7 +7,7 @@ - example.example + example.tld %ROID% diff --git a/javatests/google/registry/model/testdata/domain_update_dsdata_add.xml b/javatests/google/registry/flows/testdata/domain_update_dsdata_add.xml similarity index 100% rename from javatests/google/registry/model/testdata/domain_update_dsdata_add.xml rename to javatests/google/registry/flows/testdata/domain_update_dsdata_add.xml diff --git a/javatests/google/registry/model/testdata/domain_update_dsdata_rem.xml b/javatests/google/registry/flows/testdata/domain_update_dsdata_rem.xml similarity index 100% rename from javatests/google/registry/model/testdata/domain_update_dsdata_rem.xml rename to javatests/google/registry/flows/testdata/domain_update_dsdata_rem.xml diff --git a/javatests/google/registry/flows/testdata/domain_update_restore_request.xml b/javatests/google/registry/flows/testdata/domain_update_restore_request.xml index 85a294e98..124bc0b89 100644 --- a/javatests/google/registry/flows/testdata/domain_update_restore_request.xml +++ b/javatests/google/registry/flows/testdata/domain_update_restore_request.xml @@ -3,7 +3,7 @@ - example.example + example.tld diff --git a/javatests/google/registry/flows/testdata/poll_response_domain_transfer_request.xml b/javatests/google/registry/flows/testdata/poll_response_domain_transfer_request.xml index 472dd18b7..cb8a34b05 100644 --- a/javatests/google/registry/flows/testdata/poll_response_domain_transfer_request.xml +++ b/javatests/google/registry/flows/testdata/poll_response_domain_transfer_request.xml @@ -3,7 +3,7 @@ Command completed successfully; ack to dequeue - + 2001-01-01T00:00:00Z Transfer requested. diff --git a/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_loser.xml b/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_loser.xml index 640babb06..851c9dc3a 100644 --- a/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_loser.xml +++ b/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_loser.xml @@ -3,7 +3,7 @@ Command completed successfully; ack to dequeue - + 2001-01-06T00:00:00Z Transfer approved. diff --git a/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_winner.xml b/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_winner.xml index ed2c57b8e..ce140c107 100644 --- a/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_winner.xml +++ b/javatests/google/registry/flows/testdata/poll_response_domain_transfer_server_approve_winner.xml @@ -4,7 +4,7 @@ Command completed successfully; ack to dequeue - + 2001-01-06T00:00:00Z Transfer approved. diff --git a/javatests/google/registry/model/EppResourceUtilsTest.java b/javatests/google/registry/model/EppResourceUtilsTest.java index f858a1b6c..095530c85 100644 --- a/javatests/google/registry/model/EppResourceUtilsTest.java +++ b/javatests/google/registry/model/EppResourceUtilsTest.java @@ -15,35 +15,19 @@ package google.registry.model; import static com.google.common.truth.Truth.assertThat; -import static google.registry.flows.picker.FlowPicker.getFlowClass; import static google.registry.model.EppResourceUtils.loadAtPointInTime; -import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.newHostResource; -import static google.registry.testing.DatastoreHelper.persistActiveContact; -import static google.registry.testing.DatastoreHelper.persistActiveHost; import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.testing.DatastoreHelper.persistResourceWithCommitLog; import static google.registry.util.DateTimeUtils.START_OF_TIME; import static org.joda.time.DateTimeZone.UTC; -import static org.joda.time.Duration.standardDays; -import com.googlecode.objectify.Key; - -import google.registry.flows.EppRequestSource; -import google.registry.flows.FlowRunner; -import google.registry.flows.HttpSessionMetadata; -import google.registry.flows.PasswordOnlyTransportCredentials; -import google.registry.flows.SessionMetadata; -import google.registry.model.domain.DomainResource; -import google.registry.model.eppcommon.Trid; import google.registry.model.host.HostResource; import google.registry.model.ofy.Ofy; import google.registry.testing.AppEngineRule; -import google.registry.testing.EppLoader; import google.registry.testing.ExceptionRule; import google.registry.testing.FakeClock; -import google.registry.testing.FakeHttpSession; import google.registry.testing.InjectRule; import org.joda.time.DateTime; @@ -71,7 +55,6 @@ public class EppResourceUtilsTest { public final InjectRule inject = new InjectRule(); private final FakeClock clock = new FakeClock(DateTime.now(UTC)); - private EppLoader eppLoader; @Before public void init() throws Exception { @@ -79,103 +62,6 @@ public class EppResourceUtilsTest { inject.setStaticField(Ofy.class, "clock", clock); } - private void runFlow() throws Exception { - SessionMetadata sessionMetadata = new HttpSessionMetadata(new FakeHttpSession()); - sessionMetadata.setClientId("TheRegistrar"); - new FlowRunner( - getFlowClass(eppLoader.getEpp()), - eppLoader.getEpp(), - Trid.create(null, "server-trid"), - sessionMetadata, - new PasswordOnlyTransportCredentials(), - EppRequestSource.UNIT_TEST, - false, - false, - "".getBytes(), - null, - clock) - .run(); - } - - /** Test that update flow creates commit logs needed to reload at any arbitrary time. */ - @Test - public void testLoadAtPointInTime() throws Exception { - clock.setTo(DateTime.parse("1984-12-18T12:30Z")); // not midnight - - persistActiveHost("ns1.example.net"); - persistActiveHost("ns2.example.net"); - persistActiveContact("jd1234"); - persistActiveContact("sh8013"); - - clock.advanceBy(standardDays(1)); - DateTime timeAtCreate = clock.nowUtc(); - clock.setTo(timeAtCreate); - eppLoader = new EppLoader(this, "domain_create.xml"); - runFlow(); - ofy().clearSessionCache(); - Key key = Key.create(ofy().load().type(DomainResource.class).first().now()); - DomainResource domainAfterCreate = ofy().load().key(key).now(); - assertThat(domainAfterCreate.getFullyQualifiedDomainName()).isEqualTo("example.tld"); - - clock.advanceBy(standardDays(2)); - DateTime timeAtFirstUpdate = clock.nowUtc(); - eppLoader = new EppLoader(this, "domain_update_dsdata_add.xml"); - runFlow(); - ofy().clearSessionCache(); - - DomainResource domainAfterFirstUpdate = ofy().load().key(key).now(); - assertThat(domainAfterCreate).isNotEqualTo(domainAfterFirstUpdate); - - clock.advanceOneMilli(); // same day as first update - DateTime timeAtSecondUpdate = clock.nowUtc(); - eppLoader = new EppLoader(this, "domain_update_dsdata_rem.xml"); - runFlow(); - ofy().clearSessionCache(); - DomainResource domainAfterSecondUpdate = ofy().load().key(key).now(); - - clock.advanceBy(standardDays(2)); - DateTime timeAtDelete = clock.nowUtc(); // before 'add' grace period ends - eppLoader = new EppLoader(this, "domain_delete.xml"); - runFlow(); - ofy().clearSessionCache(); - - assertThat(domainAfterFirstUpdate).isNotEqualTo(domainAfterSecondUpdate); - - // Point-in-time can only rewind an object from the current version, not roll forward. - DomainResource latest = ofy().load().key(key).now(); - - // Creation time has millisecond granularity due to isActive() check. - ofy().clearSessionCache(); - assertThat(loadAtPointInTime(latest, timeAtCreate.minusMillis(1)).now()).isNull(); - assertThat(loadAtPointInTime(latest, timeAtCreate).now()).isNotNull(); - assertThat(loadAtPointInTime(latest, timeAtCreate.plusMillis(1)).now()).isNotNull(); - - ofy().clearSessionCache(); - assertThat(loadAtPointInTime(latest, timeAtCreate.plusDays(1)).now()) - .isEqualTo(domainAfterCreate); - - // Both updates happened on the same day. Since the revisions field has day granularity, the - // reference to the first update should have been overwritten by the second, and its timestamp - // rolled forward. So we have to fall back to the last revision before midnight. - ofy().clearSessionCache(); - assertThat(loadAtPointInTime(latest, timeAtFirstUpdate).now()) - .isEqualTo(domainAfterCreate); - - ofy().clearSessionCache(); - assertThat(loadAtPointInTime(latest, timeAtSecondUpdate).now()) - .isEqualTo(domainAfterSecondUpdate); - - ofy().clearSessionCache(); - assertThat(loadAtPointInTime(latest, timeAtSecondUpdate.plusDays(1)).now()) - .isEqualTo(domainAfterSecondUpdate); - - // Deletion time has millisecond granularity due to isActive() check. - ofy().clearSessionCache(); - assertThat(loadAtPointInTime(latest, timeAtDelete.minusMillis(1)).now()).isNotNull(); - assertThat(loadAtPointInTime(latest, timeAtDelete).now()).isNull(); - assertThat(loadAtPointInTime(latest, timeAtDelete.plusMillis(1)).now()).isNull(); - } - @Test public void testLoadAtPointInTime_beforeCreated_returnsNull() throws Exception { clock.advanceOneMilli(); diff --git a/javatests/google/registry/model/testdata/domain_delete.xml b/javatests/google/registry/model/testdata/domain_delete.xml deleted file mode 100644 index a0f5cc345..000000000 --- a/javatests/google/registry/model/testdata/domain_delete.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - example.tld - - - ABC-12345 - - diff --git a/javatests/google/registry/testing/AbstractEppResourceSubject.java b/javatests/google/registry/testing/AbstractEppResourceSubject.java index bd828f633..3895112af 100644 --- a/javatests/google/registry/testing/AbstractEppResourceSubject.java +++ b/javatests/google/registry/testing/AbstractEppResourceSubject.java @@ -26,7 +26,6 @@ import com.google.common.truth.Subject; import google.registry.model.EppResource; import google.registry.model.eppcommon.StatusValue; -import google.registry.model.eppcommon.Trid; import google.registry.model.reporting.HistoryEntry; import google.registry.model.transfer.TransferStatus; import google.registry.testing.TruthChainer.And; @@ -205,10 +204,10 @@ abstract class AbstractEppResourceSubject "has transferStatus"); } - public And hasTransferRequestTrid(Trid trid) { + public And hasTransferRequestClientTrid(String clTrid) { return hasValue( - trid, - getSubject().getTransferData().getTransferRequestTrid(), + clTrid, + getSubject().getTransferData().getTransferRequestTrid().getClientTransactionId(), "has trid"); }