Improve handling of lastSubordinateChange and beef up tests

See [] for the comments that led to this.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=147796087
This commit is contained in:
cgoldfeder 2017-02-16 18:54:16 -08:00 committed by Ben McIlwain
parent be30ecdf66
commit c23bbe35bb
5 changed files with 159 additions and 124 deletions

View file

@ -128,9 +128,10 @@ public final class HostUpdateFlow implements TransactionalFlow {
boolean isHostRename = suppliedNewHostName != null; boolean isHostRename = suppliedNewHostName != null;
String oldHostName = targetId; String oldHostName = targetId;
String newHostName = firstNonNull(suppliedNewHostName, oldHostName); String newHostName = firstNonNull(suppliedNewHostName, oldHostName);
Optional<DomainResource> superordinateDomain = // Note that lookupSuperordinateDomain calls cloneProjectedAtTime on the domain for us.
Optional<DomainResource> newSuperordinateDomain =
Optional.fromNullable(lookupSuperordinateDomain(validateHostName(newHostName), now)); Optional.fromNullable(lookupSuperordinateDomain(validateHostName(newHostName), now));
verifyUpdateAllowed(command, existingHost, superordinateDomain.orNull()); verifyUpdateAllowed(command, existingHost, newSuperordinateDomain.orNull());
if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) { if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) {
throw new HostAlreadyExistsException(newHostName); throw new HostAlreadyExistsException(newHostName);
} }
@ -138,6 +139,13 @@ public final class HostUpdateFlow implements TransactionalFlow {
AddRemove remove = command.getInnerRemove(); AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues()); checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses()); checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses());
Key<DomainResource> newSuperordinateDomainKey =
newSuperordinateDomain.isPresent() ? Key.create(newSuperordinateDomain.get()) : null;
// If the superordinateDomain field is changing, set the lastSuperordinateChange to now.
DateTime lastSuperordinateChange =
Objects.equals(newSuperordinateDomainKey, existingHost.getSuperordinateDomain())
? existingHost.getLastSuperordinateChange()
: now;
HostResource newHost = existingHost.asBuilder() HostResource newHost = existingHost.asBuilder()
.setFullyQualifiedHostName(newHostName) .setFullyQualifiedHostName(newHostName)
.addStatusValues(add.getStatusValues()) .addStatusValues(add.getStatusValues())
@ -146,12 +154,8 @@ public final class HostUpdateFlow implements TransactionalFlow {
.removeInetAddresses(remove.getInetAddresses()) .removeInetAddresses(remove.getInetAddresses())
.setLastEppUpdateTime(now) .setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId) .setLastEppUpdateClientId(clientId)
// The superordinateDomain can be missing if the new name is external. .setSuperordinateDomain(newSuperordinateDomainKey)
// Note that the value of superordinateDomain is projected to the current time inside of .setLastSuperordinateChange(lastSuperordinateChange)
// the lookupSuperordinateDomain(...) call above, so that it will never be stale.
.setSuperordinateDomain(
superordinateDomain.isPresent() ? Key.create(superordinateDomain.get()) : null)
.setLastSuperordinateChange(superordinateDomain.isPresent() ? now : null)
.build() .build()
// Rely on the host's cloneProjectedAtTime() method to handle setting of transfer data. // Rely on the host's cloneProjectedAtTime() method to handle setting of transfer data.
.cloneProjectedAtTime(now); .cloneProjectedAtTime(now);

View file

@ -85,8 +85,11 @@ public class HostResource extends EppResource implements ForeignKeyedEppResource
DateTime lastTransferTime; DateTime lastTransferTime;
/** /**
* The most recent time that the superordinate domain was changed, or null if this host is * The most recent time that the {@link #superordinateDomain} field was changed.
* external. *
* <p>This should be updated whenever the superordinate domain changes, including when it is set
* to null. This field will be null for new hosts that have never experienced a change of
* superordinate domain.
*/ */
DateTime lastSuperordinateChange; DateTime lastSuperordinateChange;

View file

