google-nomulus/javatests/google/registry/flows/EppLifecycleDomainTest.java
mcilwain e289df8a03 Consolidate more wildcarded lifecycle domain testdata XMLs
Specifically domain_info.xml, domain_delete.xml, and domain_create_response.xml.

As of this CL, all domain-related commands are standardized on the parameter
"DOMAIN" for the domain name. No more ambiguous "NAME", which could be confused
with a host name.

This finishes the domain_create_response consolidation work from []

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=204981136
2018-07-17 22:09:31 -04:00

1170 lines
49 KiB
Java

// Copyright 2017 The Nomulus 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.Truth8.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.createTlds;
import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.DatastoreHelper.stripBillingEventId;
import static google.registry.testing.EppMetricSubject.assertThat;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.re2j.Matcher;
import com.google.re2j.Pattern;
import com.googlecode.objectify.Key;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainResource;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.testing.AppEngineRule;
import java.util.Objects;
import java.util.Optional;
import org.joda.money.Money;
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;
/** Tests for domain lifecycle. */
@RunWith(JUnit4.class)
public class EppLifecycleDomainTest extends EppTestCase {
@Rule
public final AppEngineRule appEngine =
AppEngineRule.builder().withDatastore().withTaskQueue().build();
@Before
public void initTld() {
createTlds("example", "tld");
}
/** Create the two administrative contacts and two hosts. */
void createContactsAndHosts() throws Exception {
DateTime createTime = DateTime.parse("2000-06-01T00:00:00Z");
createContacts(createTime);
assertThatCommand("host_create.xml", ImmutableMap.of("HOSTNAME", "ns1.example.external"))
.atTime(createTime.plusMinutes(2))
.hasResponse(
"host_create_response.xml",
ImmutableMap.of(
"HOSTNAME", "ns1.example.external",
"CRDATE", createTime.plusMinutes(2).toString()));
assertThatCommand("host_create.xml", ImmutableMap.of("HOSTNAME", "ns2.example.external"))
.atTime(createTime.plusMinutes(3))
.hasResponse(
"host_create_response.xml",
ImmutableMap.of(
"HOSTNAME", "ns2.example.external",
"CRDATE", createTime.plusMinutes(3).toString()));
}
private void createContacts(DateTime createTime) throws Exception {
assertThatCommand("contact_create_sh8013.xml")
.atTime(createTime)
.hasResponse(
"contact_create_response_sh8013.xml", ImmutableMap.of("CRDATE", createTime.toString()));
assertThatCommand("contact_create_jd1234.xml")
.atTime(createTime.plusMinutes(1))
.hasResponse(
"contact_create_response_jd1234.xml",
ImmutableMap.of("CRDATE", createTime.plusMinutes(1).toString()));
}
/** Creates the domain fakesite.example with two nameservers on it. */
void createFakesite() throws Exception {
createContactsAndHosts();
assertThatCommand("domain_create_fakesite.xml")
.atTime("2000-06-01T00:04:00Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "fakesite.example",
"CRDATE", "2000-06-01T00:04:00.0Z",
"EXDATE", "2002-06-01T00:04:00.0Z"));
assertThatCommand("domain_info_fakesite.xml")
.atTime("2000-06-06T00:00:00Z")
.hasResponse("domain_info_response_fakesite_ok.xml");
}
/** Creates ns3.fakesite.example as a host, then adds it to fakesite. */
void createSubordinateHost() throws Exception {
// Add the fakesite nameserver (requires that domain is already created).
assertThatCommand("host_create_fakesite.xml")
.atTime("2000-06-06T00:01:00Z")
.hasResponse("host_create_response_fakesite.xml");
// Add new nameserver to domain.
assertThatCommand("domain_update_add_nameserver_fakesite.xml")
.atTime("2000-06-08T00:00:00Z")
.hasResponse("generic_success_response.xml");
// Verify new nameserver was added.
assertThatCommand("domain_info_fakesite.xml")
.atTime("2000-06-08T00:01:00Z")
.hasResponse("domain_info_response_fakesite_3_nameservers.xml");
// Verify that nameserver's data was set correctly.
assertThatCommand("host_info_fakesite.xml")
.atTime("2000-06-08T00:02:00Z")
.hasResponse("host_info_response_fakesite_linked.xml");
}
@Test
public void testDomainDeleteRestore() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createContacts(DateTime.parse("2000-06-01T00:00:00Z"));
// Create domain example.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-06-01T00:02:00Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld",
"CRDATE", "2000-06-01T00:02:00.0Z",
"EXDATE", "2002-06-01T00:02:00.0Z"));
// Delete domain example.tld after its add grace period has expired.
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-07-01T00:02:00Z")
.hasResponse("generic_success_action_pending_response.xml");
// Restore the domain.
assertThatCommand("domain_update_restore_request.xml")
.atTime("2000-07-01T00:03:00Z")
.hasResponse("generic_success_response.xml");
assertThatLogoutSucceeds();
}
@Test
public void testDomainDeletion_withinAddGracePeriod_deletesImmediately() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createContacts(DateTime.parse("2000-06-01T00:00:00Z"));
// Create domain example.tld
DateTime createTime = DateTime.parse("2000-06-01T00:02:00Z");
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime(createTime)
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld",
"CRDATE", "2000-06-01T00:02:00.0Z",
"EXDATE", "2002-06-01T00:02:00.0Z"));
DomainResource domain =
loadByForeignKey(DomainResource.class, "example.tld", createTime.plusHours(1));
// Delete domain example.tld within the add grace period.
DateTime deleteTime = createTime.plusDays(1);
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime(deleteTime)
.hasResponse("generic_success_response.xml");
// Verify that it is immediately non-existent.
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime(deleteTime.plusSeconds(1))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2303", "MSG", "The domain with given ID (example.tld) doesn't exist."));
// The expected one-time billing event, that should have an associated Cancellation.
OneTime oneTimeCreateBillingEvent = makeOneTimeCreateBillingEvent(domain, createTime);
// Verify that the OneTime billing event associated with the domain creation is canceled.
assertBillingEventsForResource(
domain,
// Check the existence of the expected create one-time billing event.
oneTimeCreateBillingEvent,
makeRecurringCreateBillingEvent(domain, createTime, deleteTime),
// Check for the existence of a cancellation for the given one-time billing event.
makeCancellationBillingEventFor(
domain, oneTimeCreateBillingEvent, createTime, deleteTime));
assertThatLogoutSucceeds();
}
@Test
public void testDomainDeletion_outsideAddGracePeriod_showsRedemptionPeriod() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createContacts(DateTime.parse("2000-06-01T00:00:00Z"));
DateTime createTime = DateTime.parse("2000-06-01T00:02:00Z");
// Create domain example.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime(createTime)
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld",
"CRDATE", "2000-06-01T00:02:00.0Z",
"EXDATE", "2002-06-01T00:02:00.0Z"));
DateTime deleteTime = DateTime.parse("2000-07-07T00:02:00Z"); // 1 month and 6 days after
// Delete domain example.tld after its add grace period has expired.
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime(deleteTime)
.hasResponse("generic_success_action_pending_response.xml");
// Verify that domain shows redemptionPeriod soon after deletion.
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-07-08T00:00:00Z")
.hasResponse(
"domain_info_response_wildcard.xml", ImmutableMap.of("STATUS", "redemptionPeriod"));
// Verify that the domain shows pendingDelete next.
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-08-08T00:00:00Z")
.hasResponse(
"domain_info_response_wildcard.xml", ImmutableMap.of("STATUS", "pendingDelete"));
// Verify that the domain is non-existent (available for registration) later.
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-09-01T00:00:00Z")
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2303", "MSG", "The domain with given ID (example.tld) doesn't exist."));
DomainResource domain =
loadByForeignKey(
DomainResource.class, "example.tld", DateTime.parse("2000-08-01T00:02:00Z"));
// Verify that the autorenew was ended and that the one-time billing event is not canceled.
assertBillingEventsForResource(
domain,
makeOneTimeCreateBillingEvent(domain, createTime),
makeRecurringCreateBillingEvent(domain, createTime, deleteTime));
assertThatLogoutSucceeds();
}
@Test
public void testEapDomainDeletion_withinAddGracePeriod_eapFeeIsNotRefunded() throws Exception {
assertThatCommand("login_valid_fee_extension.xml").hasResponse("generic_success_response.xml");
createContacts(DateTime.parse("2000-06-01T00:00:00Z"));
// Set the EAP schedule.
persistResource(
Registry.get("tld")
.asBuilder()
.setEapFeeSchedule(
ImmutableSortedMap.of(
START_OF_TIME, Money.of(USD, 0),
DateTime.parse("2000-06-01T00:00:00Z"), Money.of(USD, 100),
DateTime.parse("2000-06-02T00:00:00Z"), Money.of(USD, 0)))
.build());
// Create domain example.tld, which should have an EAP fee of USD 100.
DateTime createTime = DateTime.parse("2000-06-01T00:02:00Z");
assertThatCommand("domain_create_eap_fee.xml")
.atTime(createTime)
.hasResponse("domain_create_response_eap_fee.xml");
DomainResource domain =
loadByForeignKey(
DomainResource.class, "example.tld", DateTime.parse("2000-06-01T00:03:00Z"));
// Delete domain example.tld within the add grade period.
DateTime deleteTime = createTime.plusDays(1);
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime(deleteTime)
.hasResponse("domain_delete_response_fee.xml");
// Verify that the OneTime billing event associated with the base fee of domain registration and
// is canceled and the autorenew is ended, but that the EAP fee is not canceled.
OneTime expectedCreateEapBillingEvent =
new BillingEvent.OneTime.Builder()
.setReason(Reason.FEE_EARLY_ACCESS)
.setTargetId("example.tld")
.setClientId("NewRegistrar")
.setPeriodYears(1)
.setCost(Money.parse("USD 100.00"))
.setEventTime(createTime)
.setBillingTime(createTime.plus(Registry.get("tld").getRenewGracePeriodLength()))
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_CREATE))
.build();
// The expected one-time billing event, that should have an associated Cancellation.
OneTime expectedOneTimeCreateBillingEvent = makeOneTimeCreateBillingEvent(domain, createTime);
assertBillingEventsForResource(
domain,
// Check for the expected create one-time billing event ...
expectedOneTimeCreateBillingEvent,
// ... and the expected one-time EAP fee billing event ...
expectedCreateEapBillingEvent,
makeRecurringCreateBillingEvent(domain, createTime, deleteTime),
// ... and verify that the create one-time billing event was canceled ...
makeCancellationBillingEventFor(
domain, expectedOneTimeCreateBillingEvent, createTime, deleteTime));
// ... but there was NOT a Cancellation for the EAP fee, as this would fail if additional
// billing events were present.
assertThatLogoutSucceeds();
}
/** Makes a one-time billing event corresponding to the given domain's creation. */
private static BillingEvent.OneTime makeOneTimeCreateBillingEvent(
DomainResource domain, DateTime createTime) {
return new BillingEvent.OneTime.Builder()
.setReason(Reason.CREATE)
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setCost(Money.parse("USD 26.00"))
.setPeriodYears(2)
.setEventTime(createTime)
.setBillingTime(createTime.plus(Registry.get(domain.getTld()).getRenewGracePeriodLength()))
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_CREATE))
.build();
}
/** Makes a recurring billing event corresponding to the given domain's creation. */
private static BillingEvent.Recurring makeRecurringCreateBillingEvent(
DomainResource domain, DateTime createTime, DateTime endTime) {
return new BillingEvent.Recurring.Builder()
.setReason(Reason.RENEW)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setEventTime(createTime.plusYears(2))
.setRecurrenceEndTime(endTime)
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_CREATE))
.build();
}
/** Makes a cancellation billing event cancelling out the given domain create billing event. */
private static BillingEvent.Cancellation makeCancellationBillingEventFor(
DomainResource domain,
OneTime billingEventToCancel,
DateTime createTime,
DateTime deleteTime) {
return new BillingEvent.Cancellation.Builder()
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setEventTime(deleteTime)
.setOneTimeEventKey(findKeyToActualOneTimeBillingEvent(billingEventToCancel))
.setBillingTime(createTime.plus(Registry.get(domain.getTld()).getRenewGracePeriodLength()))
.setReason(Reason.CREATE)
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_DELETE))
.build();
}
/**
* Finds the Key to the actual one-time create billing event associated with a domain's creation.
*
* <p>This is used in the situation where we have created an expected billing event associated
* with the domain's creation (which is passed as the parameter here), then need to locate the key
* to the actual billing event in Datastore that would be seen on a Cancellation billing event.
* This is necessary because the ID will be different even though all the rest of the fields are
* the same.
*/
private static Key<OneTime> findKeyToActualOneTimeBillingEvent(OneTime expectedBillingEvent) {
Optional<OneTime> actualCreateBillingEvent =
ofy()
.load()
.type(BillingEvent.OneTime.class)
.list()
.stream()
.filter(
b ->
Objects.equals(
stripBillingEventId(b), stripBillingEventId(expectedBillingEvent)))
.findFirst();
assertThat(actualCreateBillingEvent).isPresent();
return Key.create(actualCreateBillingEvent.get());
}
@Test
public void testDomainDeletionWithSubordinateHost_fails() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
createSubordinateHost();
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-05-30T01:01:00Z")
.hasResponse(
"response_error.xml",
ImmutableMap.of("CODE", "2305", "MSG", "Domain to be deleted has subordinate hosts"));
assertThatLogoutSucceeds();
}
@Test
public void testDeletionOfDomain_afterRenameOfSubordinateHost_succeeds() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar")
.and()
.hasNoTld()
.and()
.hasCommandName("Login")
.and()
.hasStatus(SUCCESS);
createFakesite();
createSubordinateHost();
// Update the ns3 host to no longer be on fakesite.example domain.
assertThatCommand("host_update_fakesite.xml")
.atTime("2002-05-30T01:01:00Z")
.hasResponse("generic_success_response.xml");
// Add assert about EppMetric
assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar")
.and()
.hasCommandName("HostUpdate")
.and()
.hasEppTarget("ns3.fakesite.example")
.and()
.hasStatus(SUCCESS);
// Delete the fakesite.example domain (which should succeed since it no longer has subords).
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-05-30T01:02:00Z")
.hasResponse("generic_success_action_pending_response.xml");
assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar")
.and()
.hasTld("example")
.and()
.hasCommandName("DomainDelete")
.and()
.hasEppTarget("fakesite.example")
.and()
.hasStatus(SUCCESS_WITH_ACTION_PENDING);
// Check info on the renamed host and verify that it's still around and wasn't deleted.
assertThatCommand("host_info_ns9000_example.xml")
.atTime("2002-06-30T01:03:00Z")
.hasResponse("host_info_response_ns9000_example.xml");
assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar")
.and()
.hasCommandName("HostInfo")
.and()
.hasEppTarget("ns9000.example.external")
.and()
.hasStatus(SUCCESS);
assertThatLogoutSucceeds();
assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar")
.and()
.hasCommandName("Logout")
.and()
.hasStatus(SUCCESS_AND_CLOSE);
}
@Test
public void testDeletionOfDomain_afterUpdateThatCreatesSubordinateHost_fails() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
// Create domain example.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-06-02T00:00:00Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld",
"CRDATE", "2000-06-02T00:00:00.0Z",
"EXDATE", "2002-06-02T00:00:00.0Z"));
// Create nameserver ns1.example.tld
assertThatCommand("host_create_example.xml")
.atTime("2000-06-02T00:01:00Z")
.hasResponse("host_create_response_example.xml");
// Update the ns1 host to be on the fakesite.example domain.
assertThatCommand("host_update_ns1_to_fakesite.xml")
.atTime("2002-05-30T01:01:00Z")
.hasResponse("generic_success_response.xml");
// Attempt to delete the fakesite.example domain (which should fail since it now has a
// subordinate host).
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-05-30T01:02:00Z")
.hasResponse(
"response_error.xml",
ImmutableMap.of("CODE", "2305", "MSG", "Domain to be deleted has subordinate hosts"));
// Check info on the renamed host and verify that it's still around and wasn't deleted.
assertThatCommand("host_info_fakesite.xml")
.atTime("2002-06-30T01:03:00Z")
.hasResponse("host_info_response_fakesite_post_update.xml");
// Verify that fakesite.example domain is still around and wasn't deleted.
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-05-30T01:00:00Z")
.hasResponse("domain_info_response_fakesite_ok_post_host_update.xml");
assertThatLogoutSucceeds();
}
@Test
public void testDomainCreation_failsBeforeSunrise() throws Exception {
DateTime sunriseDate = DateTime.parse("2000-05-30T00:00:00Z");
createTld(
"example",
ImmutableSortedMap.of(
START_OF_TIME,
TldState.PREDELEGATION,
sunriseDate,
TldState.SUNRISE,
sunriseDate.plusMonths(2),
TldState.GENERAL_AVAILABILITY));
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createContactsAndHosts();
assertThatCommand("domain_create_sunrise_encoded_mark.xml")
.atTime(sunriseDate.minusDays(1))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2002", "MSG", "Command is not allowed in the current registry phase"));
assertThatCommand("domain_info_testvalidate.xml")
.atTime(sunriseDate.plusDays(1))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2303",
"MSG", "The domain with given ID (test-validate.example) doesn't exist."));
assertThatLogoutSucceeds();
}
@Test
public void testDomainCheckFee_succeeds() throws Exception {
DateTime gaDate = DateTime.parse("2000-05-30T00:00:00Z");
createTld(
"example",
ImmutableSortedMap.of(
START_OF_TIME, TldState.PREDELEGATION,
gaDate, TldState.GENERAL_AVAILABILITY));
assertThatCommand("login_valid_fee_extension.xml").hasResponse("generic_success_response.xml");
assertThatCommand("domain_check_fee_premium.xml")
.atTime(gaDate.plusDays(1))
.hasResponse("domain_check_fee_premium_response.xml");
assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar")
.and()
.hasCommandName("DomainCheck")
.and()
.hasEppTarget("rich.example")
.and()
.hasTld("example")
.and()
.hasStatus(SUCCESS);
assertThatLogoutSucceeds();
}
@Test
public void testDomainCreate_annualAutoRenewPollMessages_haveUniqueIds() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Create the domain.
createFakesite();
// The first autorenew poll message isn't seen until after the initial two years of registration
// are up.
assertThatCommand("poll.xml")
.atTime("2001-01-01T00:01:00Z")
.hasResponse("poll_response_empty.xml");
assertThatCommand("poll.xml")
.atTime("2002-07-01T00:01:00Z")
.hasResponse(
"poll_response_autorenew.xml",
ImmutableMap.of(
"ID", "1-C-EXAMPLE-13-16-2002",
"QDATE", "2002-06-01T00:04:00Z",
"DOMAIN", "fakesite.example",
"EXDATE", "2003-06-01T00:04:00Z"));
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-13-16-2002"))
.atTime("2002-07-01T00:02:00Z")
.hasResponse("poll_ack_response_empty.xml");
// The second autorenew poll message isn't seen until after another year, and it should have a
// different ID.
assertThatCommand("poll.xml")
.atTime("2002-07-01T00:05:00Z")
.hasResponse("poll_response_empty.xml");
assertThatCommand("poll.xml")
.atTime("2003-07-01T00:05:00Z")
.hasResponse(
"poll_response_autorenew.xml",
ImmutableMap.of(
"ID", "1-C-EXAMPLE-13-16-2003", // Note -- Year is different from previous ID.
"QDATE", "2003-06-01T00:04:00Z",
"DOMAIN", "fakesite.example",
"EXDATE", "2004-06-01T00:04:00Z"));
// Ack the second poll message and verify that none remain.
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-13-16-2003"))
.atTime("2003-07-01T00:05:05Z")
.hasResponse("poll_ack_response_empty.xml");
assertThatCommand("poll.xml")
.atTime("2003-07-01T00:05:10Z")
.hasResponse("poll_response_empty.xml");
assertThatLogoutSucceeds();
}
@Test
public void testDomainTransferPollMessage_serverApproved() throws Exception {
// As the losing registrar, create the domain.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
assertThatLogoutSucceeds();
// As the winning registrar, request a transfer. Capture the server trid; we'll need it later.
assertThatLoginSucceeds("TheRegistrar", "password2");
String response =
assertThatCommand("domain_transfer_request_1_year.xml")
.atTime("2001-01-01T00:00:00Z")
.hasResponse("domain_transfer_response_1_year.xml");
Matcher matcher = Pattern.compile("<svTRID>(.*)</svTRID>").matcher(response);
matcher.find();
String transferRequestTrid = matcher.group(1);
assertThatLogoutSucceeds();
// As the losing registrar, read the request poll message, and then ack it.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatCommand("poll.xml")
.atTime("2001-01-01T00:01:00Z")
.hasResponse("poll_response_domain_transfer_request.xml");
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-17-23-2001"))
.atTime("2001-01-01T00:01:00Z")
.hasResponse("poll_ack_response_empty.xml");
// Five days in the future, expect a server approval poll message to the loser, and ack it.
assertThatCommand("poll.xml")
.atTime("2001-01-06T00:01:00Z")
.hasResponse("poll_response_domain_transfer_server_approve_loser.xml");
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-17-22-2001"))
.atTime("2001-01-06T00:01:00Z")
.hasResponse("poll_ack_response_empty.xml");
assertThatLogoutSucceeds();
// Also expect a server approval poll message to the winner, with the transfer request trid.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("poll.xml")
.atTime("2001-01-06T00:02:00Z")
.hasResponse(
"poll_response_domain_transfer_server_approve_winner.xml",
ImmutableMap.of("SERVER_TRID", transferRequestTrid));
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-17-21-2001"))
.atTime("2001-01-06T00:02:00Z")
.hasResponse("poll_ack_response_empty.xml");
assertThatLogoutSucceeds();
}
@Test
public void testTransfer_autoRenewGraceActive_onlyAtAutomaticTransferTime_getsSubsumed()
throws Exception {
// Register the domain as the first registrar.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
assertThatLogoutSucceeds();
// Request a transfer of the domain to the second registrar.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml")
.atTime("2002-05-30T00:00:00Z")
.hasResponse("domain_transfer_response.xml");
assertThatLogoutSucceeds();
// Log back in as the first registrar and verify things.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-05-30T01:00:00Z")
.hasResponse("domain_info_response_fakesite_pending_transfer.xml");
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-06-02T00:00:00Z")
.hasResponse("domain_info_response_fakesite_pending_transfer_autorenew.xml");
assertThatLogoutSucceeds();
// Log back in as the second registrar and verify transfer details.
assertThatLoginSucceeds("TheRegistrar", "password2");
// Verify that domain is in the transfer period now with expiration date still one year out,
// since the transfer should subsume the autorenew that happened during the transfer window.
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-06-06T00:00:00Z")
.hasResponse("domain_info_response_fakesite_transfer_period.xml");
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-06-12T00:00:00Z")
.hasResponse("domain_info_response_fakesite_transfer_complete.xml");
assertThatLogoutSucceeds();
}
@Test
public void testNameserversTransferWithDomain_successfully() throws Exception {
// Log in as the first registrar and set up domains with hosts.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
createSubordinateHost();
assertThatLogoutSucceeds();
// Request a transfer of the domain to the second registrar.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml")
.atTime("2002-05-30T00:00:00Z")
.hasResponse("domain_transfer_response.xml");
assertThatLogoutSucceeds();
// Log back in as the first registrar and verify domain is pending transfer.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-05-30T01:00:00Z")
.hasResponse("domain_info_response_fakesite_3_nameservers_pending_transfer.xml");
assertThatLogoutSucceeds();
// Log back in as second registrar and verify transfer was successful.
assertThatLoginSucceeds("TheRegistrar", "password2");
// Expect transfer complete with all three nameservers on it.
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-06-09T00:00:00Z")
.hasResponse("domain_info_response_fakesite_3_nameservers_transfer_successful.xml");
// Verify that host's client ID was set to the new registrar and has the transfer date set.
assertThatCommand("host_info_fakesite.xml")
.atTime("2002-06-09T00:01:00Z")
.hasResponse(
"host_info_response_fakesite_post_transfer.xml",
ImmutableMap.of("TRDATE", "2002-06-04T00:00:00Z"));
assertThatLogoutSucceeds();
}
@Test
public void testRenewalFails_whenTotalTermExceeds10Years() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Creates domain with 2 year expiration.
createFakesite();
// Attempt to renew for 9 years, adding up to a total greater than the allowed max of 10 years.
assertThatCommand(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "fakesite.example", "EXPDATE", "2002-06-01", "YEARS", "9"))
.atTime("2000-06-07T00:00:00Z")
.hasResponse("domain_renew_response_exceeds_max_years.xml");
assertThatLogoutSucceeds();
}
@Test
public void testDomainDeletionCancelsPendingTransfer() throws Exception {
// Register the domain as the first registrar.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
assertThatLogoutSucceeds();
// Request a transfer of the domain to the second registrar.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml")
.atTime("2002-05-30T00:00:00Z")
.hasResponse("domain_transfer_response.xml");
assertThatLogoutSucceeds();
// Log back in as the first registrar and delete then restore the domain while the transfer
// is still pending.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-05-30T01:00:00Z")
.hasResponse("domain_info_response_fakesite_pending_transfer.xml");
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-05-30T01:01:00Z")
.hasResponse("generic_success_action_pending_response.xml");
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-05-30T01:02:00Z")
.hasResponse("domain_info_response_fakesite_pending_delete.xml");
assertThatCommand("domain_update_restore_fakesite.xml")
.atTime("2002-05-30T01:03:00Z")
.hasResponse("generic_success_response.xml");
// Expect domain is ok now, not pending delete or transfer, and has been extended by a year from
// the date of the restore. (Not from the original expiration date.)
assertThatCommand("domain_info_fakesite.xml")
.atTime("2002-05-30T01:04:00Z")
.hasResponse("domain_info_response_fakesite_restored_ok.xml");
assertThatLogoutSucceeds();
}
@Test
public void testDomainTransfer_subordinateHost_showsChangeInTransferQuery() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
createSubordinateHost();
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2000-09-02T00:00:00Z")
.hasResponse(
"response_error.xml",
ImmutableMap.of("CODE", "2002", "MSG", "Object has no transfer history"));
assertThatLogoutSucceeds();
// Request a transfer of the domain to the second registrar.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request_1_year.xml")
.atTime("2001-01-01T00:00:00Z")
.hasResponse("domain_transfer_response_1_year.xml");
assertThatLogoutSucceeds();
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Verify that reID is set correctly.
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2001-01-02T00:00:00Z")
.hasResponse("domain_transfer_query_response_fakesite.xml");
// Verify that status went from 'pending' to 'serverApproved'.
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2001-01-08T00:00:00Z")
.hasResponse("domain_transfer_query_response_completed_fakesite.xml");
assertThatLogoutSucceeds();
}
/**
* Tests that when a superordinate domain of a host is transferred, and then the host is updated
* to be subordinate to a different domain, that the host retains the transfer time of the first
* superordinate domain, not whatever the transfer time from the second domain is.
*/
@Test
public void testSuccess_lastTransferTime_superordinateDomainTransferFollowedByHostUpdate()
throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Create fakesite.example with subordinate host ns3.fakesite.example
createFakesite();
createSubordinateHost();
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2000-09-02T00:00:00Z")
.hasResponse(
"response_error.xml",
ImmutableMap.of("CODE", "2002", "MSG", "Object has no transfer history"));
assertThatLogoutSucceeds();
// Request a transfer of the domain to the second registrar.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request_1_year.xml")
.atTime("2001-01-01T00:00:00Z")
.hasResponse("domain_transfer_response_1_year.xml");
// Verify that the lastTransferTime now reflects the superordinate domain's transfer.
assertThatCommand("host_info.xml", ImmutableMap.of("HOSTNAME", "ns3.fakesite.example"))
.atTime("2001-01-07T00:00:00Z")
.hasResponse(
"host_info_response_fakesite_post_transfer.xml",
ImmutableMap.of("TRDATE", "2001-01-06T00:00:00.000Z"));
assertThatCommand("domain_create_secondsite.xml")
.atTime("2001-01-08T00:00:00Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "secondsite.example",
"CRDATE", "2001-01-08T00:00:00.0Z",
"EXDATE", "2003-01-08T00:00:00.0Z"));
// Update the host to be subordinate to a different domain by renaming it to
// ns3.secondsite.example
assertThatCommand(
"host_update_rename_only.xml",
ImmutableMap.of("oldName", "ns3.fakesite.example", "newName", "ns3.secondsite.example"))
.atTime("2002-05-30T01:01:00Z")
.hasResponse("generic_success_response.xml");
// The last transfer time on the host should still be what it was from the transfer.
assertThatCommand("host_info.xml", ImmutableMap.of("HOSTNAME", "ns3.secondsite.example"))
.atTime("2003-01-07T00:00:00Z")
.hasResponse(
"host_info_response_fakesite_post_transfer_and_update.xml",
ImmutableMap.of(
"HOSTNAME", "ns3.secondsite.example",
"TRDATE", "2001-01-06T00:00:00.000Z"));
assertThatLogoutSucceeds();
}
/**
* Tests that when a superordinate domain of a host is transferred, and then the host is updated
* to be external, that the host retains the transfer time of the first superordinate domain.
*/
@Test
public void testSuccess_lastTransferTime_superordinateDomainTransferThenHostUpdateToExternal()
throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Create fakesite.example with subordinate host ns3.fakesite.example
createFakesite();
createSubordinateHost();
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2000-09-02T00:00:00Z")
.hasResponse(
"response_error.xml",
ImmutableMap.of("CODE", "2002", "MSG", "Object has no transfer history"));
assertThatLogoutSucceeds();
// Request a transfer of the domain to the second registrar.
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request_1_year.xml")
.atTime("2001-01-01T00:00:00Z")
.hasResponse("domain_transfer_response_1_year.xml");
// Verify that the lastTransferTime now reflects the superordinate domain's transfer.
assertThatCommand("host_info_fakesite.xml")
.atTime("2001-01-07T00:00:00Z")
.hasResponse(
"host_info_response_fakesite_post_transfer.xml",
ImmutableMap.of("TRDATE", "2001-01-06T00:00:00.000Z"));
// Update the host to be external by renaming it to ns3.notarealsite.external
assertThatCommand(
"host_update_rename_and_remove_addresses.xml",
ImmutableMap.of(
"oldName", "ns3.fakesite.example",
"newName", "ns3.notarealsite.external"))
.atTime("2002-05-30T01:01:00Z")
.hasResponse("generic_success_response.xml");
// The last transfer time on the host should still be what it was from the transfer.
assertThatCommand("host_info.xml", ImmutableMap.of("HOSTNAME", "ns3.notarealsite.external"))
.atTime("2001-01-07T00:00:00Z")
.hasResponse(
"host_info_response_fakesite_post_transfer_and_update_no_addresses.xml",
ImmutableMap.of(
"HOSTNAME", "ns3.notarealsite.external",
"TRDATE", "2001-01-06T00:00:00.000Z"));
assertThatLogoutSucceeds();
}
@Test
public void testSuccess_multipartTldsWithSharedSuffixes() throws Exception {
createTlds("bar.foo.tld", "foo.tld");
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createContacts(DateTime.parse("2000-06-01T00:00:00.000Z"));
// Create domain example.bar.foo.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml",
ImmutableMap.of("DOMAIN", "example.bar.foo.tld"))
.atTime("2000-06-01T00:02:00.001Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.bar.foo.tld",
"CRDATE", "2000-06-01T00:02:00Z",
"EXDATE", "2002-06-01T00:02:00Z"));
// Create domain example.foo.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.foo.tld"))
.atTime("2000-06-01T00:02:00.002Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.foo.tld",
"CRDATE", "2000-06-01T00:02:00Z",
"EXDATE", "2002-06-01T00:02:00Z"));
// Create domain example.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-06-01T00:02:00.003Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld",
"CRDATE", "2000-06-01T00:02:00Z",
"EXDATE", "2002-06-01T00:02:00Z"));
assertThatLogoutSucceeds();
}
@Test
public void testSuccess_multipartTldsWithSharedPrefixes() throws Exception {
createTld("tld.foo");
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createContacts(DateTime.parse("2000-06-01T00:00:00.000Z"));
// Create domain example.tld.foo
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld.foo"))
.atTime("2000-06-01T00:02:00.001Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld.foo",
"CRDATE", "2000-06-01T00:02:00Z",
"EXDATE", "2002-06-01T00:02:00Z"));
// Create domain example.tld
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "example.tld"))
.atTime("2000-06-01T00:02:00.002Z")
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "example.tld",
"CRDATE", "2000-06-01T00:02:00Z",
"EXDATE", "2002-06-01T00:02:00Z"));
assertThatLogoutSucceeds();
}
/**
* Test a full launch of start-date sunrise.
*
* We show that we can't create during pre-delegation, can only create with an encoded mark during
* start-date sunrise - which we can then delete "as normal" (no need for a signed mark or
* anything for delete), and then use "regular" create during general-availability.
*/
@Test
public void testDomainCreation_startDateSunriseFull() throws Exception {
// The signed mark is valid between 2013 and 2017
DateTime sunriseDate = DateTime.parse("2014-09-08T09:09:09Z");
DateTime gaDate = sunriseDate.plusDays(30);
createTld(
"example",
ImmutableSortedMap.of(
START_OF_TIME, TldState.PREDELEGATION,
sunriseDate, TldState.START_DATE_SUNRISE,
gaDate, TldState.GENERAL_AVAILABILITY));
assertThatLogin("NewRegistrar", "foo-BAR2")
.atTime(sunriseDate.minusDays(3))
.hasResponse("generic_success_response.xml");
createContactsAndHosts();
// During pre-delegation, any create should fail both with and without mark
assertThatCommand("domain_create_start_date_sunrise_encoded_mark.xml")
.atTime(sunriseDate.minusDays(2))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2306",
"MSG",
"Declared launch extension phase does not match the current registry phase"));
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml",
ImmutableMap.of("DOMAIN", "general.example"))
.atTime(sunriseDate.minusDays(1))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2002",
"MSG", "The current registry phase does not allow for general registrations"));
// During start-date sunrise, create with mark will succeed but without will fail.
// We also test we can delete without a mark.
assertThatCommand("domain_create_start_date_sunrise_encoded_mark.xml")
.atTime(sunriseDate.plusDays(1))
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "test-validate.example",
"CRDATE", "2014-09-09T09:09:09Z",
"EXDATE", "2015-09-09T09:09:09Z"));
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "test-validate.example"))
.atTime(sunriseDate.plusDays(1).plusMinutes(1))
.hasResponse("generic_success_response.xml");
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml",
ImmutableMap.of("DOMAIN", "general.example"))
.atTime(sunriseDate.plusDays(2))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2002",
"MSG", "The current registry phase requires a signed mark for registrations"));
// During general availability, sunrise creates will fail but regular creates succeed
assertThatCommand("domain_create_start_date_sunrise_encoded_mark.xml")
.atTime(gaDate.plusDays(1))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2306",
"MSG",
"Declared launch extension phase does not match the current registry phase"));
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml",
ImmutableMap.of("DOMAIN", "general.example"))
.atTime(gaDate.plusDays(2))
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "general.example",
"CRDATE", "2014-10-10T09:09:09Z",
"EXDATE", "2016-10-10T09:09:09Z"));
assertThatLogoutSucceeds();
}
/**
* Test that missing type= argument on launch create works in start-date sunrise.
*
* <p>TODO(b/76095570):have the same exact test on end-date sunrise - using the same .xml file -
* that checks that an application was created.
*/
@Test
public void testDomainCreation_startDateSunrise_noType() throws Exception {
// The signed mark is valid between 2013 and 2017
DateTime sunriseDate = DateTime.parse("2014-09-08T09:09:09Z");
DateTime gaDate = sunriseDate.plusDays(30);
createTld(
"example",
ImmutableSortedMap.of(
START_OF_TIME, TldState.PREDELEGATION,
sunriseDate, TldState.START_DATE_SUNRISE,
gaDate, TldState.GENERAL_AVAILABILITY));
assertThatLogin("NewRegistrar", "foo-BAR2")
.atTime(sunriseDate.minusDays(3))
.hasResponse("generic_success_response.xml");
createContactsAndHosts();
// During start-date sunrise, create with mark will succeed but without will fail.
// We also test we can delete without a mark.
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "test-validate.example"))
.atTime(sunriseDate.plusDays(1))
.hasResponse(
"response_error.xml",
ImmutableMap.of(
"CODE", "2303",
"MSG", "The domain with given ID (test-validate.example) doesn't exist."));
assertThatCommand("domain_create_start_date_sunrise_encoded_mark_no_type.xml")
.atTime(sunriseDate.plusDays(1).plusMinutes(1))
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "test-validate.example",
"CRDATE", "2014-09-09T09:10:09Z",
"EXDATE", "2015-09-09T09:10:09Z"));
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "test-validate.example"))
.atTime(sunriseDate.plusDays(1).plusMinutes(2))
.hasResponse(
"domain_info_response_ok_wildcard.xml",
ImmutableMap.of(
"DOMAIN", "test-validate.example",
"CRDATE", "2014-09-09T09:10:09Z",
"EXDATE", "2015-09-09T09:10:09Z"));
assertThatLogoutSucceeds();
}
}