Allow the nomulus renew_domain command to specify the client ID (#567)

* Allow the `nomulus renew_domain` command to specify the client ID

This means that a superuser can renew a domain and have the associated history
entry, one time billing event, and renewal grace period be recorded against a
specified registrar rather than the owning registrar of the domain.  This is
useful to e.g. renew a domain for free by "charging" the renewal to the
registry's fake registrar.  Since the grace period is written to the specified
cliend id as well, if the actual registrar deletes the domain, they don't get
back the money that they didn't pay in the first place.
This commit is contained in:
Ben McIlwain 2020-04-24 18:06:27 -04:00 committed by GitHub
parent 210de9340e
commit cd13f6c5d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 27 deletions

View file

@ -153,6 +153,8 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
doSuccessfulTest(
responseFilename,
renewalYears,
"TheRegistrar",
UserPrivileges.NORMAL,
substitutions,
Money.of(USD, 11).multipliedBy(renewalYears));
}
@ -160,13 +162,16 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
private void doSuccessfulTest(
String responseFilename,
int renewalYears,
String renewalClientId,
UserPrivileges userPrivileges,
Map<String, String> substitutions,
Money totalRenewCost)
throws Exception {
assertTransactionalFlow(true);
DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime();
DateTime newExpiration = currentExpiration.plusYears(renewalYears);
runFlowAssertResponse(loadFile(responseFilename, substitutions));
runFlowAssertResponse(
CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions));
DomainBase domain = reloadResourceByForeignKey();
HistoryEntry historyEntryDomainRenew =
getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_RENEW);
@ -183,13 +188,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
.and()
.hasLastEppUpdateTime(clock.nowUtc())
.and()
.hasLastEppUpdateClientId("TheRegistrar");
.hasLastEppUpdateClientId(renewalClientId);
assertAboutHistoryEntries().that(historyEntryDomainRenew).hasPeriodYears(renewalYears);
BillingEvent.OneTime renewBillingEvent =
new BillingEvent.OneTime.Builder()
.setReason(Reason.RENEW)
.setTargetId(getUniqueIdFromCommand())
.setClientId("TheRegistrar")
.setClientId(renewalClientId)
.setCost(totalRenewCost)
.setPeriodYears(renewalYears)
.setEventTime(clock.nowUtc())
@ -233,7 +238,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
GracePeriod.create(
GracePeriodStatus.RENEW,
clock.nowUtc().plus(Registry.get("tld").getRenewGracePeriodLength()),
"TheRegistrar",
renewalClientId,
null),
renewBillingEvent));
}
@ -256,6 +261,19 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2005-04-03T22:00:00.0Z"));
}
@Test
public void testSuccess_recurringClientIdIsSame_whenSuperuserOverridesRenewal() throws Exception {
persistDomain();
setClientIdForFlow("NewRegistrar");
doSuccessfulTest(
"domain_renew_response.xml",
5,
"NewRegistrar",
UserPrivileges.SUPERUSER,
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2005-04-03T22:00:00.0Z"),
Money.of(USD, 55));
}
@Test
public void testSuccess_customLogicFee() throws Exception {
// The "costly-renew" domain has an additional RENEW fee of 100 from custom logic on top of the
@ -269,7 +287,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
"FEE", "111.00");
setEppInput("domain_renew_fee.xml", customFeeMap);
persistDomain();
doSuccessfulTest("domain_renew_response_fee.xml", 1, customFeeMap, Money.of(USD, 111));
doSuccessfulTest(
"domain_renew_response_fee.xml",
1,
"TheRegistrar",
UserPrivileges.NORMAL,
customFeeMap,
Money.of(USD, 111));
}
@Test
@ -687,7 +711,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
@Test
public void testFailure_unauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
setClientIdForFlow("NewRegistrar");
persistActiveDomain(getUniqueIdFromCommand());
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
@ -695,7 +719,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
@Test
public void testSuccess_superuserUnauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
setClientIdForFlow("NewRegistrar");
persistDomain();
runFlowAssertResponse(
CommitMode.LIVE,

View file

@ -15,21 +15,27 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatastoreHelper.newDomainBase;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
import static google.registry.testing.DatastoreHelper.persistNewRegistrar;
import static google.registry.testing.DatastoreHelper.persistResource;
import static org.junit.Assert.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableMap;
import google.registry.model.domain.DomainBase;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectRule;
import google.registry.util.Clock;
import java.util.List;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
/** Unit tests for {@link RenewDomainCommand}. */
public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCommand> {
@ -63,23 +69,57 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCo
.verifyNoMoreSent();
}
private static List<DomainBase> persistThreeDomains() {
ImmutableList.Builder<DomainBase> domains = new ImmutableList.Builder<>();
domains.add(
persistActiveDomain(
"domain1.tld",
DateTime.parse("2014-09-05T05:05:05Z"),
DateTime.parse("2015-09-05T05:05:05Z")));
domains.add(
persistActiveDomain(
"domain2.tld",
DateTime.parse("2014-11-05T05:05:05Z"),
DateTime.parse("2015-11-05T05:05:05Z")));
// The third domain is owned by a different registrar.
domains.add(
persistResource(
newDomainBase("domain3.tld")
.asBuilder()
.setCreationTimeForTest(DateTime.parse("2015-01-05T05:05:05Z"))
.setRegistrationExpirationTime(DateTime.parse("2016-01-05T05:05:05Z"))
.setPersistedCurrentSponsorClientId("NewRegistrar")
.build()));
return domains.build();
}
@Test
public void testSuccess_multipleDomains() throws Exception {
persistActiveDomain(
"domain1.tld",
DateTime.parse("2014-09-05T05:05:05Z"),
DateTime.parse("2015-09-05T05:05:05Z"));
persistActiveDomain(
"domain2.tld",
DateTime.parse("2014-11-05T05:05:05Z"),
DateTime.parse("2015-11-05T05:05:05Z"));
persistActiveDomain(
"domain3.tld",
DateTime.parse("2015-01-05T05:05:05Z"),
DateTime.parse("2016-01-05T05:05:05Z"));
public void testSuccess_multipleDomains_renewsAndUsesEachDomainsRegistrar() throws Exception {
persistThreeDomains();
runCommandForced("--period 3", "domain1.tld", "domain2.tld", "domain3.tld");
eppVerifier
.expectClientId("TheRegistrar")
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain1.tld", "EXPDATE", "2015-09-05", "YEARS", "3"))
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain2.tld", "EXPDATE", "2015-11-05", "YEARS", "3"))
.expectClientId("NewRegistrar")
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain3.tld", "EXPDATE", "2016-01-05", "YEARS", "3"))
.verifyNoMoreSent();
}
@Test
public void testSuccess_multipleDomains_renewsAndUsesSpecifiedRegistrar() throws Exception {
persistThreeDomains();
persistNewRegistrar("reg3", "Registrar 3", Registrar.Type.REAL, 9783L);
runCommandForced("--period 3", "domain1.tld", "domain2.tld", "domain3.tld", "-u", "-c reg3");
eppVerifier
.expectClientId("reg3")
.expectSuperuser()
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain1.tld", "EXPDATE", "2015-09-05", "YEARS", "3"))
@ -106,9 +146,7 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCo
persistDeletedDomain("deleted.tld", DateTime.parse("2012-10-05T05:05:05Z"));
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("deleted.tld"));
assertThat(e)
.hasMessageThat()
.isEqualTo("Domain 'deleted.tld' does not exist or is deleted");
assertThat(e).hasMessageThat().isEqualTo("Domain 'deleted.tld' does not exist or is deleted");
}
@Test
@ -128,9 +166,7 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCo
IllegalArgumentException e =
assertThrows(
IllegalArgumentException.class, () -> runCommandForced("domain.tld", "--period 10"));
assertThat(e)
.hasMessageThat()
.isEqualTo("Cannot renew domains for 10 or more years");
assertThat(e).hasMessageThat().isEqualTo("Cannot renew domains for 10 or more years");
}
@Test