@ -15,7 +15,7 @@
package google.registry.flows.host; package google.registry.flows.host;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents; import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistActiveDomain; import static google.registry.testing.DatastoreHelper.persistActiveDomain;
@ -27,6 +27,7 @@ import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
import google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException; import google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.exceptions.ResourceAlreadyExistsException; import google.registry.flows.exceptions.ResourceAlreadyExistsException;
@ -39,6 +40,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException; import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException; import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException; import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
import google.registry.model.domain.DomainResource;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -80,6 +82,7 @@ public class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Hos
runFlowAssertResponse(readFile("host_create_response.xml")); runFlowAssertResponse(readFile("host_create_response.xml"));
// Check that the host was created and persisted with a history entry. // Check that the host was created and persisted with a history entry.
assertAboutHosts().that(reloadResourceByForeignKey()) assertAboutHosts().that(reloadResourceByForeignKey())
.hasLastSuperordinateChange(null).and()
.hasOnlyOneHistoryEntryWhich() .hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_CREATE); .hasType(HistoryEntry.Type.HOST_CREATE);
assertNoBillingEvents(); assertNoBillingEvents();
@ -101,17 +104,18 @@ public class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Hos
@Test @Test
public void testSuccess_externalNeverExisted() throws Exception { public void testSuccess_externalNeverExisted() throws Exception {
doSuccessfulTest(); doSuccessfulTest();
assertAboutHosts().that(reloadResourceByForeignKey()).hasSuperordinateDomain(null);
assertNoDnsTasksEnqueued(); assertNoDnsTasksEnqueued();
} }
@Test @Test
public void testSuccess_internalNeverExisted() throws Exception { public void testSuccess_internalNeverExisted() throws Exception {
doSuccessfulInternalTest("tld"); doSuccessfulInternalTest("tld");
assertThat(ofy().load().key(reloadResourceByForeignKey().getSuperordinateDomain()) HostResource host = reloadResourceByForeignKey();
.now().getFullyQualifiedDomainName()) DomainResource superordinateDomain =
.isEqualTo("example.tld"); loadByForeignKey(DomainResource.class, "example.tld", clock.nowUtc());
assertThat(ofy().load().key(reloadResourceByForeignKey().getSuperordinateDomain()) assertAboutHosts().that(host).hasSuperordinateDomain(Key.create(superordinateDomain));
.now().getSubordinateHosts()).containsExactly("ns1.example.tld"); assertThat(superordinateDomain.getSubordinateHosts()).containsExactly("ns1.example.tld");
assertDnsTasksEnqueued("ns1.example.tld"); assertDnsTasksEnqueued("ns1.example.tld");
} }
@ -119,6 +123,7 @@ public class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Hos
public void testSuccess_externalExistedButWasDeleted() throws Exception { public void testSuccess_externalExistedButWasDeleted() throws Exception {
persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1)); persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
doSuccessfulTest(); doSuccessfulTest();
assertAboutHosts().that(reloadResourceByForeignKey()).hasSuperordinateDomain(null);
assertNoDnsTasksEnqueued(); assertNoDnsTasksEnqueued();
} }
@ -126,11 +131,11 @@ public class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Hos
public void testSuccess_internalExistedButWasDeleted() throws Exception { public void testSuccess_internalExistedButWasDeleted() throws Exception {
persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1)); persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
doSuccessfulInternalTest("tld"); doSuccessfulInternalTest("tld");
assertThat(ofy().load().key(reloadResourceByForeignKey().getSuperordinateDomain()) HostResource host = reloadResourceByForeignKey();
.now().getFullyQualifiedDomainName()) DomainResource superordinateDomain =
.isEqualTo("example.tld"); loadByForeignKey(DomainResource.class, "example.tld", clock.nowUtc());
assertThat(ofy().load().key(reloadResourceByForeignKey().getSuperordinateDomain()) assertAboutHosts().that(host).hasSuperordinateDomain(Key.create(superordinateDomain));
.now().getSubordinateHosts()).containsExactly("ns1.example.tld"); assertThat(superordinateDomain.getSubordinateHosts()).containsExactly("ns1.example.tld");
assertDnsTasksEnqueued("ns1.example.tld"); assertDnsTasksEnqueued("ns1.example.tld");
} }

View file

@ -18,6 +18,7 @@ import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.flows.async.AsyncFlowEnqueuer.QUEUE_ASYNC_HOST_RENAME; import static google.registry.flows.async.AsyncFlowEnqueuer.QUEUE_ASYNC_HOST_RENAME;
import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents; import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType; import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
@ -174,80 +175,107 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
setEppInput("host_update_name_unchanged.xml"); setEppInput("host_update_name_unchanged.xml");
createTld("tld"); createTld("tld");
DomainResource domain = persistActiveDomain("example.tld"); DomainResource domain = persistActiveDomain("example.tld");
persistActiveSubordinateHost(oldHostName(), domain); HostResource oldHost = persistActiveSubordinateHost(oldHostName(), domain);
clock.advanceOneMilli(); clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_update_response.xml")); runFlowAssertResponse(readFile("host_update_response.xml"));
// The example xml doesn't do a host rename, so reloading the host should work. // The example xml doesn't do a host rename, so reloading the host should work.
assertAboutHosts().that(reloadResourceByForeignKey()) assertAboutHosts().that(reloadResourceByForeignKey())
.hasLastSuperordinateChange(oldHost.getLastSuperordinateChange()).and()
.hasSuperordinateDomain(Key.create(domain)).and()
.hasOnlyOneHistoryEntryWhich() .hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_UPDATE); .hasType(HistoryEntry.Type.HOST_UPDATE);
assertDnsTasksEnqueued("ns1.example.tld"); assertDnsTasksEnqueued("ns1.example.tld");
} }
@Test @Test
public void testSuccess_renameWithSameSuperordinateDomain() throws Exception { public void testSuccess_internalToInternalOnSameDomain() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
"ns1.example.tld", "ns1.example.tld",
"ns2.example.tld", "ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>"); "<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
createTld("tld"); createTld("tld");
DomainResource domain = persistActiveDomain("example.tld"); DomainResource domain = persistResource(newDomainResource("example.tld")
persistActiveSubordinateHost(oldHostName(), domain); .asBuilder()
persistResource(
domain.asBuilder()
.setSubordinateHosts(ImmutableSet.of(oldHostName())) .setSubordinateHosts(ImmutableSet.of(oldHostName()))
.build()); .build());
assertThat( HostResource oldHost = persistActiveSubordinateHost(oldHostName(), domain);
loadByForeignKey( assertThat(domain.getSubordinateHosts()).containsExactly("ns1.example.tld");
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts())
.containsExactly("ns1.example.tld");
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getSuperordinateDomain()).isEqualTo(Key.create(domain)); assertAboutHosts().that(renamedHost)
assertThat( .hasSuperordinateDomain(Key.create(domain)).and()
loadByForeignKey( .hasLastSuperordinateChange(oldHost.getLastSuperordinateChange());
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts()) DomainResource reloadedDomain =
.containsExactly("ns2.example.tld"); ofy().load().entity(domain).now().cloneProjectedAtTime(clock.nowUtc());
assertThat(reloadedDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld"); assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld");
} }
@Test @Test
public void testSuccess_internalToSameInternal() throws Exception { public void testSuccess_internalToInternalOnSameTld() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
"ns2.foo.tld", "ns2.foo.tld",
"ns2.example.tld", "ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>"); "<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
createTld("tld"); createTld("tld");
DomainResource foo = persistActiveDomain("foo.tld");
DomainResource example = persistActiveDomain("example.tld"); DomainResource example = persistActiveDomain("example.tld");
persistActiveSubordinateHost(oldHostName(), foo); DomainResource foo = persistResource(newDomainResource("foo.tld").asBuilder()
persistResource(
foo.asBuilder()
.setSubordinateHosts(ImmutableSet.of(oldHostName())) .setSubordinateHosts(ImmutableSet.of(oldHostName()))
.build()); .build());
assertThat( persistActiveSubordinateHost(oldHostName(), foo);
loadByForeignKey( assertThat(foo.getSubordinateHosts()).containsExactly("ns2.foo.tld");
DomainResource.class, "foo.tld", clock.nowUtc()).getSubordinateHosts()) assertThat(example.getSubordinateHosts()).isEmpty();
.containsExactly("ns2.foo.tld");
assertThat(
loadByForeignKey(
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts())
.isEmpty();
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getSuperordinateDomain()).isEqualTo(Key.create(example)); DateTime now = clock.nowUtc();
assertThat( assertAboutHosts().that(renamedHost)
loadByForeignKey( .hasSuperordinateDomain(Key.create(example)).and()
DomainResource.class, "foo.tld", clock.nowUtc()).getSubordinateHosts()) .hasLastSuperordinateChange(now);
assertThat(ofy().load().entity(foo).now().cloneProjectedAtTime(now).getSubordinateHosts())
.isEmpty(); .isEmpty();
assertThat( assertThat(ofy().load().entity(example).now().cloneProjectedAtTime(now).getSubordinateHosts())
loadByForeignKey(
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts())
.containsExactly("ns2.example.tld"); .containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns2.foo.tld", "ns2.example.tld"); assertDnsTasksEnqueued("ns2.foo.tld", "ns2.example.tld");
} }
@Test
public void testSuccess_internalToInternalOnDifferentTld() throws Exception {
setEppHostUpdateInput(
"ns1.example.foo",
"ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
createTld("foo");
createTld("tld");
DomainResource fooDomain = persistResource(newDomainResource("example.foo").asBuilder()
.setSubordinateHosts(ImmutableSet.of(oldHostName()))
.build());
DomainResource tldDomain = persistActiveDomain("example.tld");
HostResource oldHost = persistActiveSubordinateHost(oldHostName(), fooDomain);
assertThat(oldHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
assertThat(fooDomain.getSubordinateHosts()).containsExactly("ns1.example.foo");
assertThat(tldDomain.getSubordinateHosts()).isEmpty();
HostResource renamedHost = doSuccessfulTest();
DateTime now = clock.nowUtc();
assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(Key.create(tldDomain)).and()
.hasLastSuperordinateChange(now);
DomainResource reloadedFooDomain =
ofy().load().entity(fooDomain).now().cloneProjectedAtTime(now);
assertThat(reloadedFooDomain.getSubordinateHosts()).isEmpty();
DomainResource reloadedTldDomain =
ofy().load().entity(tldDomain).now().cloneProjectedAtTime(now);
assertThat(reloadedTldDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns1.example.foo", "ns2.example.tld");
// Ensure that the client id is read off the domain because this is a subordinate host now.
persistResource(
tldDomain.asBuilder().setCurrentSponsorClientId("it_should_be_this").build());
assertThat(
renamedHost.cloneProjectedAtTime(clock.nowUtc().plusMinutes(1)).getCurrentSponsorClientId())
.isEqualTo("it_should_be_this");
}
@Test @Test
public void testSuccess_internalToExternal() throws Exception { public void testSuccess_internalToExternal() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
@ -256,62 +284,28 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
null, null,
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>"); "<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
createTld("foo"); createTld("foo");
DomainResource domain = persistActiveDomain("example.foo"); DomainResource domain = persistResource(newDomainResource("example.foo").asBuilder()
persistActiveSubordinateHost(oldHostName(), domain);
persistResource(
domain.asBuilder()
.setSubordinateHosts(ImmutableSet.of(oldHostName())) .setSubordinateHosts(ImmutableSet.of(oldHostName()))
.build()); .build());
assertThat( assertThat(domain.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
loadByForeignKey( HostResource oldHost = persistResource(
DomainResource.class, "example.foo", clock.nowUtc()).getSubordinateHosts()) persistActiveSubordinateHost(oldHostName(), domain).asBuilder()
.containsExactly("ns1.example.foo"); .setCurrentSponsorClientId("ClientThatShouldBeSupersededByDomainClient")
.build());
assertThat(oldHost.isSubordinate()).isTrue();
assertThat(domain.getSubordinateHosts()).containsExactly("ns1.example.foo");
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.isSubordinate()).isFalse(); assertAboutHosts().that(renamedHost)
// Ensure that the client id is set to the new registrar correctly (and that this necessarily // Ensure that the client id is copied off of the superordinate domain.
// comes from the field on the host itself, because the superordinate domain is null). .hasCurrentSponsorClientId("TheRegistrar").and()
assertThat(renamedHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar"); .hasSuperordinateDomain(null).and()
assertThat( .hasLastSuperordinateChange(clock.nowUtc());
loadByForeignKey( DomainResource reloadedDomain =
DomainResource.class, "example.foo", clock.nowUtc()).getSubordinateHosts()) ofy().load().entity(domain).now().cloneProjectedAtTime(clock.nowUtc());
.isEmpty(); assertThat(reloadedDomain.getSubordinateHosts()).isEmpty();
assertDnsTasksEnqueued("ns1.example.foo"); assertDnsTasksEnqueued("ns1.example.foo");
} }
@Test
public void testSuccess_internalToDifferentInternal() throws Exception {
setEppHostUpdateInput(
"ns1.example.foo",
"ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
createTld("foo");
persistActiveDomain("example.foo");
createTld("tld");
DomainResource tldDomain = persistActiveDomain("example.tld");
persistActiveHost(oldHostName());
assertThat(loadByForeignKey(
HostResource.class, oldHostName(), clock.nowUtc()).getCurrentSponsorClientId())
.isEqualTo("TheRegistrar");
assertThat(
loadByForeignKey(
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts())
.isEmpty();
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getSuperordinateDomain()).isEqualTo(Key.create(tldDomain));
assertThat(loadByForeignKey(
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts())
.containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns2.example.tld");
// Ensure that the client id is read off the domain because this is a subordinate host now.
persistResource(
tldDomain.asBuilder().setCurrentSponsorClientId("it_should_be_this").build());
assertThat(
renamedHost.cloneProjectedAtTime(clock.nowUtc().plusMinutes(1)).getCurrentSponsorClientId())
.isEqualTo("it_should_be_this");
}
@Test @Test
public void testSuccess_externalToInternal() throws Exception { public void testSuccess_externalToInternal() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
@ -321,28 +315,41 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
null); null);
createTld("tld"); createTld("tld");
DomainResource domain = persistActiveDomain("example.tld"); DomainResource domain = persistActiveDomain("example.tld");
persistActiveHost(oldHostName()); HostResource oldHost = persistActiveHost(oldHostName());
assertThat(oldHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
assertThat(loadByForeignKey( assertThat(domain.getSubordinateHosts()).isEmpty();
HostResource.class, oldHostName(), clock.nowUtc()).getCurrentSponsorClientId())
.isEqualTo("TheRegistrar");
assertThat(loadByForeignKey(
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts())
.isEmpty();
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getSuperordinateDomain()).isEqualTo(Key.create(domain)); DateTime now = clock.nowUtc();
assertThat(loadByForeignKey( assertAboutHosts().that(renamedHost)
DomainResource.class, "example.tld", clock.nowUtc()).getSubordinateHosts()) .hasSuperordinateDomain(Key.create(domain)).and()
.hasLastSuperordinateChange(now);
assertThat(ofy().load().entity(domain).now().cloneProjectedAtTime(now).getSubordinateHosts())
.containsExactly("ns2.example.tld"); .containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns2.example.tld"); assertDnsTasksEnqueued("ns2.example.tld");
// Ensure that the client id is read off the domain because this is a subordinate host now. // Ensure that the client id is read off the domain because this is a subordinate host now.
persistResource( persistResource(
domain.asBuilder().setCurrentSponsorClientId("it_should_be_this").build()); domain.asBuilder().setCurrentSponsorClientId("it_should_be_this").build());
assertThat( assertThat(
renamedHost.cloneProjectedAtTime(clock.nowUtc().plusMinutes(1)).getCurrentSponsorClientId()) renamedHost.cloneProjectedAtTime(now.plusMinutes(1)).getCurrentSponsorClientId())
.isEqualTo("it_should_be_this"); .isEqualTo("it_should_be_this");
} }
@Test
public void testSuccess_externalToExternal() throws Exception {
setEppHostUpdateInput(
"ns1.example.foo",
"ns2.example.tld",
null,
null);
HostResource oldHost = persistActiveHost(oldHostName());
assertThat(oldHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
HostResource renamedHost = doSuccessfulTest();
assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(null).and()
.hasLastSuperordinateChange(null);
assertNoDnsTasksEnqueued();
}
@Test @Test
public void testSuccess_superuserClientUpdateProhibited() throws Exception { public void testSuccess_superuserClientUpdateProhibited() throws Exception {
setEppInput("host_update_add_status.xml"); setEppInput("host_update_add_status.xml");
@ -550,7 +557,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
// update, not what it is later changed to. // update, not what it is later changed to.
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime); assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
// External hosts should always have null lastSuperordinateChange. // External hosts should always have null lastSuperordinateChange.
assertThat(renamedHost.getLastSuperordinateChange()).isNull(); assertThat(renamedHost.getLastSuperordinateChange()).isEqualTo(clock.nowUtc());
} }
@Test @Test

View file

@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertAbout;
import com.google.common.truth.AbstractVerb.DelegatedVerb; import com.google.common.truth.AbstractVerb.DelegatedVerb;
import com.google.common.truth.FailureStrategy; import com.google.common.truth.FailureStrategy;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DomainResource;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.testing.TruthChainer.And; import google.registry.testing.TruthChainer.And;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -52,4 +54,18 @@ public final class HostResourceSubject
actual().getLastTransferTime(), actual().getLastTransferTime(),
"lastTransferTime"); "lastTransferTime");
} }
public And<HostResourceSubject> hasLastSuperordinateChange(DateTime lastSuperordinateChange) {
return hasValue(
lastSuperordinateChange,
actual().getLastSuperordinateChange(),
"has lastSuperordinateChange");
}
public And<HostResourceSubject> hasSuperordinateDomain(Key<DomainResource> superordinateDomain) {
return hasValue(
superordinateDomain,
actual().getSuperordinateDomain(),
"has superordinateDomain");
}
} }