mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Dagger, meet Flows. Flows, meet Dagger.
Daggerizes all of the EPP flows. This does not change anything yet about the flows themselves, just how they are invoked, but after this CL it's safe to @Inject things into flow classes. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=125382478
This commit is contained in:
parent
116bf1f4d6
commit
c9a16f7f11
69 changed files with 973 additions and 292 deletions
|
@ -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<String> 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());
|
||||
}
|
||||
|
|
35
java/google/registry/flows/FlowComponent.java
Normal file
35
java/google/registry/flows/FlowComponent.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
335
java/google/registry/flows/FlowModule.java
Normal file
335
java/google/registry/flows/FlowModule.java
Normal file
|
@ -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<? extends Flow> 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<Class<? extends Flow>, Provider<? extends Flow>> provideFlowClassMap(
|
||||
Provider<ContactCheckFlow> contactCheckFlowProvider,
|
||||
Provider<ContactCreateFlow> contactCreateFlowProvider,
|
||||
Provider<ContactDeleteFlow> contactDeleteFlowProvider,
|
||||
Provider<ContactInfoFlow> contactInfoFlowProvider,
|
||||
Provider<ContactTransferApproveFlow> contactTransferApproveFlowProvider,
|
||||
Provider<ContactTransferCancelFlow> contactTransferCancelFlowProvider,
|
||||
Provider<ContactTransferQueryFlow> contactTransferQueryFlowProvider,
|
||||
Provider<ContactTransferRejectFlow> contactTransferRejectFlowProvider,
|
||||
Provider<ContactTransferRequestFlow> contactTransferRequestFlowProvider,
|
||||
Provider<ContactUpdateFlow> contactUpdateFlowProvider,
|
||||
Provider<ClaimsCheckFlow> claimsCheckFlowProvider,
|
||||
Provider<DomainAllocateFlow> domainAllocateFlowProvider,
|
||||
Provider<DomainApplicationCreateFlow> domainApplicationCreateFlowProvider,
|
||||
Provider<DomainApplicationDeleteFlow> domainApplicationDeleteFlowProvider,
|
||||
Provider<DomainApplicationInfoFlow> domainApplicationInfoFlowProvider,
|
||||
Provider<DomainApplicationUpdateFlow> domainApplicationUpdateFlowProvider,
|
||||
Provider<DomainCheckFlow> domainCheckFlowProvider,
|
||||
Provider<DomainCreateFlow> domainCreateFlowProvider,
|
||||
Provider<DomainDeleteFlow> domainDeleteFlowProvider,
|
||||
Provider<DomainInfoFlow> domainInfoFlowProvider,
|
||||
Provider<DomainRenewFlow> domainRenewFlowProvider,
|
||||
Provider<DomainRestoreRequestFlow> domainRestoreRequestFlowProvider,
|
||||
Provider<DomainTransferApproveFlow> domainTransferApproveFlowProvider,
|
||||
Provider<DomainTransferCancelFlow> domainTransferCancelFlowProvider,
|
||||
Provider<DomainTransferQueryFlow> domainTransferQueryFlowProvider,
|
||||
Provider<DomainTransferRejectFlow> domainTransferRejectFlowProvider,
|
||||
Provider<DomainTransferRequestFlow> domainTransferRequestFlowProvider,
|
||||
Provider<DomainUpdateFlow> domainUpdateFlowProvider,
|
||||
Provider<HostCheckFlow> hostCheckFlowProvider,
|
||||
Provider<HostCreateFlow> hostCreateFlowProvider,
|
||||
Provider<HostDeleteFlow> hostDeleteFlowProvider,
|
||||
Provider<HostInfoFlow> hostInfoFlowProvider,
|
||||
Provider<HostUpdateFlow> hostUpdateFlowProvider,
|
||||
Provider<PollAckFlow> pollAckFlowProvider,
|
||||
Provider<PollRequestFlow> pollRequestFlowProvider,
|
||||
Provider<HelloFlow> helloFlowProvider,
|
||||
Provider<LoginFlow> loginFlowProvider,
|
||||
Provider<LogoutFlow> logoutFlowProvider) {
|
||||
return new ImmutableMap.Builder<Class<? extends Flow>, Provider<? extends Flow>>()
|
||||
.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<? extends Flow> provideFlowClass(EppInput eppInput) {
|
||||
try {
|
||||
return FlowPicker.getFlowClass(eppInput);
|
||||
} catch (EppException e) {
|
||||
throw new EppExceptionInProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FlowScope
|
||||
static Flow provideFlow(
|
||||
Map<Class<? extends Flow>, Provider<? extends Flow>> flowProviders,
|
||||
Class<? extends Flow> 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 {}
|
||||
}
|
|
@ -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<? extends Flow> 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<? extends Flow> 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<Flow> 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<EppOutput>() {
|
||||
@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.<Flow>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.
|
||||
*
|
||||
|
|
35
java/google/registry/flows/FlowScope.java
Normal file
35
java/google/registry/flows/FlowScope.java
Normal file
|
@ -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.
|
||||
*
|
||||
* <p>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 {}
|
|
@ -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<ContactResource, Check> {
|
||||
|
||||
@Inject ContactCheckFlow() {}
|
||||
|
||||
@Override
|
||||
protected CheckData getCheckData() {
|
||||
Set<String> existingIds = checkResourcesExist(resourceClass, targetIds, now);
|
||||
|
|
|
@ -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<ContactResource, Builder, Create> {
|
||||
|
||||
@Inject ContactCreateFlow() {}
|
||||
|
||||
@Override
|
||||
protected EppOutput getOutput() {
|
||||
return createOutput(Success, ContactCreateData.create(newResource.getContactId(), now));
|
||||
|
|
|
@ -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<ContactResource,
|
|||
/** In {@link #isLinkedForFailfast}, check this (arbitrary) number of resources from the query. */
|
||||
private static final int FAILFAST_CHECK_COUNT = 5;
|
||||
|
||||
@Inject ContactDeleteFlow() {}
|
||||
|
||||
@Override
|
||||
protected boolean isLinkedForFailfast(final Ref<ContactResource> ref) {
|
||||
// Query for the first few linked domains, and if found, actually load them. The query is
|
||||
|
|
|
@ -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<ContactResource, Info> {}
|
||||
public class ContactInfoFlow extends ResourceInfoFlow<ContactResource, Info> {
|
||||
@Inject ContactInfoFlow() {}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ContactResource, Builder, Transfer> {
|
||||
|
||||
@Inject ContactTransferApproveFlow() {}
|
||||
|
||||
@Override
|
||||
protected final HistoryEntry.Type getHistoryEntryType() {
|
||||
return HistoryEntry.Type.CONTACT_TRANSFER_APPROVE;
|
||||
|
|
|
@ -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<ContactResource, Builder, Transfer> {
|
||||
|
||||
@Inject ContactTransferCancelFlow() {}
|
||||
|
||||
@Override
|
||||
protected final HistoryEntry.Type getHistoryEntryType() {
|
||||
return HistoryEntry.Type.CONTACT_TRANSFER_CANCEL;
|
||||
|
|
|
@ -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<ContactResource, Transfer> {
|
||||
@Inject ContactTransferQueryFlow() {}
|
||||
}
|
||||
|
|
|
@ -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<ContactResource, Builder, Transfer> {
|
||||
|
||||
@Inject ContactTransferRejectFlow() {}
|
||||
|
||||
@Override
|
||||
protected final HistoryEntry.Type getHistoryEntryType() {
|
||||
return HistoryEntry.Type.CONTACT_TRANSFER_REJECT;
|
||||
|
|
|
@ -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<ContactResource, Transfer> {
|
||||
|
||||
@Inject ContactTransferRequestFlow() {}
|
||||
|
||||
@Override
|
||||
protected final HistoryEntry.Type getHistoryEntryType() {
|
||||
return HistoryEntry.Type.CONTACT_TRANSFER_REQUEST;
|
||||
|
|
|
@ -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<ContactResource, Builder, Update> {
|
||||
|
||||
@Inject ContactUpdateFlow() {}
|
||||
|
||||
@Override
|
||||
protected void verifyNewUpdatedStateIsAllowed() throws EppException {
|
||||
validateAsciiPostalInfo(newResource.getInternationalizedPostalInfo());
|
||||
|
|
|
@ -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<TldState> DISALLOWED_TLD_STATES = Sets.immutableEnumSet(
|
||||
TldState.PREDELEGATION, TldState.SUNRISE);
|
||||
|
||||
@Inject ClaimsCheckFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initDomainCheckFlow() throws EppException {
|
||||
registerExtensions(LaunchCheckExtension.class);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<DomainApplication, Builder> {
|
||||
|
||||
@Inject DomainApplicationCreateFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initDomainCreateFlow() {
|
||||
registerExtensions(FeeCreateExtension.class, LaunchCreateExtension.class);
|
||||
|
|
|
@ -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<DomainApplication, Builder, Delete> {
|
||||
|
||||
@Inject DomainApplicationDeleteFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initResourceCreateOrMutateFlow() throws EppException {
|
||||
registerExtensions(LaunchDeleteExtension.class);
|
||||
|
|
|
@ -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<DomainApplicat
|
|||
|
||||
private boolean includeMarks;
|
||||
|
||||
@Inject DomainApplicationInfoFlow() {}
|
||||
|
||||
@Override
|
||||
protected final void initSingleResourceFlow() throws EppException {
|
||||
registerExtensions(LaunchInfoExtension.class);
|
||||
|
|
|
@ -30,6 +30,8 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
|||
import google.registry.model.registry.Registry.TldState;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that updates a domain resource.
|
||||
*
|
||||
|
@ -59,6 +61,8 @@ import google.registry.model.reporting.HistoryEntry;
|
|||
public class DomainApplicationUpdateFlow
|
||||
extends BaseDomainUpdateFlow<DomainApplication, Builder> {
|
||||
|
||||
@Inject DomainApplicationUpdateFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initDomainUpdateFlow() throws EppException {
|
||||
registerExtensions(LaunchUpdateExtension.class, SecDnsUpdateExtension.class);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<DomainResource, Bui
|
|||
|
||||
ImmutableList<Credit> credits;
|
||||
|
||||
@Inject DomainDeleteFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initResourceCreateOrMutateFlow() throws EppException {
|
||||
registerExtensions(SecDnsUpdateExtension.class);
|
||||
|
|
|
@ -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<DomainResource, Builder>
|
|||
|
||||
protected List<String> registrationTypes;
|
||||
|
||||
@Inject DomainInfoFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initSingleResourceFlow() throws EppException {
|
||||
registerExtensions(FeeInfoExtension.class);
|
||||
|
|
|
@ -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<DomainResource, Ren
|
|||
protected FeeRenewExtension feeRenew;
|
||||
protected Money renewCost;
|
||||
|
||||
@Inject DomainRenewFlow() {}
|
||||
|
||||
@Override
|
||||
protected Set<StatusValue> getDisallowedStatuses() {
|
||||
return RENEW_DISALLOWED_STATUSES;
|
||||
|
|
|
@ -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<DomainReso
|
|||
protected Money restoreCost;
|
||||
protected Money renewCost;
|
||||
|
||||
@Inject DomainRestoreRequestFlow() {}
|
||||
|
||||
@Override
|
||||
protected final void initResourceCreateOrMutateFlow() throws EppException {
|
||||
registerExtensions(FeeUpdateExtension.class, RgpUpdateExtension.class);
|
||||
|
|
|
@ -45,6 +45,8 @@ import google.registry.model.transfer.TransferData;
|
|||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that approves a pending transfer on a {@link DomainResource}.
|
||||
*
|
||||
|
@ -60,6 +62,8 @@ import org.joda.time.DateTime;
|
|||
public class DomainTransferApproveFlow extends
|
||||
ResourceTransferApproveFlow<DomainResource, Builder, Transfer> {
|
||||
|
||||
@Inject DomainTransferApproveFlow() {}
|
||||
|
||||
@Override
|
||||
protected void verifyOwnedResourcePendingTransferMutationAllowed() throws EppException {
|
||||
checkAllowedAccessToTld(getAllowedTlds(), existingResource.getTld());
|
||||
|
|
|
@ -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<DomainResource, Builder, Transfer> {
|
||||
|
||||
@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
|
||||
|
|
|
@ -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<DomainResource, Transfer> {}
|
||||
public class DomainTransferQueryFlow extends ResourceTransferQueryFlow<DomainResource, Transfer> {
|
||||
@Inject DomainTransferQueryFlow() {}
|
||||
}
|
||||
|
|
|
@ -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<DomainResource, Builder, Transfer> {
|
||||
|
||||
@Inject DomainTransferRejectFlow() {}
|
||||
|
||||
@Override
|
||||
protected void verifyOwnedResourcePendingTransferMutationAllowed() throws EppException {
|
||||
checkAllowedAccessToTld(getAllowedTlds(), existingResource.getTld());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<DomainResource, Build
|
|||
|
||||
protected RegTypeUpdateExtension regTypeExtension;
|
||||
|
||||
@Inject DomainUpdateFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initDomainUpdateFlow() {
|
||||
registerExtensions(SecDnsUpdateExtension.class, RegTypeUpdateExtension.class);
|
||||
|
|
|
@ -27,12 +27,17 @@ import google.registry.model.host.HostResource;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow that checks whether a host can be provisioned.
|
||||
*
|
||||
* @error {@link google.registry.flows.ResourceCheckFlow.TooManyResourceChecksException}
|
||||
*/
|
||||
public class HostCheckFlow extends ResourceCheckFlow<HostResource, Check> {
|
||||
|
||||
@Inject HostCheckFlow() {}
|
||||
|
||||
@Override
|
||||
protected CheckData getCheckData() {
|
||||
Set<String> existingIds = checkResourcesExist(resourceClass, targetIds, now);
|
||||
|
|
|
@ -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<HostResource, Builder, Cr
|
|||
*/
|
||||
private Optional<Ref<DomainResource>> superordinateDomain;
|
||||
|
||||
@Inject HostCreateFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initResourceCreateOrMutateFlow() throws EppException {
|
||||
superordinateDomain = Optional.fromNullable(lookupSuperordinateDomain(
|
||||
|
|
|
@ -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<HostResource, Builde
|
|||
/** In {@link #isLinkedForFailfast}, check this (arbitrary) number of resources from the query. */
|
||||
private static final int FAILFAST_CHECK_COUNT = 5;
|
||||
|
||||
@Inject HostDeleteFlow() {}
|
||||
|
||||
@Override
|
||||
protected boolean isLinkedForFailfast(final Ref<HostResource> ref) {
|
||||
// Query for the first few linked domains, and if found, actually load them. The query is
|
||||
|
|
|
@ -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<HostResource, HostCommand.Info> {}
|
||||
public class HostInfoFlow extends ResourceInfoFlow<HostResource, HostCommand.Info> {
|
||||
@Inject HostInfoFlow() {}
|
||||
}
|
||||
|
|
|
@ -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<HostResource, Builder, Up
|
|||
private String newHostName;
|
||||
private boolean isHostRename;
|
||||
|
||||
@Inject HostUpdateFlow() {}
|
||||
|
||||
@Override
|
||||
protected void initResourceCreateOrMutateFlow() throws EppException {
|
||||
String suppliedNewHostName = command.getInnerChange().getFullyQualifiedHostName();
|
||||
|
|
|
@ -35,6 +35,8 @@ import google.registry.model.poll.PollMessageExternalKeyConverter.PollMessageExt
|
|||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow for acknowledging poll messages.
|
||||
*
|
||||
|
@ -45,6 +47,8 @@ import org.joda.time.DateTime;
|
|||
*/
|
||||
public class PollAckFlow extends PollFlow implements TransactionalFlow {
|
||||
|
||||
@Inject PollAckFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppOutput run() throws EppException {
|
||||
if (command.getMessageId() == null) {
|
||||
|
|
|
@ -29,6 +29,8 @@ import google.registry.model.poll.PollMessage;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow for requesting poll messages.
|
||||
*
|
||||
|
@ -36,6 +38,8 @@ import java.util.List;
|
|||
*/
|
||||
public class PollRequestFlow extends PollFlow {
|
||||
|
||||
@Inject PollRequestFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppOutput run() throws EppException {
|
||||
if (command.getMessageId() != null) {
|
||||
|
|
|
@ -18,8 +18,13 @@ import google.registry.flows.Flow;
|
|||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.Greeting;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** A flow for an Epp "hello". */
|
||||
public class HelloFlow extends Flow {
|
||||
|
||||
@Inject HelloFlow() {}
|
||||
|
||||
@Override
|
||||
public EppOutput run() {
|
||||
return EppOutput.create(Greeting.create(now));
|
||||
|
|
|
@ -41,6 +41,8 @@ import google.registry.util.FormattingLogger;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow for login.
|
||||
*
|
||||
|
@ -68,6 +70,8 @@ public class LoginFlow extends Flow {
|
|||
/** Maximum number of failed login attempts allowed per connection. */
|
||||
private static final int MAX_FAILED_LOGIN_ATTEMPTS_PER_CONNECTION = 3;
|
||||
|
||||
@Inject LoginFlow() {}
|
||||
|
||||
/** Run the flow and log errors. */
|
||||
@Override
|
||||
public final EppOutput run() throws EppException {
|
||||
|
|
|
@ -20,12 +20,17 @@ import google.registry.flows.EppException;
|
|||
import google.registry.flows.LoggedInFlow;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An EPP flow for logout.
|
||||
*
|
||||
* @error {@link google.registry.flows.LoggedInFlow.NotLoggedInException}
|
||||
*/
|
||||
public class LogoutFlow extends LoggedInFlow {
|
||||
|
||||
@Inject LogoutFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppOutput run() throws EppException {
|
||||
sessionMetadata.invalidate();
|
||||
|
|
|
@ -20,6 +20,7 @@ import google.registry.flows.CheckApiAction;
|
|||
import google.registry.flows.CheckApiAction.CheckApiModule;
|
||||
import google.registry.flows.EppConsoleAction;
|
||||
import google.registry.flows.EppTlsAction;
|
||||
import google.registry.flows.FlowComponent;
|
||||
import google.registry.flows.TlsCredentials.EppTlsModule;
|
||||
import google.registry.rdap.RdapAutnumAction;
|
||||
import google.registry.rdap.RdapDomainAction;
|
||||
|
@ -57,6 +58,7 @@ interface FrontendRequestComponent {
|
|||
ConsoleUiAction consoleUiAction();
|
||||
EppConsoleAction eppConsoleAction();
|
||||
EppTlsAction eppTlsAction();
|
||||
FlowComponent.Builder flowComponentBuilder();
|
||||
RdapAutnumAction rdapAutnumAction();
|
||||
RegistrarPaymentAction registrarPaymentAction();
|
||||
RegistrarPaymentSetupAction registrarPaymentSetupAction();
|
||||
|
|
|
@ -19,6 +19,7 @@ import dagger.Subcomponent;
|
|||
import google.registry.export.PublishDetailReportAction;
|
||||
import google.registry.flows.EppToolAction;
|
||||
import google.registry.flows.EppToolAction.EppToolModule;
|
||||
import google.registry.flows.FlowComponent;
|
||||
import google.registry.loadtest.LoadTestAction;
|
||||
import google.registry.loadtest.LoadTestModule;
|
||||
import google.registry.mapreduce.MapreduceModule;
|
||||
|
@ -62,6 +63,7 @@ interface ToolsRequestComponent {
|
|||
DeleteEntityAction deleteEntityAction();
|
||||
DeleteProberDataAction deleteProberDataAction();
|
||||
EppToolAction eppToolAction();
|
||||
FlowComponent.Builder flowComponentBuilder();
|
||||
GenerateZoneFilesAction generateZoneFilesAction();
|
||||
KillAllCommitLogsAction killAllCommitLogsAction();
|
||||
KillAllEppResourcesAction killAllEppResourcesAction();
|
||||
|
|
|
@ -31,6 +31,7 @@ java_library(
|
|||
"//java/com/google/common/net",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/appengine:appengine-testing",
|
||||
"//third_party/java/dagger",
|
||||
"//third_party/java/joda_money",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/json_simple",
|
||||
|
|
|
@ -19,17 +19,16 @@ import static google.registry.testing.DatastoreHelper.createTld;
|
|||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistReservedList;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.flows.EppTestComponent.FakesAndMocksModule;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.monitoring.whitebox.EppMetrics;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.util.SystemClock;
|
||||
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Before;
|
||||
|
@ -66,9 +65,11 @@ public class CheckApiActionTest {
|
|||
action.domain = domain;
|
||||
action.response = new FakeResponse();
|
||||
action.config = RegistryEnvironment.UNITTEST.config();
|
||||
action.eppController = new EppController();
|
||||
action.eppController.clock = new SystemClock();
|
||||
action.eppController.metrics = mock(EppMetrics.class);
|
||||
action.eppController = DaggerEppTestComponent.builder()
|
||||
.fakesAndMocksModule(new FakesAndMocksModule(new FakeClock()))
|
||||
.build()
|
||||
.startRequest()
|
||||
.eppController();
|
||||
action.run();
|
||||
return (Map<String, Object>) JSONValue.parse(((FakeResponse) action.response).getPayload());
|
||||
}
|
||||
|
|
171
javatests/google/registry/flows/EppCommitLogsTest.java
Normal file
171
javatests/google/registry/flows/EppCommitLogsTest.java
Normal file
|
@ -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<DomainResource> 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();
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
|
|
|
@ -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);
|
||||
|
|
70
javatests/google/registry/flows/EppTestComponent.java
Normal file
70
javatests/google/registry/flows/EppTestComponent.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<F extends Flow> {
|
|||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
private Class<? extends Flow> flowClass;
|
||||
|
||||
protected EppLoader eppLoader;
|
||||
protected SessionMetadata sessionMetadata;
|
||||
protected FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
|
@ -120,29 +117,8 @@ public abstract class FlowTestCase<F extends Flow> {
|
|||
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<F>(getClass()){}.getExactType();
|
||||
assertThat(flowClass).isEqualTo(expectedFlowClass);
|
||||
return new FlowRunner(
|
||||
flowClass,
|
||||
eppInput,
|
||||
getTrid(),
|
||||
sessionMetadata,
|
||||
credentials,
|
||||
eppRequestSource,
|
||||
commitMode.equals(CommitMode.DRY_RUN),
|
||||
userPrivileges.equals(UserPrivileges.SUPERUSER),
|
||||
"<xml></xml>".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<F extends Flow> {
|
|||
}
|
||||
|
||||
public void assertTransactionalFlow(boolean isTransactional) throws Exception {
|
||||
assertThat(getFlowRunner(CommitMode.LIVE, UserPrivileges.NORMAL).isTransactional())
|
||||
.isEqualTo(isTransactional);
|
||||
Class<? extends Flow> 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<F extends Flow> {
|
|||
.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<F>(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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<create>
|
||||
<domain:create
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.example</domain:name>
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:period unit="y">2</domain:period>
|
||||
<domain:registrant>jd1234</domain:registrant>
|
||||
<domain:contact type="admin">sh8013</domain:contact>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<resData>
|
||||
<domain:creData
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.example</domain:name>
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:crDate>2000-06-01T00:02:00.0Z</domain:crDate>
|
||||
<domain:exDate>2002-06-01T00:02:00.0Z</domain:exDate>
|
||||
</domain:creData>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<delete>
|
||||
<domain:delete
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.example</domain:name>
|
||||
<domain:name>example.tld</domain:name>
|
||||
</domain:delete>
|
||||
</delete>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<info>
|
||||
<domain:info
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name hosts="all">example.example</domain:name>
|
||||
<domain:name hosts="all">example.tld</domain:name>
|
||||
</domain:info>
|
||||
</info>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<resData>
|
||||
<domain:infData
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.example</domain:name>
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:roid>%ROID%</domain:roid>
|
||||
<domain:status s="inactive"/>
|
||||
<domain:status s="pendingDelete"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.example</domain:name>
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:chg/>
|
||||
</domain:update>
|
||||
</update>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<result code="1301">
|
||||
<msg>Command completed successfully; ack to dequeue</msg>
|
||||
</result>
|
||||
<msgQ count="1" id="1-A-EXAMPLE-16-20">
|
||||
<msgQ count="1" id="1-B-EXAMPLE-17-21">
|
||||
<qDate>2001-01-01T00:00:00Z</qDate>
|
||||
<msg>Transfer requested.</msg>
|
||||
</msgQ>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<result code="1301">
|
||||
<msg>Command completed successfully; ack to dequeue</msg>
|
||||
</result>
|
||||
<msgQ count="1" id="1-A-EXAMPLE-16-22">
|
||||
<msgQ count="1" id="1-B-EXAMPLE-17-23">
|
||||
<qDate>2001-01-06T00:00:00Z</qDate>
|
||||
<msg>Transfer approved.</msg>
|
||||
</msgQ>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<result code="1301">
|
||||
<msg>Command completed successfully; ack to dequeue</msg>
|
||||
</result>
|
||||
<msgQ count="1" id="1-A-EXAMPLE-16-21">
|
||||
<msgQ count="1" id="1-B-EXAMPLE-17-22">
|
||||
<qDate>2001-01-06T00:00:00Z</qDate>
|
||||
<msg>Transfer approved.</msg>
|
||||
</msgQ>
|
||||
|
|
|
@ -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,
|
||||
"<xml></xml>".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<DomainResource> 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();
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<delete>
|
||||
<domain:delete
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
</domain:delete>
|
||||
</delete>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -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<S> hasTransferRequestTrid(Trid trid) {
|
||||
public And<S> hasTransferRequestClientTrid(String clTrid) {
|
||||
return hasValue(
|
||||
trid,
|
||||
getSubject().getTransferData().getTransferRequestTrid(),
|
||||
clTrid,
|
||||
getSubject().getTransferData().getTransferRequestTrid().getClientTransactionId(),
|
||||
"has trid");
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue